@xpert-ai/chatkit-ui 0.4.7 → 0.4.9

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 (337) hide show
  1. package/dist/app/assets/{_baseUniq-zhZsBqC1.js → _baseUniq-CvUv2HwQ.js} +1 -1
  2. package/dist/app/assets/{abap-C1NkPSGQ.js → abap-BO7niWiC.js} +1 -1
  3. package/dist/app/assets/{abnf-JbwQvl8G.js → abnf-CWEz7Drs.js} +1 -1
  4. package/dist/app/assets/{actionscript-DmGKVMdE.js → actionscript-CyOkZZxh.js} +1 -1
  5. package/dist/app/assets/{ada-BFUkZTyl.js → ada-Jlv844Rv.js} +1 -1
  6. package/dist/app/assets/{agda-DaMAzqVU.js → agda-C_kFG5ee.js} +1 -1
  7. package/dist/app/assets/{al-BJTYBSmw.js → al-BJB3bCYn.js} +1 -1
  8. package/dist/app/assets/{antlr4-Dp3xUyR5.js → antlr4-CxC5pLeu.js} +1 -1
  9. package/dist/app/assets/{apacheconf-CNs6LiCv.js → apacheconf-Do-yEyZc.js} +1 -1
  10. package/dist/app/assets/{apex-Cb-6Ow2z.js → apex-_x2gfDUc.js} +1 -1
  11. package/dist/app/assets/{apl-Caij2pyM.js → apl-CV7O96Vz.js} +1 -1
  12. package/dist/app/assets/{applescript-Za6DtdYI.js → applescript-BBZjdzgl.js} +1 -1
  13. package/dist/app/assets/{aql-rq-zV86w.js → aql-CPRi8JU5.js} +1 -1
  14. package/dist/app/assets/{arc-OYw_1mUi.js → arc-COu-nBNR.js} +1 -1
  15. package/dist/app/assets/{architectureDiagram-Q4EWVU46-DB9yrqvi.js → architectureDiagram-Q4EWVU46-D-ddveKc.js} +1 -1
  16. package/dist/app/assets/{arduino-BaodkhmL.js → arduino-B_V9Srpy.js} +1 -1
  17. package/dist/app/assets/{arff-CtdflkdY.js → arff-DsGhNcbT.js} +1 -1
  18. package/dist/app/assets/{asciidoc-YRCvqvDt.js → asciidoc-B5CEO5fh.js} +1 -1
  19. package/dist/app/assets/{asm6502-DQmj6WYF.js → asm6502-D2a8tVul.js} +1 -1
  20. package/dist/app/assets/{asmatmel-B_b34PU9.js → asmatmel-DUTqaTnC.js} +1 -1
  21. package/dist/app/assets/{aspnet-DikoFau7.js → aspnet-DLUpHuHv.js} +1 -1
  22. package/dist/app/assets/{autohotkey-DtLs5eHy.js → autohotkey-BSB_nyws.js} +1 -1
  23. package/dist/app/assets/{autoit-CV5yNCU9.js → autoit-BwgYwpuM.js} +1 -1
  24. package/dist/app/assets/{avisynth-Cvl9Dxbj.js → avisynth-Cgf1pYso.js} +1 -1
  25. package/dist/app/assets/{avro-idl-CHxahZY6.js → avro-idl-XqteGdRE.js} +1 -1
  26. package/dist/app/assets/{bash-B5Db2471.js → bash-Dk281cbu.js} +1 -1
  27. package/dist/app/assets/{basic-SxMwItEb.js → basic-uRpIiMGe.js} +1 -1
  28. package/dist/app/assets/{batch-BBcoFjlC.js → batch-C4-m-mLr.js} +1 -1
  29. package/dist/app/assets/{bbcode-BjiejoUJ.js → bbcode-B1LUoNFx.js} +1 -1
  30. package/dist/app/assets/{bicep-KsVmEn1g.js → bicep-CqsJcsXf.js} +1 -1
  31. package/dist/app/assets/{birb-B8jRVP3x.js → birb-DXU3R8QI.js} +1 -1
  32. package/dist/app/assets/{bison-CCal2Z3u.js → bison-BLjm1RgB.js} +1 -1
  33. package/dist/app/assets/{blockDiagram-DXYQGD6D-4aEcQrY2.js → blockDiagram-DXYQGD6D-BHxMFapA.js} +1 -1
  34. package/dist/app/assets/{bnf-D9700Acc.js → bnf-D-7oTwhm.js} +1 -1
  35. package/dist/app/assets/{brainfuck-D8nhdXqW.js → brainfuck-I-YgfuEr.js} +1 -1
  36. package/dist/app/assets/{brightscript-Dj-vu9BW.js → brightscript-CkF_ucD-.js} +1 -1
  37. package/dist/app/assets/{bro-Cd22dEet.js → bro-CPPYpjZw.js} +1 -1
  38. package/dist/app/assets/{bsl-glz5E-bI.js → bsl-CVgUnXO6.js} +1 -1
  39. package/dist/app/assets/{c-BT_dkbEx.js → c-BS7yj6Yf.js} +1 -1
  40. package/dist/app/assets/{c4Diagram-AHTNJAMY-k4XfyLu9.js → c4Diagram-AHTNJAMY-BuCOREEO.js} +1 -1
  41. package/dist/app/assets/{cfscript-C3JXuiQs.js → cfscript-CIVISA6c.js} +1 -1
  42. package/dist/app/assets/{chaiscript-CtAXHhN2.js → chaiscript-DPJ77ndP.js} +1 -1
  43. package/dist/app/assets/channel-DqqmKvlV.js +1 -0
  44. package/dist/app/assets/{chunk-4BX2VUAB-ufyL9ML5.js → chunk-4BX2VUAB-C9mHTP0m.js} +1 -1
  45. package/dist/app/assets/{chunk-4TB4RGXK-BcWB3V7R.js → chunk-4TB4RGXK-B9VoBVJp.js} +1 -1
  46. package/dist/app/assets/{chunk-55IACEB6-B-bXUWk6.js → chunk-55IACEB6-N4Q-mlk6.js} +1 -1
  47. package/dist/app/assets/{chunk-EDXVE4YY-Sb8Q75g2.js → chunk-EDXVE4YY-D-MWM76q.js} +1 -1
  48. package/dist/app/assets/{chunk-FMBD7UC4-BKt1Qj6I.js → chunk-FMBD7UC4-DDGTq6jI.js} +1 -1
  49. package/dist/app/assets/{chunk-OYMX7WX6-D22I1Lke.js → chunk-OYMX7WX6-BBZDoYQI.js} +1 -1
  50. package/dist/app/assets/{chunk-QZHKN3VN-OBgxRqO-.js → chunk-QZHKN3VN-DdnHt9oV.js} +1 -1
  51. package/dist/app/assets/{chunk-YZCP3GAM-pUxs6dq2.js → chunk-YZCP3GAM-CDlHGJHz.js} +1 -1
  52. package/dist/app/assets/{cil-Aus-_gof.js → cil-DZ05JSZt.js} +1 -1
  53. package/dist/app/assets/classDiagram-6PBFFD2Q-DDmxiqHK.js +1 -0
  54. package/dist/app/assets/classDiagram-v2-HSJHXN6E-DDmxiqHK.js +1 -0
  55. package/dist/app/assets/{clike-BmPHnJ_s.js → clike-C-dce4Yl.js} +1 -1
  56. package/dist/app/assets/{clojure-CW-GjCE-.js → clojure-Cik0pyKG.js} +1 -1
  57. package/dist/app/assets/clone-DzAFCb4d.js +1 -0
  58. package/dist/app/assets/{cmake-B9JwnXJm.js → cmake-ClItZh_8.js} +1 -1
  59. package/dist/app/assets/{cobol-MM2iB1tf.js → cobol-DWNFtn0e.js} +1 -1
  60. package/dist/app/assets/{coffeescript-BYj4cAte.js → coffeescript-DFxA9g0F.js} +1 -1
  61. package/dist/app/assets/{concurnas-Dvsu2_MG.js → concurnas-uPVT6qf5.js} +1 -1
  62. package/dist/app/assets/{coq-CgVwYmnQ.js → coq-BSKv5Z4t.js} +1 -1
  63. package/dist/app/assets/{core-C_147WSZ.js → core-CqabDKxB.js} +1 -1
  64. package/dist/app/assets/{cose-bilkent-S5V4N54A-D1OYkuPl.js → cose-bilkent-S5V4N54A-BRQTAZ30.js} +1 -1
  65. package/dist/app/assets/{cpp-BXHX6A9n.js → cpp-BKB6xq7P.js} +1 -1
  66. package/dist/app/assets/{crystal-CjFk19Ts.js → crystal-ptPEIgBt.js} +1 -1
  67. package/dist/app/assets/{csharp-CmTfGjFs.js → csharp-DKCrBSIr.js} +1 -1
  68. package/dist/app/assets/{cshtml-BCUe0yaT.js → cshtml-DnjmY1aO.js} +1 -1
  69. package/dist/app/assets/{csp-CCHnC8Po.js → csp-CzmWWq7i.js} +1 -1
  70. package/dist/app/assets/{css-extras-DK4mKYOO.js → css-extras-CZ9kQxJC.js} +1 -1
  71. package/dist/app/assets/{css-C8eNDHXz.js → css-nabIgEws.js} +1 -1
  72. package/dist/app/assets/{csv-qe24SbyQ.js → csv-BG0H1N52.js} +1 -1
  73. package/dist/app/assets/{cypher-DTaNl2V1.js → cypher-DyEzG7ti.js} +1 -1
  74. package/dist/app/assets/{d-DTUhWIJ2.js → d-BMmV-4z1.js} +1 -1
  75. package/dist/app/assets/{dagre-KV5264BT-DwXVdlOV.js → dagre-KV5264BT-B8BjxTZj.js} +1 -1
  76. package/dist/app/assets/{dart-C5UOys48.js → dart-CpGxTj2o.js} +1 -1
  77. package/dist/app/assets/{dataweave-Dj0pMNyP.js → dataweave-DhQPX3BU.js} +1 -1
  78. package/dist/app/assets/{dax-CEobCOU5.js → dax-C_hSU3cL.js} +1 -1
  79. package/dist/app/assets/{dhall-B1ZNT4vf.js → dhall-DHj_sxCo.js} +1 -1
  80. package/dist/app/assets/{diagram-5BDNPKRD-D0Dhsrwn.js → diagram-5BDNPKRD-CAiueCI6.js} +1 -1
  81. package/dist/app/assets/{diagram-G4DWMVQ6-CKzhB2Vi.js → diagram-G4DWMVQ6-DlsV8l1r.js} +1 -1
  82. package/dist/app/assets/{diagram-MMDJMWI5-CVK8DZmo.js → diagram-MMDJMWI5-Kv6CoQdl.js} +1 -1
  83. package/dist/app/assets/{diagram-TYMM5635-C63pXHON.js → diagram-TYMM5635-BznfcBm-.js} +1 -1
  84. package/dist/app/assets/{diff-DUbfn8vo.js → diff-TDLgKsTC.js} +1 -1
  85. package/dist/app/assets/{django-BqtTf9W_.js → django-BGA6uMwl.js} +1 -1
  86. package/dist/app/assets/{dns-zone-file-HiFRqdUC.js → dns-zone-file-CS7N29Nh.js} +1 -1
  87. package/dist/app/assets/{docker-DGrPELO1.js → docker-CFuWEMG4.js} +1 -1
  88. package/dist/app/assets/{dot-BSr3hUqB.js → dot-BuI3fIl5.js} +1 -1
  89. package/dist/app/assets/{ebnf-B6oU2VcU.js → ebnf-0yXcRKzq.js} +1 -1
  90. package/dist/app/assets/{editorconfig-CR4Ao-pW.js → editorconfig-ZwKFQrw_.js} +1 -1
  91. package/dist/app/assets/{eiffel-whkSHtSL.js → eiffel-CCkWkof9.js} +1 -1
  92. package/dist/app/assets/{ejs-BW2scL4F.js → ejs-C9upEEvN.js} +1 -1
  93. package/dist/app/assets/{elixir-CUNINv_i.js → elixir-DpngNXg2.js} +1 -1
  94. package/dist/app/assets/{elm-DmNP9VV8.js → elm-F-WH2jVY.js} +1 -1
  95. package/dist/app/assets/{erDiagram-SMLLAGMA-Bzh8tjuV.js → erDiagram-SMLLAGMA-evVGq9aA.js} +1 -1
  96. package/dist/app/assets/{erb-Ch3DT-PT.js → erb-BGEr245J.js} +1 -1
  97. package/dist/app/assets/{erlang-BaS46QcW.js → erlang-R3_RAdeP.js} +1 -1
  98. package/dist/app/assets/{etlua-Cw5-5TpW.js → etlua-DqqAkZdO.js} +1 -1
  99. package/dist/app/assets/{excel-formula-B7JQQYH7.js → excel-formula-CSiml3ju.js} +1 -1
  100. package/dist/app/assets/{factor-CVzm3y29.js → factor-DmMNhX8j.js} +1 -1
  101. package/dist/app/assets/{false-DFa4x2p8.js → false-BRxcTXb3.js} +1 -1
  102. package/dist/app/assets/{firestore-security-rules-BWCfa1-J.js → firestore-security-rules-QUZ9d15G.js} +1 -1
  103. package/dist/app/assets/{flow-Bt3qEnW5.js → flow-CM8Ul_F8.js} +1 -1
  104. package/dist/app/assets/{flowDiagram-DWJPFMVM-Dvq1OIJB.js → flowDiagram-DWJPFMVM-CRC5ztDh.js} +1 -1
  105. package/dist/app/assets/{fortran-CCu-4Ium.js → fortran-4BoXeWjv.js} +1 -1
  106. package/dist/app/assets/{fsharp-CDiO0qvE.js → fsharp-aLuIEWkd.js} +1 -1
  107. package/dist/app/assets/{ftl-DkrbBJ6h.js → ftl-CiEvcjAh.js} +1 -1
  108. package/dist/app/assets/{ganttDiagram-T4ZO3ILL-BtaWNNLn.js → ganttDiagram-T4ZO3ILL-BA5PQPVx.js} +1 -1
  109. package/dist/app/assets/{gap-CElgN_G6.js → gap-DRHnZupb.js} +1 -1
  110. package/dist/app/assets/{gcode-D1m1Jx_m.js → gcode-Ci4yyT_S.js} +1 -1
  111. package/dist/app/assets/{gdscript-CQyrpld6.js → gdscript-CwHuZksE.js} +1 -1
  112. package/dist/app/assets/{gedcom-C0t2XJjb.js → gedcom-514pRwDC.js} +1 -1
  113. package/dist/app/assets/{gherkin-D2Z-kIb5.js → gherkin-CHJmGFl4.js} +1 -1
  114. package/dist/app/assets/{git-COtp78Yi.js → git-Cpt88esC.js} +1 -1
  115. package/dist/app/assets/{gitGraphDiagram-UUTBAWPF-CwEA20GK.js → gitGraphDiagram-UUTBAWPF-r2T7lPpJ.js} +1 -1
  116. package/dist/app/assets/{glsl-BOfIEs6F.js → glsl-BfrS8yJO.js} +1 -1
  117. package/dist/app/assets/{gml-DEJcGKIl.js → gml-DDgXE7W7.js} +1 -1
  118. package/dist/app/assets/{gn-D2URDt4C.js → gn-CoQG_0n5.js} +1 -1
  119. package/dist/app/assets/{go-H9iqUz92.js → go-B5zj8JkX.js} +1 -1
  120. package/dist/app/assets/{go-module-CI1Cdki8.js → go-module-EmzvkBoA.js} +1 -1
  121. package/dist/app/assets/{graph-DNTBpla7.js → graph-Cf1KoQrp.js} +1 -1
  122. package/dist/app/assets/{graphql-CfY3OrBB.js → graphql-BiDysM4-.js} +1 -1
  123. package/dist/app/assets/{groovy-DKOMKQyq.js → groovy-CpSog8z5.js} +1 -1
  124. package/dist/app/assets/{haml-tAB3bBZc.js → haml-CvSPf2h1.js} +1 -1
  125. package/dist/app/assets/{handlebars-CMRoFkcp.js → handlebars-D-WQRJEB.js} +1 -1
  126. package/dist/app/assets/{haskell-BIno1Xj8.js → haskell-C7BRSZIe.js} +1 -1
  127. package/dist/app/assets/{haxe-BjUHc9TK.js → haxe-_Hcflzq6.js} +1 -1
  128. package/dist/app/assets/{hcl-d_N2T1VA.js → hcl-CWqWstRc.js} +1 -1
  129. package/dist/app/assets/{hlsl-Czs9_QAo.js → hlsl-BxXCCGJZ.js} +1 -1
  130. package/dist/app/assets/{hoon-1-5xCFh9.js → hoon-CwaQ-EFH.js} +1 -1
  131. package/dist/app/assets/{hpkp-BDx00Z1B.js → hpkp-DQmRthIx.js} +1 -1
  132. package/dist/app/assets/{hsts-D_MF-HB_.js → hsts-D8Ur8bD-.js} +1 -1
  133. package/dist/app/assets/{http-D5BtxMl1.js → http-Cw3RkimR.js} +1 -1
  134. package/dist/app/assets/{ichigojam-DMEwRzWG.js → ichigojam-CM6bS6zb.js} +1 -1
  135. package/dist/app/assets/{icon-BePaZLuK.js → icon-CtcSAZYC.js} +1 -1
  136. package/dist/app/assets/{icu-message-format-BlPybne8.js → icu-message-format-DF5LqWc8.js} +1 -1
  137. package/dist/app/assets/{idris-DZlcuSA9.js → idris-BFiVs7gd.js} +1 -1
  138. package/dist/app/assets/{iecst-BkjvfWtO.js → iecst-DdrMjXQ5.js} +1 -1
  139. package/dist/app/assets/{ignore-CdeiHJ0n.js → ignore-DIq2g2-l.js} +1 -1
  140. package/dist/app/assets/index-o0o3Q2hC.css +1 -0
  141. package/dist/app/assets/index-tsW7eKsE.js +762 -0
  142. package/dist/app/assets/{infoDiagram-42DDH7IO-BHLFr032.js → infoDiagram-42DDH7IO-wYyuNxNj.js} +1 -1
  143. package/dist/app/assets/{inform7-cMmC84KD.js → inform7-DzmXERkt.js} +1 -1
  144. package/dist/app/assets/{ini-DVzqNVZv.js → ini-D5KL9MSR.js} +1 -1
  145. package/dist/app/assets/{io-DZZuQgET.js → io-DhsFH1Tp.js} +1 -1
  146. package/dist/app/assets/{ishikawaDiagram-UXIWVN3A-Cfb4YddV.js → ishikawaDiagram-UXIWVN3A-C4-BPurQ.js} +1 -1
  147. package/dist/app/assets/{j-CJ-4uAlV.js → j-5x99BUy1.js} +1 -1
  148. package/dist/app/assets/{java-DCXkSxET.js → java-BF9JoKMx.js} +1 -1
  149. package/dist/app/assets/{javadoc-CrVMKEsI.js → javadoc-BxSJmEM7.js} +1 -1
  150. package/dist/app/assets/{javadoclike-D2L56h5j.js → javadoclike-CPt-8K6_.js} +1 -1
  151. package/dist/app/assets/{javascript-hgymZZUH.js → javascript-BssOsFWy.js} +1 -1
  152. package/dist/app/assets/{javastacktrace-ChLmPkJH.js → javastacktrace-Dd6I7h5J.js} +1 -1
  153. package/dist/app/assets/{jexl-Cv8EINDe.js → jexl-CUEZVd6g.js} +1 -1
  154. package/dist/app/assets/{jolie-C8GHrQQz.js → jolie-D4tUWCAe.js} +1 -1
  155. package/dist/app/assets/{journeyDiagram-VCZTEJTY-BTArqTvD.js → journeyDiagram-VCZTEJTY-4dsXMpZz.js} +1 -1
  156. package/dist/app/assets/{jq-BNVdoY6Z.js → jq-DA4saxp1.js} +1 -1
  157. package/dist/app/assets/{js-extras-BlUxCYhv.js → js-extras-BHoZQrc7.js} +1 -1
  158. package/dist/app/assets/{js-templates-DXYRbGAM.js → js-templates-DHIHpncv.js} +1 -1
  159. package/dist/app/assets/{jsdoc-CMLYNOYD.js → jsdoc-DiRqJjfA.js} +1 -1
  160. package/dist/app/assets/{json-odBxYu2B.js → json-WG7VBScH.js} +1 -1
  161. package/dist/app/assets/{json5-DP7aJM4_.js → json5-TZgr9JRE.js} +1 -1
  162. package/dist/app/assets/{jsonp-B2xUHyW0.js → jsonp-Dv9WqRYx.js} +1 -1
  163. package/dist/app/assets/{jsstacktrace-CmkoO76I.js → jsstacktrace-Gz4Bje7i.js} +1 -1
  164. package/dist/app/assets/{jsx-45IrULtU.js → jsx-Bw3uULWP.js} +1 -1
  165. package/dist/app/assets/{julia-ClR9qq8g.js → julia-D8b2chKD.js} +1 -1
  166. package/dist/app/assets/{kanban-definition-6JOO6SKY-JROcHSgz.js → kanban-definition-6JOO6SKY-BpSZrzpV.js} +1 -1
  167. package/dist/app/assets/{keepalived-C-KownHW.js → keepalived-CxrShb2S.js} +1 -1
  168. package/dist/app/assets/{keyman-CYpySklF.js → keyman-CiksSo_Q.js} +1 -1
  169. package/dist/app/assets/{kotlin-CQbGs2Ue.js → kotlin-DrUdw5kE.js} +1 -1
  170. package/dist/app/assets/{kumir-DToHbC4q.js → kumir-D7RWib-C.js} +1 -1
  171. package/dist/app/assets/{kusto-B6SHYgRi.js → kusto-BV4XMg16.js} +1 -1
  172. package/dist/app/assets/{latex-DrhQGKi6.js → latex-BC0Uyc-d.js} +1 -1
  173. package/dist/app/assets/{latte-BatIWxZM.js → latte-tPT1UrWz.js} +1 -1
  174. package/dist/app/assets/{layout-CmJisaFk.js → layout-BOlQN9Mo.js} +1 -1
  175. package/dist/app/assets/{less-BJapF0M4.js → less-oxG_fu4g.js} +1 -1
  176. package/dist/app/assets/{lilypond-DHb81Qrb.js → lilypond-C88RotJr.js} +1 -1
  177. package/dist/app/assets/{linear-HilAl6Kl.js → linear-BfflU34i.js} +1 -1
  178. package/dist/app/assets/{liquid-BYBkN767.js → liquid-C7TfcW57.js} +1 -1
  179. package/dist/app/assets/{lisp-PTlDHAFe.js → lisp-Buz4RfpM.js} +1 -1
  180. package/dist/app/assets/{livescript-D7mEGuFt.js → livescript-1DQfUkd-.js} +1 -1
  181. package/dist/app/assets/{llvm-BOF01C_Q.js → llvm-JvopDbcE.js} +1 -1
  182. package/dist/app/assets/{log-D_oLYdec.js → log-BnfCB9DE.js} +1 -1
  183. package/dist/app/assets/{lolcode-BOp3ZdpE.js → lolcode-D_D_7GzE.js} +1 -1
  184. package/dist/app/assets/{lua-CdyGJajb.js → lua-CO1cU0XH.js} +1 -1
  185. package/dist/app/assets/{magma-asqA2vhX.js → magma-B1G7u0t4.js} +1 -1
  186. package/dist/app/assets/{makefile-CYytCSPK.js → makefile-AeGGTOcq.js} +1 -1
  187. package/dist/app/assets/{markdown-jxdlECxY.js → markdown-C8OTDGWj.js} +1 -1
  188. package/dist/app/assets/{markup-CLxozN6F.js → markup-fcpLEWs9.js} +1 -1
  189. package/dist/app/assets/{markup-templating-Cs7ayZpi.js → markup-templating-BJPOJotJ.js} +1 -1
  190. package/dist/app/assets/{matlab-BoNKjSLV.js → matlab-C5u9cVSe.js} +1 -1
  191. package/dist/app/assets/{maxscript-xgjeOfTE.js → maxscript-D1j46lZY.js} +1 -1
  192. package/dist/app/assets/{mel-DnN2qY7Z.js → mel-4T8xB3kc.js} +1 -1
  193. package/dist/app/assets/{mermaid-Di7Rvujk.js → mermaid-D2CuapgG.js} +1 -1
  194. package/dist/app/assets/{min-D-U2U04w.js → min-C6bAU5tf.js} +1 -1
  195. package/dist/app/assets/{mindmap-definition-QFDTVHPH-7f0wW_f6.js → mindmap-definition-QFDTVHPH-DQCqFXf4.js} +1 -1
  196. package/dist/app/assets/{mizar-DNfbYlTh.js → mizar-6YzPCneu.js} +1 -1
  197. package/dist/app/assets/{mongodb-BDy5e9Pj.js → mongodb-rU_FNrrO.js} +1 -1
  198. package/dist/app/assets/{monkey-BRH4J8qW.js → monkey-DHTaMD5j.js} +1 -1
  199. package/dist/app/assets/{moonscript-CH8q91fg.js → moonscript-B4Q1sWnw.js} +1 -1
  200. package/dist/app/assets/{n1ql-Cnsejlzs.js → n1ql-C-kQ4Dz0.js} +1 -1
  201. package/dist/app/assets/{n4js-B3Iq3-1_.js → n4js-B4Kuv0gT.js} +1 -1
  202. package/dist/app/assets/{nand2tetris-hdl-CU1IJ4Jw.js → nand2tetris-hdl-BEZvFDwm.js} +1 -1
  203. package/dist/app/assets/{naniscript-jbrJD2kA.js → naniscript-0DISbVj5.js} +1 -1
  204. package/dist/app/assets/{nasm-CknzFEer.js → nasm-Cy_rHjd9.js} +1 -1
  205. package/dist/app/assets/{neon-26-IayFN.js → neon-CQPnGFjU.js} +1 -1
  206. package/dist/app/assets/{nevod-BJEC391b.js → nevod-Cc2uvwJy.js} +1 -1
  207. package/dist/app/assets/{nginx-Vpvjjaaf.js → nginx-CtSV-zWN.js} +1 -1
  208. package/dist/app/assets/{nim-DyKtgNBt.js → nim-Cx8sXTrq.js} +1 -1
  209. package/dist/app/assets/{nix-BMFnBzg-.js → nix-fzCInmbw.js} +1 -1
  210. package/dist/app/assets/{nsis-SbQZmFez.js → nsis-B-WmXulG.js} +1 -1
  211. package/dist/app/assets/{objectivec-BHCbn7Vg.js → objectivec-B7mP6oMV.js} +1 -1
  212. package/dist/app/assets/{ocaml-B_NbRFYO.js → ocaml-BCNitKcz.js} +1 -1
  213. package/dist/app/assets/{opencl-DGGnjyh8.js → opencl-Ccg1YnSK.js} +1 -1
  214. package/dist/app/assets/{openqasm-BB7WCrXB.js → openqasm-CtnHTd2G.js} +1 -1
  215. package/dist/app/assets/{oz-CHFXD-ie.js → oz-DXv1OItd.js} +1 -1
  216. package/dist/app/assets/{parigp-hCut1WJq.js → parigp-Cb_kuYUA.js} +1 -1
  217. package/dist/app/assets/{parser-Cst8mRu7.js → parser-CwT8uubF.js} +1 -1
  218. package/dist/app/assets/{pascal-BCJwXon0.js → pascal-B5wSlm8n.js} +1 -1
  219. package/dist/app/assets/{pascaligo-B6Cgg9Mq.js → pascaligo-D7-1FMxX.js} +1 -1
  220. package/dist/app/assets/{pcaxis-C4xWQM2D.js → pcaxis-DbHPrVNE.js} +1 -1
  221. package/dist/app/assets/{peoplecode-Dkb6XtUf.js → peoplecode-Bwty_AUm.js} +1 -1
  222. package/dist/app/assets/{perl-H221EXvJ.js → perl-BiIJMtwN.js} +1 -1
  223. package/dist/app/assets/{php-BShmZ9_M.js → php-6mreideO.js} +1 -1
  224. package/dist/app/assets/{php-extras-ByhH4OKy.js → php-extras-CBjQ7vIX.js} +1 -1
  225. package/dist/app/assets/{phpdoc-p3qE-fVK.js → phpdoc-B62bzA5k.js} +1 -1
  226. package/dist/app/assets/{pieDiagram-DEJITSTG-BpxQ_Sug.js → pieDiagram-DEJITSTG-URmplZD6.js} +1 -1
  227. package/dist/app/assets/{plsql-Bq0RDvXx.js → plsql-BAj_vv6G.js} +1 -1
  228. package/dist/app/assets/{powerquery-DRH8DvSi.js → powerquery-CzCmbNz6.js} +1 -1
  229. package/dist/app/assets/{powershell-Bevaimo1.js → powershell-CpwS-v1m.js} +1 -1
  230. package/dist/app/assets/{processing-C0GbD3oE.js → processing-9HFL_Kda.js} +1 -1
  231. package/dist/app/assets/{prolog-Di4z8LJE.js → prolog-D71hnbvz.js} +1 -1
  232. package/dist/app/assets/{promql-03Fgifpl.js → promql-Cr4QC9HL.js} +1 -1
  233. package/dist/app/assets/{properties-D1Z19tT1.js → properties-J9p1gfGR.js} +1 -1
  234. package/dist/app/assets/{protobuf-DWz8yR_O.js → protobuf-DMxIf431.js} +1 -1
  235. package/dist/app/assets/{psl-tBEfR2Sh.js → psl-CTytrTSB.js} +1 -1
  236. package/dist/app/assets/{pug-C7eejEs9.js → pug-jEAnZaKi.js} +1 -1
  237. package/dist/app/assets/{puppet-B7zctoCl.js → puppet-DGT0PXLM.js} +1 -1
  238. package/dist/app/assets/{pure-BtT7EWOj.js → pure-DFlG-Euv.js} +1 -1
  239. package/dist/app/assets/{purebasic-Ccj2c-Ej.js → purebasic-fdJezgk1.js} +1 -1
  240. package/dist/app/assets/{purescript-DMkp7ORC.js → purescript-WUURLlSz.js} +1 -1
  241. package/dist/app/assets/{q-DnC31I_1.js → q-CmD9Xmj5.js} +1 -1
  242. package/dist/app/assets/{qml-qQROczBb.js → qml-BMG0y4hi.js} +1 -1
  243. package/dist/app/assets/{qore-CYWTKmh1.js → qore-ndBZlJKP.js} +1 -1
  244. package/dist/app/assets/{qsharp-DGDhAWfE.js → qsharp-DLCEDNKN.js} +1 -1
  245. package/dist/app/assets/{quadrantDiagram-34T5L4WZ-BCvqKtV-.js → quadrantDiagram-34T5L4WZ-DYv3ycY4.js} +1 -1
  246. package/dist/app/assets/{r-DvcBehxz.js → r-B8Kaj2hw.js} +1 -1
  247. package/dist/app/assets/{racket-XWJUhFHR.js → racket-BmjGoXCu.js} +1 -1
  248. package/dist/app/assets/{reason-DpsxmggQ.js → reason-BMBey7GD.js} +1 -1
  249. package/dist/app/assets/{regex-DQtV1_Nu.js → regex-CcOJ-RBo.js} +1 -1
  250. package/dist/app/assets/{rego-D2-FjG8h.js → rego-BIXa5YcP.js} +1 -1
  251. package/dist/app/assets/{renpy-C3S_oPNw.js → renpy-DFVE_JD1.js} +1 -1
  252. package/dist/app/assets/{requirementDiagram-MS252O5E-BICcpYGT.js → requirementDiagram-MS252O5E-enCn9qyU.js} +1 -1
  253. package/dist/app/assets/{rest-DXmPPeBy.js → rest-B9H-hgOJ.js} +1 -1
  254. package/dist/app/assets/{rip-NSOmDEr3.js → rip-Bv5Hr1Jw.js} +1 -1
  255. package/dist/app/assets/{roboconf-CuCQ-NJX.js → roboconf-jRCQTbv5.js} +1 -1
  256. package/dist/app/assets/{robotframework-BsCP1w9s.js → robotframework-B5SYb3S6.js} +1 -1
  257. package/dist/app/assets/{ruby-CJnf6nnh.js → ruby-B9xBZ2-7.js} +1 -1
  258. package/dist/app/assets/{rust-DESdYva3.js → rust-DxSKWUH3.js} +1 -1
  259. package/dist/app/assets/{sankeyDiagram-XADWPNL6-69KpnHMz.js → sankeyDiagram-XADWPNL6-Bhc5bfvg.js} +1 -1
  260. package/dist/app/assets/{sas-DZFbJKR-.js → sas-Ufzee22m.js} +1 -1
  261. package/dist/app/assets/{sass-AnS1s1br.js → sass-D2SeUbd3.js} +1 -1
  262. package/dist/app/assets/{scala-CwhoAHEC.js → scala-1mDQ7lT3.js} +1 -1
  263. package/dist/app/assets/{scheme-C_ljvZBy.js → scheme-C1DE_OtV.js} +1 -1
  264. package/dist/app/assets/{scss-DL1XxErH.js → scss-CG-uC_jx.js} +1 -1
  265. package/dist/app/assets/{sequenceDiagram-FGHM5R23-D7oS24WP.js → sequenceDiagram-FGHM5R23-CDe6bCwe.js} +1 -1
  266. package/dist/app/assets/{shell-session-Cz9O3eeT.js → shell-session-BXrndzdM.js} +1 -1
  267. package/dist/app/assets/{smali-CB-r7O-_.js → smali-QM7yFavH.js} +1 -1
  268. package/dist/app/assets/{smalltalk-CVFZJVem.js → smalltalk-C-fITGMb.js} +1 -1
  269. package/dist/app/assets/{smarty-BzZkcGHn.js → smarty-4kJKkU5q.js} +1 -1
  270. package/dist/app/assets/{sml-D9RGeV5i.js → sml-ot95negB.js} +1 -1
  271. package/dist/app/assets/{solidity-Dz-wQnyp.js → solidity-Dx_IP6eq.js} +1 -1
  272. package/dist/app/assets/{solution-file-DkmD5yqD.js → solution-file-wapuUhtE.js} +1 -1
  273. package/dist/app/assets/{soy-D85tR8Fr.js → soy-D-5oz9aj.js} +1 -1
  274. package/dist/app/assets/{sparql-BgbB63AF.js → sparql--6Q0TOqj.js} +1 -1
  275. package/dist/app/assets/{splunk-spl-BCo2DCmB.js → splunk-spl-CNbdZc4Q.js} +1 -1
  276. package/dist/app/assets/{sqf-CiA74sHU.js → sqf-DSKo3YQF.js} +1 -1
  277. package/dist/app/assets/{sql-hLzyaqCr.js → sql-gNTttuTN.js} +1 -1
  278. package/dist/app/assets/{squirrel-zcX4QdBa.js → squirrel-DBA8eFXS.js} +1 -1
  279. package/dist/app/assets/{stan-Ckw12XOd.js → stan-DDf1Y7DO.js} +1 -1
  280. package/dist/app/assets/{stateDiagram-FHFEXIEX-BvjpuD2U.js → stateDiagram-FHFEXIEX-p42Be8mf.js} +1 -1
  281. package/dist/app/assets/stateDiagram-v2-QKLJ7IA2-CAhlZfwO.js +1 -0
  282. package/dist/app/assets/{stylus-v6XOnT6H.js → stylus-CjUUyrES.js} +1 -1
  283. package/dist/app/assets/{swift-5_1e6kft.js → swift-CKnKs81t.js} +1 -1
  284. package/dist/app/assets/{systemd-DrgFw48M.js → systemd-C10k014a.js} +1 -1
  285. package/dist/app/assets/{t4-cs-DM0v3lxQ.js → t4-cs-DDiM4sZJ.js} +1 -1
  286. package/dist/app/assets/{t4-templating-DD8VmPrg.js → t4-templating-7kKJq4TZ.js} +1 -1
  287. package/dist/app/assets/{t4-vb-DycV_cM9.js → t4-vb-DuiSnonv.js} +1 -1
  288. package/dist/app/assets/{tap-DGpedrqN.js → tap-IQ8yl2oh.js} +1 -1
  289. package/dist/app/assets/{tcl-c2qhHAdq.js → tcl-DURyRJDt.js} +1 -1
  290. package/dist/app/assets/{textile-C8oUBrkr.js → textile-DQ_JtUdC.js} +1 -1
  291. package/dist/app/assets/{timeline-definition-GMOUNBTQ-B4Jcyau2.js → timeline-definition-GMOUNBTQ-B4uPbG-W.js} +1 -1
  292. package/dist/app/assets/{toml-BGo5hlUM.js → toml-IQN2CNuI.js} +1 -1
  293. package/dist/app/assets/{tremor-eRNxuoON.js → tremor-Bny5MqnS.js} +1 -1
  294. package/dist/app/assets/{tt2-Di8pz9fy.js → tt2-DcdeYRm9.js} +1 -1
  295. package/dist/app/assets/{turtle-vJP3xRTT.js → turtle-ePfiwKUJ.js} +1 -1
  296. package/dist/app/assets/{twig-BnhrPMSB.js → twig-DYNpPvPW.js} +1 -1
  297. package/dist/app/assets/{typescript-37w5F4sD.js → typescript-myhWeMeg.js} +1 -1
  298. package/dist/app/assets/{typoscript-CsApf0xg.js → typoscript-BtWmq6lK.js} +1 -1
  299. package/dist/app/assets/{unrealscript-dRcLpqab.js → unrealscript-BdPAyGL5.js} +1 -1
  300. package/dist/app/assets/{uorazor-30r9Eeul.js → uorazor-CdoHfnCa.js} +1 -1
  301. package/dist/app/assets/{uri-D77IB2tJ.js → uri-8lWJiWx5.js} +1 -1
  302. package/dist/app/assets/{v-CKeEdKLN.js → v-0tJN9Hku.js} +1 -1
  303. package/dist/app/assets/{vala-BetNh6ws.js → vala-XUiF0ZAF.js} +1 -1
  304. package/dist/app/assets/{vbnet-BEMab70S.js → vbnet-BUEocEyh.js} +1 -1
  305. package/dist/app/assets/{velocity-DrfQgf6-.js → velocity-BEOmqWKD.js} +1 -1
  306. package/dist/app/assets/{vennDiagram-DHZGUBPP-CegebJbe.js → vennDiagram-DHZGUBPP-CiBcI7a1.js} +1 -1
  307. package/dist/app/assets/{verilog-uQXkk7Nj.js → verilog-BBKGGmem.js} +1 -1
  308. package/dist/app/assets/{vhdl-DDmmL8UD.js → vhdl-B-_TUb2S.js} +1 -1
  309. package/dist/app/assets/{vim-BDNt86iz.js → vim-D12Uaiun.js} +1 -1
  310. package/dist/app/assets/{visual-basic-pucIF_mU.js → visual-basic-Bt6yOtui.js} +1 -1
  311. package/dist/app/assets/{wardley-RL74JXVD-DsKO1a_J.js → wardley-RL74JXVD-CAHah9aU.js} +1 -1
  312. package/dist/app/assets/{wardleyDiagram-NUSXRM2D-B2JNwjAB.js → wardleyDiagram-NUSXRM2D-DuJOM0rD.js} +1 -1
  313. package/dist/app/assets/{warpscript-CHmOiWY2.js → warpscript-CeTM4-Gj.js} +1 -1
  314. package/dist/app/assets/{wasm-4NqiPBMD.js → wasm-SfMoRKqG.js} +1 -1
  315. package/dist/app/assets/{web-idl-LsIw2yg-.js → web-idl-D20E2F0O.js} +1 -1
  316. package/dist/app/assets/{wiki-nXUE249D.js → wiki-D8abQrQq.js} +1 -1
  317. package/dist/app/assets/{wolfram-Df8JMtQM.js → wolfram-CGEar8g5.js} +1 -1
  318. package/dist/app/assets/{wren-Cs5S9jF3.js → wren-D2cfeRDa.js} +1 -1
  319. package/dist/app/assets/{xeora-BFuaZkC6.js → xeora-CjjXFLG8.js} +1 -1
  320. package/dist/app/assets/{xml-doc-gKIq2LAK.js → xml-doc-3_owB9PN.js} +1 -1
  321. package/dist/app/assets/{xojo-pDFvmFo8.js → xojo-C312JS6O.js} +1 -1
  322. package/dist/app/assets/{xquery-B1ncakta.js → xquery-Cn9l8bPn.js} +1 -1
  323. package/dist/app/assets/{xychartDiagram-5P7HB3ND-WNR7ZTqi.js → xychartDiagram-5P7HB3ND-CvrNIPqq.js} +1 -1
  324. package/dist/app/assets/{yaml-Bar2VcxI.js → yaml-OkW6jhVj.js} +1 -1
  325. package/dist/app/assets/{yang-CpPBz6Mu.js → yang-Dg93mnQG.js} +1 -1
  326. package/dist/app/assets/{zig-BtNZL4AA.js → zig-CD6h8YdZ.js} +1 -1
  327. package/dist/app/index.html +2 -2
  328. package/dist/index.cjs +2341 -872
  329. package/dist/index.js +2354 -873
  330. package/package.json +4 -4
  331. package/dist/app/assets/channel-DVMXuD76.js +0 -1
  332. package/dist/app/assets/classDiagram-6PBFFD2Q-ninoD-P9.js +0 -1
  333. package/dist/app/assets/classDiagram-v2-HSJHXN6E-ninoD-P9.js +0 -1
  334. package/dist/app/assets/clone-BeYqBERf.js +0 -1
  335. package/dist/app/assets/index-AMzNmc5s.js +0 -756
  336. package/dist/app/assets/index-CSm4lUOB.css +0 -1
  337. package/dist/app/assets/stateDiagram-v2-QKLJ7IA2-BcXNYcdm.js +0 -1
package/dist/index.js CHANGED
@@ -1,21 +1,22 @@
1
1
  // src/components/chat.tsx
2
- import * as React52 from "react";
2
+ import * as React54 from "react";
3
3
  import {
4
4
  ArrowDown as ArrowDown2,
5
5
  ChevronDown as ChevronDown5,
6
6
  FileText as FileText5,
7
7
  ImageIcon,
8
- Loader2 as Loader29,
8
+ Loader2 as Loader210,
9
9
  Minus,
10
10
  Pause,
11
11
  Pencil as Pencil4,
12
12
  Play,
13
13
  Quote,
14
14
  Settings as Settings2,
15
- Target as Target2,
15
+ Target as Target3,
16
16
  Trash2 as Trash23,
17
17
  X as X7
18
18
  } from "lucide-react";
19
+ import { CHATKIT_TASK_SUMMARY_OPEN_RESOURCE_EFFECT } from "@xpert-ai/chatkit-types";
19
20
 
20
21
  // src/lib/utils.ts
21
22
  import { clsx } from "clsx";
@@ -393,6 +394,15 @@ function toLineNumber(value) {
393
394
  function isOptionalNumber(value) {
394
395
  return value === void 0 || Number.isFinite(value);
395
396
  }
397
+ function isElementAttribute(value) {
398
+ if (!isObjectLike(value)) {
399
+ return false;
400
+ }
401
+ return "name" in value && "value" in value && typeof value.name === "string" && typeof value.value === "string";
402
+ }
403
+ function isElementAttributes(value) {
404
+ return Array.isArray(value) && value.every(isElementAttribute);
405
+ }
396
406
  function toOptionalNumber(value, options) {
397
407
  const allowZero = options?.allowZero ?? false;
398
408
  if (!Number.isFinite(value)) {
@@ -428,6 +438,20 @@ function isImageReferenceCandidate(value) {
428
438
  const candidate = value;
429
439
  return candidate.type === "image" && isOptionalString(candidate.id) && isOptionalString(candidate.label) && isOptionalString(candidate.text) && isOptionalString(candidate.fileId) && isOptionalString(candidate.url) && isOptionalString(candidate.mimeType) && isOptionalString(candidate.name) && isOptionalNumber(candidate.size) && isOptionalNumber(candidate.width) && isOptionalNumber(candidate.height) && hasImageReferenceLocator(candidate);
430
440
  }
441
+ function isElementReferenceCandidate(value) {
442
+ if (!isObjectLike(value)) {
443
+ return false;
444
+ }
445
+ const candidate = value;
446
+ return candidate.type === "element" && isElementAttributes(candidate.attributes) && isNonEmptyString(candidate.outerHtml) && isNonEmptyString(candidate.pageUrl) && isNonEmptyString(candidate.selector) && isNonEmptyString(candidate.serviceId) && isNonEmptyString(candidate.tagName) && toReferenceText(candidate.text) !== null && isOptionalString(candidate.id) && isOptionalString(candidate.label) && isOptionalString(candidate.pageTitle) && isOptionalString(candidate.role);
447
+ }
448
+ function isFileElementReferenceCandidate(value) {
449
+ if (!isObjectLike(value)) {
450
+ return false;
451
+ }
452
+ const candidate = value;
453
+ return candidate.type === "file_element" && isElementAttributes(candidate.attributes) && isNonEmptyString(candidate.domPath) && isNonEmptyString(candidate.filePath) && isNonEmptyString(candidate.outerHtml) && isNonEmptyString(candidate.selector) && isNonEmptyString(candidate.tagName) && toReferenceText(candidate.text) !== null && isOptionalString(candidate.id) && isOptionalString(candidate.label) && isOptionalString(candidate.documentTitle) && isOptionalString(candidate.role) && isOptionalNumber(candidate.sourceStartLine) && isOptionalNumber(candidate.sourceEndLine);
454
+ }
431
455
  function toCodeReference(candidate) {
432
456
  return {
433
457
  type: "code",
@@ -472,6 +496,48 @@ function toImageReference(candidate) {
472
496
  ...toOptionalNumber(candidate.height) !== void 0 ? { height: toOptionalNumber(candidate.height) } : {}
473
497
  };
474
498
  }
499
+ function toElementReference(candidate) {
500
+ const id = toOptionalString(candidate.id);
501
+ const label = toOptionalString(candidate.label);
502
+ const pageTitle = toOptionalString(candidate.pageTitle);
503
+ const role = toOptionalString(candidate.role);
504
+ return {
505
+ type: "element",
506
+ ...id ? { id } : {},
507
+ ...label ? { label } : {},
508
+ attributes: candidate.attributes,
509
+ outerHtml: candidate.outerHtml,
510
+ ...pageTitle ? { pageTitle } : {},
511
+ pageUrl: candidate.pageUrl.trim(),
512
+ ...role ? { role } : {},
513
+ selector: candidate.selector,
514
+ serviceId: candidate.serviceId,
515
+ tagName: candidate.tagName,
516
+ text: candidate.text
517
+ };
518
+ }
519
+ function toFileElementReference(candidate) {
520
+ const id = toOptionalString(candidate.id);
521
+ const label = toOptionalString(candidate.label);
522
+ const documentTitle = toOptionalString(candidate.documentTitle);
523
+ const role = toOptionalString(candidate.role);
524
+ return {
525
+ type: "file_element",
526
+ ...id ? { id } : {},
527
+ ...label ? { label } : {},
528
+ attributes: candidate.attributes,
529
+ ...documentTitle ? { documentTitle } : {},
530
+ domPath: candidate.domPath,
531
+ filePath: candidate.filePath,
532
+ outerHtml: candidate.outerHtml,
533
+ ...role ? { role } : {},
534
+ selector: candidate.selector,
535
+ ...toOptionalNumber(candidate.sourceStartLine) !== void 0 ? { sourceStartLine: candidate.sourceStartLine } : {},
536
+ ...toOptionalNumber(candidate.sourceEndLine) !== void 0 ? { sourceEndLine: candidate.sourceEndLine } : {},
537
+ tagName: candidate.tagName,
538
+ text: candidate.text
539
+ };
540
+ }
475
541
  function isLegacyCodeReference(candidate) {
476
542
  return candidate.type === void 0 && isNonEmptyString(candidate.path) && toLineNumber(candidate.startLine) !== null && toLineNumber(candidate.endLine) !== null && toReferenceText(candidate.text) !== null;
477
543
  }
@@ -490,6 +556,12 @@ function normalizeReference(value) {
490
556
  if (isImageReferenceCandidate(candidate)) {
491
557
  return toImageReference(candidate);
492
558
  }
559
+ if (isElementReferenceCandidate(candidate)) {
560
+ return toElementReference(candidate);
561
+ }
562
+ if (isFileElementReferenceCandidate(candidate)) {
563
+ return toFileElementReference(candidate);
564
+ }
493
565
  if (type === void 0 && isLegacyCodeReference(candidate)) {
494
566
  return toCodeReference(candidate);
495
567
  }
@@ -564,6 +636,22 @@ function getReferenceKey(reference) {
564
636
  reference.text
565
637
  ].join(":");
566
638
  }
639
+ if (reference.type === "element") {
640
+ return [
641
+ reference.type,
642
+ reference.serviceId,
643
+ reference.pageUrl,
644
+ reference.selector
645
+ ].join(":");
646
+ }
647
+ if (reference.type === "file_element") {
648
+ return [
649
+ reference.type,
650
+ reference.filePath,
651
+ reference.domPath,
652
+ reference.selector
653
+ ].join(":");
654
+ }
567
655
  return [
568
656
  reference.type,
569
657
  reference.messageId ?? "",
@@ -596,7 +684,13 @@ function getReferenceLabel(reference) {
596
684
  if (reference.type === "image") {
597
685
  return reference.name?.trim() || "Pasted image";
598
686
  }
599
- if (reference.source && reference.source.trim()) {
687
+ if (reference.type === "element") {
688
+ return reference.pageTitle?.trim() || reference.tagName;
689
+ }
690
+ if (reference.type === "file_element") {
691
+ return reference.documentTitle?.trim() || reference.filePath;
692
+ }
693
+ if (reference.type === "quote" && reference.source?.trim()) {
600
694
  return reference.source.trim();
601
695
  }
602
696
  return getQuoteExcerpt(reference);
@@ -609,10 +703,18 @@ function getReferenceMetaLine(reference) {
609
703
  const parts = getImageReferenceMetaParts(reference);
610
704
  return parts.length ? parts.join(" \u2022 ") : null;
611
705
  }
612
- if (reference.source && reference.source.trim()) {
706
+ if (reference.type === "element") {
707
+ return reference.pageUrl;
708
+ }
709
+ if (reference.type === "file_element") {
710
+ const start = reference.sourceStartLine;
711
+ const end = reference.sourceEndLine ?? start;
712
+ return start ? `${reference.filePath}:${start}${end === start ? "" : `-${end}`}` : reference.filePath;
713
+ }
714
+ if (reference.type === "quote" && reference.source?.trim()) {
613
715
  return getQuoteExcerpt(reference);
614
716
  }
615
- if (reference.messageId && reference.messageId.trim()) {
717
+ if (reference.type === "quote" && reference.messageId?.trim()) {
616
718
  return `Message ${reference.messageId.trim()}`;
617
719
  }
618
720
  return null;
@@ -638,6 +740,17 @@ ${reference.text}`;
638
740
  }
639
741
  return titleLines.join("\n");
640
742
  }
743
+ if (reference.type === "element") {
744
+ return `${getReferenceLabel(reference)}
745
+ ${reference.pageUrl}
746
+
747
+ ${reference.text}`;
748
+ }
749
+ if (reference.type === "file_element") {
750
+ return `${getReferenceMetaLine(reference) ?? reference.filePath}
751
+
752
+ ${reference.text}`;
753
+ }
641
754
  const header = reference.label?.trim() || reference.source?.trim() || "Quoted text";
642
755
  return `${header}
643
756
 
@@ -1258,6 +1371,550 @@ function countCompletedTodos(items) {
1258
1371
  return items.filter((item) => item.status === "completed").length;
1259
1372
  }
1260
1373
 
1374
+ // src/lib/task-summary.ts
1375
+ var PLAN_PATTERN = /<proposed_plan>\s*([\s\S]*?)\s*<\/proposed_plan>/i;
1376
+ function isObject(value) {
1377
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1378
+ }
1379
+ function stringValue(value) {
1380
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
1381
+ }
1382
+ function timestamp(value) {
1383
+ const parsed = value ? Date.parse(value) : 0;
1384
+ return Number.isNaN(parsed) ? 0 : parsed;
1385
+ }
1386
+ function contentParts(content) {
1387
+ return Array.isArray(content) ? content.filter((part) => isObject(part)) : [];
1388
+ }
1389
+ function messageText(content) {
1390
+ if (typeof content === "string") return content;
1391
+ return contentParts(content).map(
1392
+ (part) => isObject(part) && "text" in part ? stringValue(part.text) ?? "" : ""
1393
+ ).join("\n");
1394
+ }
1395
+ function normalizeTaskSummaryContribution(value) {
1396
+ if (!isObject(value)) return null;
1397
+ const candidate = value;
1398
+ if (candidate.version !== 1) return null;
1399
+ const plan = normalizePlan(candidate.plan);
1400
+ const todos = normalizeTodos(candidate.todos);
1401
+ const outputs = Array.isArray(candidate.outputs) ? candidate.outputs.flatMap((item) => normalizeOutput(item) ?? []) : [];
1402
+ const sources = Array.isArray(candidate.sources) ? candidate.sources.flatMap((item) => normalizeSource(item) ?? []) : [];
1403
+ return {
1404
+ version: 1,
1405
+ ...plan ? { plan } : {},
1406
+ ...todos ? { todos } : {},
1407
+ ...outputs.length ? { outputs } : {},
1408
+ ...sources.length ? { sources } : {}
1409
+ };
1410
+ }
1411
+ function normalizePlan(value) {
1412
+ if (!isObject(value)) return null;
1413
+ const candidate = value;
1414
+ const title = stringValue(candidate.title);
1415
+ const excerpt = stringValue(candidate.excerpt);
1416
+ return title && excerpt ? {
1417
+ title,
1418
+ excerpt,
1419
+ messageId: stringValue(candidate.messageId),
1420
+ updatedAt: stringValue(candidate.updatedAt)
1421
+ } : null;
1422
+ }
1423
+ function normalizeTodos(value) {
1424
+ if (!isObject(value)) return null;
1425
+ const candidate = value;
1426
+ const componentId = stringValue(candidate.componentId);
1427
+ if (!componentId || !Array.isArray(candidate.items)) return null;
1428
+ const items = candidate.items.flatMap((item) => {
1429
+ if (!isObject(item)) return [];
1430
+ const todo = item;
1431
+ const id = stringValue(todo.id);
1432
+ const content = stringValue(todo.content);
1433
+ const status = todo.status;
1434
+ return id && content && isTodoStatus(status) ? [{ id, content, status }] : [];
1435
+ });
1436
+ return items.length ? {
1437
+ componentId,
1438
+ title: stringValue(candidate.title),
1439
+ items,
1440
+ messageId: stringValue(candidate.messageId),
1441
+ updatedAt: stringValue(candidate.updatedAt)
1442
+ } : null;
1443
+ }
1444
+ function isTodoStatus(value) {
1445
+ return value === "pending" || value === "in_progress" || value === "completed";
1446
+ }
1447
+ function normalizeOutput(value) {
1448
+ if (!isObject(value)) return null;
1449
+ const candidate = value;
1450
+ const id = stringValue(candidate.id);
1451
+ const title = stringValue(candidate.title);
1452
+ const kind = artifactKind(candidate.kind);
1453
+ if (!id || !title || !kind) return null;
1454
+ const status = candidate.status;
1455
+ return {
1456
+ id,
1457
+ kind,
1458
+ title,
1459
+ description: stringValue(candidate.description),
1460
+ status: status === "pending" || status === "running" || status === "success" || status === "error" ? status : void 0,
1461
+ resource: normalizeResource(candidate.resource),
1462
+ messageId: stringValue(candidate.messageId),
1463
+ updatedAt: stringValue(candidate.updatedAt)
1464
+ };
1465
+ }
1466
+ function normalizeSource(value) {
1467
+ if (!isObject(value)) return null;
1468
+ const candidate = value;
1469
+ const id = stringValue(candidate.id);
1470
+ const title = stringValue(candidate.title);
1471
+ if (!id || !title || !isSourceKind(candidate.kind)) return null;
1472
+ return {
1473
+ id,
1474
+ kind: candidate.kind,
1475
+ title,
1476
+ description: stringValue(candidate.description),
1477
+ resource: normalizeResource(candidate.resource),
1478
+ messageId: stringValue(candidate.messageId),
1479
+ updatedAt: stringValue(candidate.updatedAt)
1480
+ };
1481
+ }
1482
+ function normalizeResource(value) {
1483
+ if (!isObject(value)) return void 0;
1484
+ const candidate = value;
1485
+ if (candidate.type === "message") {
1486
+ const messageId = stringValue(candidate.messageId);
1487
+ return messageId ? { type: "message", messageId } : void 0;
1488
+ }
1489
+ if (candidate.type === "workspace_file") {
1490
+ const workspacePath = stringValue(candidate.workspacePath);
1491
+ return workspacePath ? {
1492
+ type: "workspace_file",
1493
+ workspacePath,
1494
+ fileAssetId: stringValue(candidate.fileAssetId),
1495
+ storageFileId: stringValue(candidate.storageFileId)
1496
+ } : void 0;
1497
+ }
1498
+ if (candidate.type === "artifact") {
1499
+ const artifactId = stringValue(candidate.artifactId);
1500
+ return artifactId ? { type: "artifact", artifactId } : void 0;
1501
+ }
1502
+ if (candidate.type === "browser") {
1503
+ const serviceId = stringValue(candidate.serviceId);
1504
+ const url = stringValue(candidate.url);
1505
+ return serviceId || url ? { type: "browser", serviceId, url } : void 0;
1506
+ }
1507
+ if (candidate.type === "url") {
1508
+ const url = stringValue(candidate.url);
1509
+ return url ? { type: "url", url } : void 0;
1510
+ }
1511
+ return void 0;
1512
+ }
1513
+ function isSourceKind(value) {
1514
+ return value === "attachment" || value === "code" || value === "quote" || value === "image" || value === "web_page" || value === "file_element" || value === "knowledge" || value === "skill" || value === "plugin" || value === "sub_agent";
1515
+ }
1516
+ function contributionFromPart(part) {
1517
+ if (part.type !== "component" || !isObject(part.data)) return null;
1518
+ const data = part.data;
1519
+ const direct = normalizeTaskSummaryContribution(data.taskSummary);
1520
+ if (direct) return direct;
1521
+ if (!isObject(data._meta)) return null;
1522
+ return normalizeTaskSummaryContribution(
1523
+ data._meta["xpertai/taskSummary"]
1524
+ );
1525
+ }
1526
+ function extractPlan(message) {
1527
+ const match = PLAN_PATTERN.exec(messageText(message.content));
1528
+ const markdown = match?.[1]?.trim();
1529
+ if (!markdown) return void 0;
1530
+ const title = markdown.split(/\r?\n/).map((line) => line.replace(/^#{1,6}\s+/, "").trim()).find(Boolean);
1531
+ const excerpt = markdown.replace(/\s+/g, " ").trim();
1532
+ return {
1533
+ title: title ?? "Plan",
1534
+ excerpt: excerpt.length <= 160 ? excerpt : `${excerpt.slice(0, 157).trimEnd()}...`,
1535
+ messageId: message.id,
1536
+ updatedAt: message.updatedAt ?? message.createdAt
1537
+ };
1538
+ }
1539
+ function artifactKind(value) {
1540
+ switch (value) {
1541
+ case "file":
1542
+ case "image":
1543
+ case "document":
1544
+ case "spreadsheet":
1545
+ case "presentation":
1546
+ case "site":
1547
+ case "url":
1548
+ case "mcp_app":
1549
+ return value;
1550
+ case "html":
1551
+ return "site";
1552
+ case "markdown":
1553
+ case "pdf":
1554
+ return "document";
1555
+ case "pptx":
1556
+ return "presentation";
1557
+ default:
1558
+ return null;
1559
+ }
1560
+ }
1561
+ function knownPartOutputs(part, message) {
1562
+ const updatedAt = message.updatedAt ?? message.createdAt;
1563
+ if (part.type === "image_url") {
1564
+ const url = stringValue(part.image_url) ?? (isObject(part.image_url) && "url" in part.image_url ? stringValue(part.image_url.url) : void 0);
1565
+ return url ? [
1566
+ {
1567
+ id: `image:${url}`,
1568
+ kind: "image",
1569
+ title: stringValue(part.title) ?? "Image",
1570
+ resource: { type: "url", url },
1571
+ messageId: message.id,
1572
+ updatedAt
1573
+ }
1574
+ ] : [];
1575
+ }
1576
+ if (part.type === "iframe") {
1577
+ const url = stringValue(part.url) ?? (isObject(part.data) ? stringValue(part.data.url) : void 0);
1578
+ return url ? [
1579
+ {
1580
+ id: `url:${url}`,
1581
+ kind: "url",
1582
+ title: stringValue(part.title) ?? url,
1583
+ resource: { type: "url", url },
1584
+ messageId: message.id,
1585
+ updatedAt
1586
+ }
1587
+ ] : [];
1588
+ }
1589
+ if (part.type !== "component" || !isObject(part.data)) return [];
1590
+ const data = part.data;
1591
+ const outputs = [...contributionFromPart(part)?.outputs ?? []];
1592
+ if (data.type === "McpApp") {
1593
+ outputs.push({
1594
+ id: `mcp-app:${stringValue(part.id) ?? message.id ?? "message"}`,
1595
+ kind: "mcp_app",
1596
+ title: stringValue(data.title) ?? "MCP App",
1597
+ resource: message.id ? { type: "message", messageId: message.id } : void 0,
1598
+ messageId: message.id,
1599
+ updatedAt
1600
+ });
1601
+ }
1602
+ if (isObject(data.artifact)) {
1603
+ const artifact = data.artifact;
1604
+ const artifactId = stringValue(artifact.artifactId) ?? stringValue(artifact.id);
1605
+ const workspacePath = stringValue(artifact.workspacePath);
1606
+ const kind = artifactKind(artifact.kind) ?? "file";
1607
+ const id = artifactId ?? stringValue(artifact.fileAssetId) ?? workspacePath;
1608
+ if (kind && id && (artifactId || workspacePath)) {
1609
+ outputs.push({
1610
+ id: `artifact:${id}`,
1611
+ kind,
1612
+ title: stringValue(artifact.title) ?? id,
1613
+ description: stringValue(artifact.description),
1614
+ resource: artifactId ? { type: "artifact", artifactId } : {
1615
+ type: "workspace_file",
1616
+ workspacePath,
1617
+ fileAssetId: stringValue(artifact.fileAssetId),
1618
+ storageFileId: stringValue(artifact.storageFileId)
1619
+ },
1620
+ messageId: message.id,
1621
+ updatedAt
1622
+ });
1623
+ }
1624
+ }
1625
+ for (const value of [data.artifactLink, data.file]) {
1626
+ if (!isObject(value)) continue;
1627
+ const artifact = value;
1628
+ const artifactId = stringValue(artifact.artifactId) ?? stringValue(artifact.id);
1629
+ const workspacePath = stringValue(artifact.workspacePath);
1630
+ const id = artifactId ?? stringValue(artifact.fileAssetId) ?? workspacePath;
1631
+ if (!id || !artifactId && !workspacePath) continue;
1632
+ outputs.push({
1633
+ id: `artifact:${id}`,
1634
+ kind: artifactKind(artifact.kind) ?? "file",
1635
+ title: stringValue(artifact.title) ?? id,
1636
+ description: stringValue(artifact.description),
1637
+ resource: artifactId ? { type: "artifact", artifactId } : {
1638
+ type: "workspace_file",
1639
+ workspacePath,
1640
+ fileAssetId: stringValue(artifact.fileAssetId),
1641
+ storageFileId: stringValue(artifact.storageFileId)
1642
+ },
1643
+ messageId: message.id,
1644
+ updatedAt
1645
+ });
1646
+ }
1647
+ return outputs;
1648
+ }
1649
+ function sourceFromReference(reference, message) {
1650
+ const updatedAt = message.updatedAt ?? message.createdAt;
1651
+ const common = {
1652
+ id: reference.id ?? `${reference.type}:${reference.text}`,
1653
+ title: reference.label?.trim() || reference.text.trim().slice(0, 80),
1654
+ messageId: message.id,
1655
+ updatedAt
1656
+ };
1657
+ if (reference.type === "code") {
1658
+ return {
1659
+ ...common,
1660
+ kind: "code",
1661
+ title: reference.label ?? reference.path,
1662
+ description: `${reference.path}:${reference.startLine}-${reference.endLine}`,
1663
+ resource: message.id ? { type: "message", messageId: message.id } : void 0
1664
+ };
1665
+ }
1666
+ if (reference.type === "image") {
1667
+ return {
1668
+ ...common,
1669
+ kind: "image",
1670
+ title: reference.name ?? common.title,
1671
+ resource: reference.url ? { type: "url", url: reference.url } : void 0
1672
+ };
1673
+ }
1674
+ if (reference.type === "element") {
1675
+ return {
1676
+ ...common,
1677
+ kind: "web_page",
1678
+ title: reference.pageTitle ?? reference.pageUrl,
1679
+ description: reference.pageUrl,
1680
+ resource: {
1681
+ type: "browser",
1682
+ serviceId: reference.serviceId,
1683
+ url: reference.pageUrl
1684
+ }
1685
+ };
1686
+ }
1687
+ if (reference.type === "file_element") {
1688
+ return {
1689
+ ...common,
1690
+ kind: "file_element",
1691
+ title: reference.documentTitle ?? reference.filePath,
1692
+ description: reference.filePath,
1693
+ resource: { type: "workspace_file", workspacePath: reference.filePath }
1694
+ };
1695
+ }
1696
+ return { ...common, kind: "quote", description: reference.source };
1697
+ }
1698
+ function fileSources(files, message) {
1699
+ return (files ?? []).flatMap((file) => {
1700
+ const id = stringValue(file.fileAssetId) ?? stringValue(file.id) ?? stringValue(file.storageFileId);
1701
+ const title = stringValue(file.originalName) ?? stringValue(file.name) ?? stringValue(file.fileName);
1702
+ if (!id || !title) return [];
1703
+ const workspacePath = stringValue(file.workspacePath);
1704
+ return [
1705
+ {
1706
+ id: `attachment:${id}`,
1707
+ kind: "attachment",
1708
+ title,
1709
+ resource: workspacePath ? {
1710
+ type: "workspace_file",
1711
+ workspacePath,
1712
+ fileAssetId: stringValue(file.fileAssetId) ?? stringValue(file.id),
1713
+ storageFileId: stringValue(file.storageFileId)
1714
+ } : message.id ? { type: "message", messageId: message.id } : void 0,
1715
+ messageId: message.id,
1716
+ updatedAt: message.updatedAt ?? message.createdAt
1717
+ }
1718
+ ];
1719
+ });
1720
+ }
1721
+ function capabilitySources(message) {
1722
+ const selection = message.runtimeCapabilities;
1723
+ if (!selection) return [];
1724
+ const updatedAt = message.updatedAt ?? message.createdAt;
1725
+ const common = { messageId: message.id, updatedAt };
1726
+ return [
1727
+ ...selection.skills.ids.map((id) => ({
1728
+ ...common,
1729
+ id: `skill:${id}`,
1730
+ kind: "skill",
1731
+ title: id
1732
+ })),
1733
+ ...selection.plugins.nodeKeys.map((id) => ({
1734
+ ...common,
1735
+ id: `plugin:${id}`,
1736
+ kind: "plugin",
1737
+ title: id
1738
+ }))
1739
+ ];
1740
+ }
1741
+ function collectLiveTaskSummary({
1742
+ messages,
1743
+ goal,
1744
+ todos,
1745
+ pending,
1746
+ running,
1747
+ agentNames
1748
+ }) {
1749
+ const contributions = messages.flatMap((message) => [
1750
+ ...message.taskSummary?.version === 1 ? [message.taskSummary] : [],
1751
+ ...contentParts(message.content).flatMap(
1752
+ (part) => contributionFromPart(part) ?? []
1753
+ )
1754
+ ]);
1755
+ const messagePlans = messages.flatMap(
1756
+ (message) => extractPlan(message) ?? []
1757
+ );
1758
+ const agentRuns = messages.flatMap(
1759
+ (message) => (message.agentRuns ?? []).filter((run) => Boolean(run.parentId)).map((run) => ({
1760
+ id: run.id,
1761
+ parentId: run.parentId,
1762
+ level: agentRunLevel(run, messages),
1763
+ agentKey: run.agentKey,
1764
+ title: (run.agentKey ? agentNames?.get(run.agentKey) : void 0) ?? run.title ?? run.xpertName ?? run.agentKey ?? "Agent",
1765
+ status: taskSummaryAgentStatus(run.status),
1766
+ elapsedTime: run.elapsedTime,
1767
+ error: typeof run.error === "string" ? run.error : void 0,
1768
+ messageId: message.id,
1769
+ updatedAt: run.updatedAt ?? run.endedAt ?? run.startedAt ?? message.updatedAt
1770
+ }))
1771
+ );
1772
+ return {
1773
+ goal,
1774
+ plan: newest([
1775
+ ...contributions.flatMap((item) => item.plan ?? []),
1776
+ ...messagePlans
1777
+ ]),
1778
+ todos: todos ? {
1779
+ componentId: todos.componentId,
1780
+ title: todos.title,
1781
+ items: todos.items,
1782
+ updatedAt: todos.endDate ?? todos.createdDate
1783
+ } : newest(contributions.flatMap((item) => item.todos ?? [])),
1784
+ outputs: mergeLatest([
1785
+ ...contributions.flatMap((item) => item.outputs ?? []),
1786
+ ...messages.flatMap(
1787
+ (message) => contentParts(message.content).flatMap(
1788
+ (part) => knownPartOutputs(part, message)
1789
+ )
1790
+ )
1791
+ ]),
1792
+ sources: mergeLatest([
1793
+ ...contributions.flatMap((item) => item.sources ?? []).filter((source) => source.kind !== "sub_agent"),
1794
+ ...messages.flatMap((message) => [
1795
+ ...(message.references ?? []).map(
1796
+ (reference) => sourceFromReference(reference, message)
1797
+ ),
1798
+ ...fileSources(message.fileAssets, message),
1799
+ ...fileSources(message.attachments, message),
1800
+ ...capabilitySources(message)
1801
+ ])
1802
+ ]),
1803
+ agents: mergeAgents(agentRuns),
1804
+ pending: pending ?? [],
1805
+ running: running ?? []
1806
+ };
1807
+ }
1808
+ function mergeTaskSummary(history, live, historySections) {
1809
+ const outputs = mergeLatest([
1810
+ ...historySections?.outputs ?? history?.outputs.items ?? [],
1811
+ ...live.outputs
1812
+ ]);
1813
+ const sources = mergeLatest([
1814
+ ...historySections?.sources ?? history?.sources.items ?? [],
1815
+ ...live.sources
1816
+ ]);
1817
+ const agents = mergeAgents([
1818
+ ...(historySections?.agents ?? history?.agents.items ?? []).filter(
1819
+ (agent) => Boolean(agent.parentId)
1820
+ ),
1821
+ ...live.agents
1822
+ ]);
1823
+ const pending = mergePending([
1824
+ ...historySections?.pending ?? history?.pending.items ?? [],
1825
+ ...live.pending
1826
+ ]);
1827
+ return {
1828
+ goal: live.goal ?? history?.task.goal,
1829
+ plan: newest(
1830
+ [history?.task.plan, live.plan].filter(
1831
+ (item) => Boolean(item)
1832
+ )
1833
+ ),
1834
+ todos: newest(
1835
+ [history?.task.todos, live.todos].filter(
1836
+ (item) => Boolean(item)
1837
+ )
1838
+ ),
1839
+ outputs,
1840
+ sources,
1841
+ agents,
1842
+ pending,
1843
+ running: live.running,
1844
+ totals: {
1845
+ outputs: Math.max(history?.outputs.total ?? 0, outputs.length),
1846
+ sources: Math.max(history?.sources.total ?? 0, sources.length),
1847
+ agents: agents.length,
1848
+ pending: Math.max(history?.pending.total ?? 0, pending.length)
1849
+ }
1850
+ };
1851
+ }
1852
+ function mergeLatest(items) {
1853
+ const byId = /* @__PURE__ */ new Map();
1854
+ items.forEach((item) => {
1855
+ const current = byId.get(item.id);
1856
+ if (!current || timestamp(item.updatedAt) >= timestamp(current.updatedAt)) {
1857
+ byId.set(item.id, item);
1858
+ }
1859
+ });
1860
+ return [...byId.values()].sort(
1861
+ (left, right) => timestamp(right.updatedAt) - timestamp(left.updatedAt)
1862
+ );
1863
+ }
1864
+ function mergeAgents(items) {
1865
+ const byAgent = /* @__PURE__ */ new Map();
1866
+ items.forEach((item) => {
1867
+ const key = item.agentKey?.trim() || item.id;
1868
+ const current = byAgent.get(key);
1869
+ if (!current || timestamp(item.updatedAt) >= timestamp(current.updatedAt)) {
1870
+ byAgent.set(key, item);
1871
+ }
1872
+ });
1873
+ return [...byAgent.values()].sort(
1874
+ (left, right) => timestamp(right.updatedAt) - timestamp(left.updatedAt)
1875
+ );
1876
+ }
1877
+ function mergePending(items) {
1878
+ const byId = new Map(items.map((item) => [item.id, item]));
1879
+ return [...byId.values()].sort(
1880
+ (left, right) => timestamp(right.createdAt) - timestamp(left.createdAt)
1881
+ );
1882
+ }
1883
+ function taskSummaryAgentStatus(status) {
1884
+ switch (status) {
1885
+ case "running":
1886
+ case "success":
1887
+ case "error":
1888
+ case "pending":
1889
+ case "timeout":
1890
+ case "interrupted":
1891
+ return status;
1892
+ default:
1893
+ return void 0;
1894
+ }
1895
+ }
1896
+ function newest(items) {
1897
+ return [...items].sort(
1898
+ (left, right) => timestamp(right.updatedAt) - timestamp(left.updatedAt)
1899
+ )[0];
1900
+ }
1901
+ function agentRunLevel(run, messages) {
1902
+ const byId = new Map(
1903
+ messages.flatMap(
1904
+ (message) => (message.agentRuns ?? []).map((item) => [item.id, item])
1905
+ )
1906
+ );
1907
+ let parentId = run.parentId;
1908
+ let level = 0;
1909
+ const visited = /* @__PURE__ */ new Set();
1910
+ while (parentId && !visited.has(parentId)) {
1911
+ visited.add(parentId);
1912
+ level += 1;
1913
+ parentId = byId.get(parentId)?.parentId;
1914
+ }
1915
+ return level;
1916
+ }
1917
+
1261
1918
  // src/providers/Stream.tsx
1262
1919
  import { jsx as jsx2 } from "react/jsx-runtime";
1263
1920
  var StreamContext = createContext2(void 0);
@@ -1714,6 +2371,39 @@ var en_US_default = {
1714
2371
  failed: "Failed to render diagram"
1715
2372
  }
1716
2373
  },
2374
+ taskSummary: {
2375
+ title: "Task summary",
2376
+ description: "Current task, outputs, sources, running services, agent activity, and pending requests.",
2377
+ open: "Open task summary",
2378
+ empty: "Task activity will appear here.",
2379
+ historyError: "Some historical summary data failed to load. Live activity is still available.",
2380
+ retry: "Retry",
2381
+ viewAll: "View all",
2382
+ loadMore: "Load more",
2383
+ collapse: "Show less",
2384
+ createOutput: "Create files or sites",
2385
+ addOutput: "Create output",
2386
+ addSource: "Add source",
2387
+ sections: {
2388
+ task: "Task",
2389
+ outputs: "Outputs",
2390
+ sources: "Sources",
2391
+ running: "Running",
2392
+ agents: "Agent activity",
2393
+ pending: "Pending"
2394
+ },
2395
+ status: {
2396
+ pending: "Pending",
2397
+ in_progress: "In progress",
2398
+ completed: "Completed"
2399
+ },
2400
+ pending: {
2401
+ approval: "Approval required",
2402
+ userInput: "Input required",
2403
+ followUp: "Pending follow-up message",
2404
+ steer: "Pending steering message"
2405
+ }
2406
+ },
1717
2407
  thread: {
1718
2408
  errorToast: "An error occurred. Please try again.",
1719
2409
  errorLabel: "Error:",
@@ -2122,6 +2812,39 @@ var zh_CN_default = {
2122
2812
  failed: "\u56FE\u8868\u6E32\u67D3\u5931\u8D25"
2123
2813
  }
2124
2814
  },
2815
+ taskSummary: {
2816
+ title: "\u4EFB\u52A1\u6458\u8981",
2817
+ description: "\u5F53\u524D\u4EFB\u52A1\u3001\u4EA7\u51FA\u3001\u6765\u6E90\u3001\u8FD0\u884C\u4E2D\u670D\u52A1\u3001Agent \u6D3B\u52A8\u548C\u5F85\u5904\u7406\u8BF7\u6C42\u3002",
2818
+ open: "\u6253\u5F00\u4EFB\u52A1\u6458\u8981",
2819
+ empty: "\u4EFB\u52A1\u6D3B\u52A8\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\u3002",
2820
+ historyError: "\u90E8\u5206\u5386\u53F2\u6458\u8981\u52A0\u8F7D\u5931\u8D25\uFF0C\u5B9E\u65F6\u6D3B\u52A8\u4ECD\u53EF\u4F7F\u7528\u3002",
2821
+ retry: "\u91CD\u8BD5",
2822
+ viewAll: "\u67E5\u770B\u5168\u90E8",
2823
+ loadMore: "\u52A0\u8F7D\u66F4\u591A",
2824
+ collapse: "\u6536\u8D77",
2825
+ createOutput: "\u521B\u5EFA\u6587\u4EF6\u6216\u7AD9\u70B9",
2826
+ addOutput: "\u521B\u5EFA\u4EA7\u51FA",
2827
+ addSource: "\u6DFB\u52A0\u6765\u6E90",
2828
+ sections: {
2829
+ task: "\u4EFB\u52A1",
2830
+ outputs: "\u4EA7\u51FA",
2831
+ sources: "\u6765\u6E90",
2832
+ running: "\u8FD0\u884C\u4E2D",
2833
+ agents: "Agent \u6D3B\u52A8",
2834
+ pending: "\u5F85\u5904\u7406"
2835
+ },
2836
+ status: {
2837
+ pending: "\u5F85\u5904\u7406",
2838
+ in_progress: "\u8FDB\u884C\u4E2D",
2839
+ completed: "\u5DF2\u5B8C\u6210"
2840
+ },
2841
+ pending: {
2842
+ approval: "\u9700\u8981\u5BA1\u6279",
2843
+ userInput: "\u9700\u8981\u8F93\u5165",
2844
+ followUp: "\u7B49\u5F85\u53D1\u9001\u7684\u8DDF\u8FDB\u6D88\u606F",
2845
+ steer: "\u7B49\u5F85\u53D1\u9001\u7684\u5F15\u5BFC\u6D88\u606F"
2846
+ }
2847
+ },
2125
2848
  thread: {
2126
2849
  errorToast: "\u53D1\u751F\u9519\u8BEF\uFF0C\u8BF7\u91CD\u8BD5\u3002",
2127
2850
  errorLabel: "\u9519\u8BEF\uFF1A",
@@ -4888,8 +5611,8 @@ function JsonTreeNode({
4888
5611
  depth = 0
4889
5612
  }) {
4890
5613
  const isArray = Array.isArray(value);
4891
- const isObject = isJsonObjectValue(value);
4892
- const isExpandable = isArray || isObject;
5614
+ const isObject2 = isJsonObjectValue(value);
5615
+ const isExpandable = isArray || isObject2;
4893
5616
  const [isExpanded, setIsExpanded] = React18.useState(depth < 2);
4894
5617
  if (!isExpandable) {
4895
5618
  return /* @__PURE__ */ jsxs13("div", { className: "flex min-w-0 gap-2 leading-6", children: [
@@ -5284,7 +6007,7 @@ function HITLApprovalPanel({
5284
6007
  }
5285
6008
  const argsText = currentDraft.argsText ?? formatArgs(currentAction.args);
5286
6009
  const argsJsonValue = toJsonValue(currentAction.args) ?? {};
5287
- const messageText = currentDraft.message ?? "";
6010
+ const messageText2 = currentDraft.message ?? "";
5288
6011
  const isCurrentInvalid = validation.error?.actionIndex === currentActionIndex;
5289
6012
  return /* @__PURE__ */ jsxs14(
5290
6013
  "section",
@@ -5446,7 +6169,7 @@ function HITLApprovalPanel({
5446
6169
  /* @__PURE__ */ jsx22(
5447
6170
  "textarea",
5448
6171
  {
5449
- value: messageText,
6172
+ value: messageText2,
5450
6173
  onChange: (event) => updateCurrentDraft({
5451
6174
  ...currentDraft,
5452
6175
  message: event.target.value
@@ -6917,6 +7640,59 @@ var UploadDroppedFiles = React23.forwardRef(function UploadDroppedFiles2({
6917
7640
  );
6918
7641
  });
6919
7642
 
7643
+ // src/components/chat/message-files.ts
7644
+ function addIdentity(identities, value) {
7645
+ const identity = value?.trim();
7646
+ if (identity) {
7647
+ identities.add(identity);
7648
+ }
7649
+ }
7650
+ function getAttachmentIdentities(file) {
7651
+ const identities = /* @__PURE__ */ new Set();
7652
+ addIdentity(identities, file.id);
7653
+ addIdentity(identities, file.fileId);
7654
+ addIdentity(identities, file.storageFileId);
7655
+ addIdentity(identities, file.url);
7656
+ addIdentity(identities, file.fileUrl);
7657
+ addIdentity(identities, file.thumbUrl);
7658
+ return identities;
7659
+ }
7660
+ function getImageReferenceIdentities(references) {
7661
+ const identities = /* @__PURE__ */ new Set();
7662
+ references.forEach((reference) => {
7663
+ if (reference.type !== "image") {
7664
+ return;
7665
+ }
7666
+ addIdentity(identities, reference.id);
7667
+ addIdentity(identities, reference.fileId);
7668
+ addIdentity(identities, reference.url);
7669
+ });
7670
+ return identities;
7671
+ }
7672
+ function getVisibleHumanAttachments(attachments, references) {
7673
+ const imageReferenceIdentities = getImageReferenceIdentities(references);
7674
+ const visibleAttachmentIdentities = /* @__PURE__ */ new Set();
7675
+ return attachments.filter((attachment) => {
7676
+ const identities = getAttachmentIdentities(attachment);
7677
+ const isImageReference = [...identities].some(
7678
+ (identity) => imageReferenceIdentities.has(identity)
7679
+ );
7680
+ if (isImageReference) {
7681
+ return false;
7682
+ }
7683
+ const isDuplicate = [...identities].some(
7684
+ (identity) => visibleAttachmentIdentities.has(identity)
7685
+ );
7686
+ if (isDuplicate) {
7687
+ return false;
7688
+ }
7689
+ identities.forEach(
7690
+ (identity) => visibleAttachmentIdentities.add(identity)
7691
+ );
7692
+ return true;
7693
+ });
7694
+ }
7695
+
6920
7696
  // src/components/chat/usePetAutoState.ts
6921
7697
  import * as React24 from "react";
6922
7698
  function usePetAutoState({
@@ -7880,14 +8656,14 @@ function isComponentContent(content) {
7880
8656
  }
7881
8657
  function parseDateValue(value) {
7882
8658
  if (value instanceof Date) {
7883
- const timestamp2 = value.getTime();
7884
- return Number.isNaN(timestamp2) ? null : timestamp2;
8659
+ const timestamp3 = value.getTime();
8660
+ return Number.isNaN(timestamp3) ? null : timestamp3;
7885
8661
  }
7886
8662
  if (typeof value !== "string") {
7887
8663
  return null;
7888
8664
  }
7889
- const timestamp = Date.parse(value);
7890
- return Number.isNaN(timestamp) ? null : timestamp;
8665
+ const timestamp2 = Date.parse(value);
8666
+ return Number.isNaN(timestamp2) ? null : timestamp2;
7891
8667
  }
7892
8668
  function readContentTitle(content) {
7893
8669
  if (typeof content === "string") return void 0;
@@ -10706,14 +11482,14 @@ function getToolStepData(content) {
10706
11482
  }
10707
11483
  function parseStepDate(value) {
10708
11484
  if (value instanceof Date) {
10709
- const timestamp2 = value.getTime();
10710
- return Number.isNaN(timestamp2) ? null : timestamp2;
11485
+ const timestamp3 = value.getTime();
11486
+ return Number.isNaN(timestamp3) ? null : timestamp3;
10711
11487
  }
10712
11488
  if (typeof value !== "string") {
10713
11489
  return null;
10714
11490
  }
10715
- const timestamp = Date.parse(value);
10716
- return Number.isNaN(timestamp) ? null : timestamp;
11491
+ const timestamp2 = Date.parse(value);
11492
+ return Number.isNaN(timestamp2) ? null : timestamp2;
10717
11493
  }
10718
11494
  function isThreadKnownIdle(isThreadRunning) {
10719
11495
  return isThreadRunning === false;
@@ -12986,14 +13762,14 @@ function MemoryBlock({ content }) {
12986
13762
  }
12987
13763
  function parseStepDate2(value) {
12988
13764
  if (value instanceof Date) {
12989
- const timestamp2 = value.getTime();
12990
- return Number.isNaN(timestamp2) ? null : timestamp2;
13765
+ const timestamp3 = value.getTime();
13766
+ return Number.isNaN(timestamp3) ? null : timestamp3;
12991
13767
  }
12992
13768
  if (typeof value !== "string") {
12993
13769
  return null;
12994
13770
  }
12995
- const timestamp = Date.parse(value);
12996
- return Number.isNaN(timestamp) ? null : timestamp;
13771
+ const timestamp2 = Date.parse(value);
13772
+ return Number.isNaN(timestamp2) ? null : timestamp2;
12997
13773
  }
12998
13774
  function formatStepDuration3(durationMs) {
12999
13775
  if (durationMs < 1e3) {
@@ -13772,9 +14548,9 @@ var getThreadTitle = (threadRecord) => {
13772
14548
  };
13773
14549
  var toDate = (value) => {
13774
14550
  if (!value) return void 0;
13775
- const timestamp = Date.parse(value);
13776
- if (Number.isNaN(timestamp)) return void 0;
13777
- return new Date(timestamp);
14551
+ const timestamp2 = Date.parse(value);
14552
+ if (Number.isNaN(timestamp2)) return void 0;
14553
+ return new Date(timestamp2);
13778
14554
  };
13779
14555
  var getErrorMessage2 = (error) => {
13780
14556
  if (!error) return void 0;
@@ -16533,43 +17309,491 @@ function buildMessageNavigationItems(messages, options) {
16533
17309
  return items;
16534
17310
  }
16535
17311
 
16536
- // src/components/chat.tsx
16537
- import { Fragment as Fragment9, jsx as jsx57, jsxs as jsxs39 } from "react/jsx-runtime";
16538
- var defaultApiUrl2 = import.meta.env.VITE_XPERTAI_API_URL;
16539
- var COMPOSER_INPUT_MAX_HEIGHT = 128;
16540
- var LONG_TEXT_REFERENCE_THRESHOLD = 5e3;
16541
- var GOAL_RUN_INPUT = "Continue working toward the active goal.";
16542
- function isGoalAdapter(value) {
16543
- return Boolean(value) && typeof value === "object" && typeof value.getGoal === "function" && typeof value.setGoal === "function" && typeof value.updateGoal === "function" && typeof value.clearGoal === "function";
16544
- }
16545
- function formatGoalElapsed(seconds) {
16546
- if (seconds < 60) {
16547
- return `${seconds}s`;
16548
- }
16549
- const minutes = Math.floor(seconds / 60);
16550
- const remainingSeconds = seconds % 60;
16551
- return remainingSeconds ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
16552
- }
16553
- async function readImageDimensions(file) {
16554
- if (typeof window === "undefined" || typeof URL === "undefined") {
16555
- return {};
16556
- }
16557
- return new Promise((resolve) => {
16558
- const objectUrl = URL.createObjectURL(file);
16559
- const image = new window.Image();
16560
- const cleanup = () => {
16561
- URL.revokeObjectURL(objectUrl);
16562
- };
16563
- image.onload = () => {
16564
- resolve({
16565
- width: image.naturalWidth || void 0,
16566
- height: image.naturalHeight || void 0
16567
- });
16568
- cleanup();
17312
+ // src/hooks/useTaskSummary.ts
17313
+ import * as React52 from "react";
17314
+ function useTaskSummary({
17315
+ enabled,
17316
+ conversationId,
17317
+ client,
17318
+ live
17319
+ }) {
17320
+ const [loaded, setLoaded] = React52.useState(null);
17321
+ const [historySections, setHistorySections] = React52.useState({});
17322
+ const [historySectionsConversationId, setHistorySectionsConversationId] = React52.useState(null);
17323
+ const [loadingSections, setLoadingSections] = React52.useState({});
17324
+ const [error, setError] = React52.useState(null);
17325
+ const [retryVersion, setRetryVersion] = React52.useState(0);
17326
+ const requestVersionRef = React52.useRef(0);
17327
+ const conversationIdRef = React52.useRef(conversationId);
17328
+ const sectionControllersRef = React52.useRef(
17329
+ /* @__PURE__ */ new Map()
17330
+ );
17331
+ conversationIdRef.current = conversationId;
17332
+ const abortSectionRequests = React52.useCallback(() => {
17333
+ sectionControllersRef.current.forEach((controller) => controller.abort());
17334
+ sectionControllersRef.current.clear();
17335
+ }, []);
17336
+ React52.useEffect(() => {
17337
+ abortSectionRequests();
17338
+ setHistorySections({});
17339
+ setHistorySectionsConversationId(conversationId);
17340
+ setLoadingSections({});
17341
+ setError(null);
17342
+ if (!enabled || !conversationId) {
17343
+ setLoaded(null);
17344
+ setHistorySectionsConversationId(null);
17345
+ return;
17346
+ }
17347
+ const controller = new AbortController();
17348
+ const requestVersion = ++requestVersionRef.current;
17349
+ client.conversations.getTaskSummary(conversationId, { signal: controller.signal }).then((snapshot2) => {
17350
+ if (requestVersionRef.current !== requestVersion) return;
17351
+ setLoaded({ conversationId, snapshot: snapshot2 });
17352
+ }).catch((nextError) => {
17353
+ if (controller.signal.aborted || requestVersionRef.current !== requestVersion)
17354
+ return;
17355
+ setLoaded(null);
17356
+ setError(nextError);
17357
+ });
17358
+ return () => {
17359
+ controller.abort();
17360
+ abortSectionRequests();
17361
+ requestVersionRef.current += 1;
16569
17362
  };
16570
- image.onerror = () => {
16571
- resolve({});
16572
- cleanup();
17363
+ }, [abortSectionRequests, client, conversationId, enabled, retryVersion]);
17364
+ const snapshot = loaded?.conversationId === conversationId ? loaded.snapshot : null;
17365
+ const activeHistorySections = React52.useMemo(
17366
+ () => historySectionsConversationId === conversationId ? historySections : {},
17367
+ [conversationId, historySections, historySectionsConversationId]
17368
+ );
17369
+ const loadSection = React52.useCallback(
17370
+ async (section) => {
17371
+ if (!enabled || !conversationId || loadingSections[section]) {
17372
+ return;
17373
+ }
17374
+ const current = activeHistorySections[section]?.length ?? 0;
17375
+ const controller = new AbortController();
17376
+ sectionControllersRef.current.get(section)?.abort();
17377
+ sectionControllersRef.current.set(section, controller);
17378
+ setLoadingSections((state) => ({ ...state, [section]: true }));
17379
+ try {
17380
+ const page = await client.conversations.listTaskSummaryItems(
17381
+ conversationId,
17382
+ section,
17383
+ { offset: current, limit: 50, signal: controller.signal }
17384
+ );
17385
+ if (conversationIdRef.current !== conversationId) return;
17386
+ setHistorySections(
17387
+ (state) => ({
17388
+ ...state,
17389
+ [section]: [...state[section] ?? [], ...page.items]
17390
+ })
17391
+ );
17392
+ } catch (nextError) {
17393
+ if (!controller.signal.aborted) {
17394
+ setError(nextError);
17395
+ }
17396
+ } finally {
17397
+ if (sectionControllersRef.current.get(section) === controller) {
17398
+ sectionControllersRef.current.delete(section);
17399
+ }
17400
+ if (conversationIdRef.current === conversationId) {
17401
+ setLoadingSections((state) => ({ ...state, [section]: false }));
17402
+ }
17403
+ }
17404
+ },
17405
+ [
17406
+ activeHistorySections,
17407
+ client,
17408
+ conversationId,
17409
+ enabled,
17410
+ loadingSections
17411
+ ]
17412
+ );
17413
+ return {
17414
+ summary: mergeTaskSummary(snapshot, live, activeHistorySections),
17415
+ historyError: error,
17416
+ retryHistory: () => setRetryVersion((version) => version + 1),
17417
+ loadSection,
17418
+ loadingSections,
17419
+ loadedSectionCounts: {
17420
+ outputs: activeHistorySections.outputs?.length ?? 0,
17421
+ sources: activeHistorySections.sources?.length ?? 0,
17422
+ agents: activeHistorySections.agents?.length ?? 0,
17423
+ pending: activeHistorySections.pending?.length ?? 0
17424
+ }
17425
+ };
17426
+ }
17427
+
17428
+ // src/components/task-summary/TaskSummary.tsx
17429
+ import * as React53 from "react";
17430
+ import {
17431
+ Bot as Bot4,
17432
+ BookOpen as BookOpen3,
17433
+ CheckCircle2 as CheckCircle25,
17434
+ CircleEllipsis,
17435
+ ExternalLink,
17436
+ FileOutput,
17437
+ ListChecks as ListChecks3,
17438
+ Loader2 as Loader29,
17439
+ PlayCircle,
17440
+ RotateCcw,
17441
+ Target as Target2
17442
+ } from "lucide-react";
17443
+ import { jsx as jsx57, jsxs as jsxs39 } from "react/jsx-runtime";
17444
+ var PREVIEW_SIZE = 3;
17445
+ function TaskSummaryTrigger({
17446
+ displayMode = "popover",
17447
+ open: controlledOpen,
17448
+ onOpenChange,
17449
+ ...props
17450
+ }) {
17451
+ const { t } = useChatkitTranslation();
17452
+ const [uncontrolledOpen, setUncontrolledOpen] = React53.useState(false);
17453
+ const open = controlledOpen ?? uncontrolledOpen;
17454
+ const setOpen = React53.useCallback(
17455
+ (nextOpen) => {
17456
+ if (controlledOpen === void 0) {
17457
+ setUncontrolledOpen(nextOpen);
17458
+ }
17459
+ onOpenChange?.(nextOpen);
17460
+ },
17461
+ [controlledOpen, onOpenChange]
17462
+ );
17463
+ const triggerButton = /* @__PURE__ */ jsx57(
17464
+ "button",
17465
+ {
17466
+ type: "button",
17467
+ className: "flex h-8 w-8 cursor-pointer items-center justify-center rounded-md text-muted-foreground transition-colors duration-150 hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground",
17468
+ "aria-label": t("taskSummary.open"),
17469
+ "aria-expanded": open,
17470
+ onClick: displayMode === "docked" ? () => setOpen(!open) : void 0,
17471
+ children: /* @__PURE__ */ jsx57(ListChecks3, { size: 16 })
17472
+ }
17473
+ );
17474
+ if (displayMode === "docked") {
17475
+ return /* @__PURE__ */ jsxs39(Tooltip, { children: [
17476
+ /* @__PURE__ */ jsx57(TooltipTrigger, { asChild: true, children: triggerButton }),
17477
+ /* @__PURE__ */ jsx57(TooltipContent, { side: "bottom", children: t("taskSummary.open") })
17478
+ ] });
17479
+ }
17480
+ return /* @__PURE__ */ jsxs39(Popover, { open, onOpenChange: setOpen, children: [
17481
+ /* @__PURE__ */ jsxs39(Tooltip, { children: [
17482
+ /* @__PURE__ */ jsx57(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx57(PopoverTrigger, { asChild: true, children: triggerButton }) }),
17483
+ /* @__PURE__ */ jsx57(TooltipContent, { side: "bottom", children: t("taskSummary.open") })
17484
+ ] }),
17485
+ /* @__PURE__ */ jsx57(
17486
+ PopoverContent,
17487
+ {
17488
+ align: "end",
17489
+ sideOffset: 8,
17490
+ className: "w-[min(20rem,calc(100vw-2rem))] max-h-[min(44rem,calc(100vh-5rem))] overflow-y-auto rounded-2xl border-border/70 bg-popover p-0 shadow-lg",
17491
+ "aria-label": t("taskSummary.title"),
17492
+ children: /* @__PURE__ */ jsx57(TaskSummaryContent, { ...props })
17493
+ }
17494
+ )
17495
+ ] });
17496
+ }
17497
+ function TaskSummaryPanel({
17498
+ className,
17499
+ ...props
17500
+ }) {
17501
+ const { t } = useChatkitTranslation();
17502
+ return /* @__PURE__ */ jsx57(
17503
+ "aside",
17504
+ {
17505
+ "data-slot": "task-summary-panel",
17506
+ "aria-label": t("taskSummary.title"),
17507
+ className: cn(
17508
+ "h-fit max-h-full overflow-y-auto rounded-2xl border border-border/70 bg-popover text-popover-foreground shadow-lg",
17509
+ className
17510
+ ),
17511
+ children: /* @__PURE__ */ jsx57(TaskSummaryContent, { ...props })
17512
+ }
17513
+ );
17514
+ }
17515
+ function TaskSummaryContent({
17516
+ summary,
17517
+ historyError,
17518
+ loadingSections = {},
17519
+ loadedSectionCounts = { outputs: 0, sources: 0, agents: 0, pending: 0 },
17520
+ onRetryHistory,
17521
+ onLoadSection,
17522
+ onNavigateMessage,
17523
+ onFocusComposer,
17524
+ onOpenResource
17525
+ }) {
17526
+ const { t } = useChatkitTranslation();
17527
+ const [expanded, setExpanded] = React53.useState({});
17528
+ const hasTask = Boolean(
17529
+ summary.goal || summary.plan || summary.todos?.items.length
17530
+ );
17531
+ const toggleSection = (section) => {
17532
+ if (expanded[section]) {
17533
+ setExpanded((state) => ({ ...state, [section]: false }));
17534
+ return;
17535
+ }
17536
+ setExpanded((state) => ({ ...state, [section]: true }));
17537
+ if (loadedSectionCounts[section] === 0) {
17538
+ void onLoadSection(section);
17539
+ }
17540
+ };
17541
+ const sectionItems = (section, items) => expanded[section] ? items : items.slice(0, PREVIEW_SIZE);
17542
+ const openSummaryItem = (resource, messageId, title) => {
17543
+ if (resource?.type === "message") {
17544
+ onNavigateMessage(resource.messageId);
17545
+ return;
17546
+ }
17547
+ if (resource) {
17548
+ onOpenResource(resource, messageId, title);
17549
+ return;
17550
+ }
17551
+ if (messageId) {
17552
+ onNavigateMessage(messageId);
17553
+ }
17554
+ };
17555
+ const sectionAction = (section, total2) => {
17556
+ if (total2 <= PREVIEW_SIZE && !expanded[section]) return null;
17557
+ const loading = loadingSections[section];
17558
+ const canLoadMore = Boolean(expanded[section]) && loadedSectionCounts[section] < total2;
17559
+ return /* @__PURE__ */ jsxs39(
17560
+ "button",
17561
+ {
17562
+ type: "button",
17563
+ className: "mt-1 flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-left text-sm text-muted-foreground transition-colors hover:bg-muted/60 hover:text-foreground disabled:pointer-events-none disabled:opacity-50",
17564
+ disabled: loading,
17565
+ onClick: () => canLoadMore ? void onLoadSection(section) : toggleSection(section),
17566
+ children: [
17567
+ loading && /* @__PURE__ */ jsx57(Loader29, { className: "size-3 animate-spin" }),
17568
+ !loading && /* @__PURE__ */ jsx57(ListChecks3, { className: "size-3.5" }),
17569
+ canLoadMore ? t("taskSummary.loadMore") : expanded[section] ? t("taskSummary.collapse") : t("taskSummary.viewAll", { count: total2 })
17570
+ ]
17571
+ }
17572
+ );
17573
+ };
17574
+ return /* @__PURE__ */ jsxs39("div", { className: "divide-y divide-border/70", children: [
17575
+ Boolean(historyError) && /* @__PURE__ */ jsxs39("div", { className: "m-3 flex items-start justify-between gap-3 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: [
17576
+ /* @__PURE__ */ jsx57("span", { children: t("taskSummary.historyError") }),
17577
+ /* @__PURE__ */ jsxs39(
17578
+ "button",
17579
+ {
17580
+ type: "button",
17581
+ className: "inline-flex shrink-0 items-center gap-1 font-medium hover:underline",
17582
+ onClick: onRetryHistory,
17583
+ children: [
17584
+ /* @__PURE__ */ jsx57(RotateCcw, { className: "size-3" }),
17585
+ t("taskSummary.retry")
17586
+ ]
17587
+ }
17588
+ )
17589
+ ] }),
17590
+ /* @__PURE__ */ jsxs39(
17591
+ SummarySection,
17592
+ {
17593
+ title: t("taskSummary.sections.outputs"),
17594
+ children: [
17595
+ summary.outputs.length === 0 ? /* @__PURE__ */ jsx57(SummaryPrompt, { onClick: onFocusComposer, children: t("taskSummary.createOutput") }) : sectionItems("outputs", summary.outputs).map((item) => /* @__PURE__ */ jsx57(
17596
+ SummaryButton,
17597
+ {
17598
+ title: item.title,
17599
+ description: item.description ?? item.status,
17600
+ leading: /* @__PURE__ */ jsx57(FileOutput, { className: "size-4" }),
17601
+ trailing: item.resource && item.resource.type !== "message" ? /* @__PURE__ */ jsx57(ExternalLink, { className: "size-3.5" }) : void 0,
17602
+ onClick: () => openSummaryItem(item.resource, item.messageId, item.title)
17603
+ },
17604
+ item.id
17605
+ )),
17606
+ sectionAction("outputs", summary.totals.outputs)
17607
+ ]
17608
+ }
17609
+ ),
17610
+ /* @__PURE__ */ jsxs39(
17611
+ SummarySection,
17612
+ {
17613
+ title: t("taskSummary.sections.sources"),
17614
+ children: [
17615
+ sectionItems("sources", summary.sources).map((item) => /* @__PURE__ */ jsx57(
17616
+ SummaryButton,
17617
+ {
17618
+ title: item.title,
17619
+ description: item.description,
17620
+ leading: /* @__PURE__ */ jsx57(BookOpen3, { className: "size-4" }),
17621
+ trailing: item.resource && item.resource.type !== "message" ? /* @__PURE__ */ jsx57(ExternalLink, { className: "size-3.5" }) : void 0,
17622
+ onClick: () => openSummaryItem(item.resource, item.messageId, item.title)
17623
+ },
17624
+ item.id
17625
+ )),
17626
+ sectionAction("sources", summary.totals.sources)
17627
+ ]
17628
+ }
17629
+ ),
17630
+ hasTask && /* @__PURE__ */ jsxs39(SummarySection, { title: t("taskSummary.sections.task"), children: [
17631
+ summary.goal && /* @__PURE__ */ jsx57(
17632
+ SummaryButton,
17633
+ {
17634
+ title: summary.goal.objective,
17635
+ description: summary.goal.status,
17636
+ leading: /* @__PURE__ */ jsx57(Target2, { className: "size-4" }),
17637
+ onClick: onFocusComposer
17638
+ }
17639
+ ),
17640
+ summary.plan && /* @__PURE__ */ jsx57(
17641
+ SummaryButton,
17642
+ {
17643
+ title: summary.plan.title,
17644
+ description: summary.plan.excerpt,
17645
+ leading: /* @__PURE__ */ jsx57(ListChecks3, { className: "size-4" }),
17646
+ onClick: () => summary.plan?.messageId ? onNavigateMessage(summary.plan.messageId) : onFocusComposer()
17647
+ }
17648
+ ),
17649
+ (summary.todos?.items ?? []).slice(0, PREVIEW_SIZE).map((todo) => /* @__PURE__ */ jsx57(
17650
+ SummaryButton,
17651
+ {
17652
+ title: todo.content,
17653
+ description: t(`taskSummary.status.${todo.status}`),
17654
+ leading: todo.status === "completed" ? /* @__PURE__ */ jsx57(CheckCircle25, { className: "size-4 text-muted-foreground" }) : /* @__PURE__ */ jsx57(CircleEllipsis, { className: "size-4 text-muted-foreground" }),
17655
+ onClick: () => summary.todos?.messageId ? onNavigateMessage(summary.todos.messageId) : onFocusComposer()
17656
+ },
17657
+ todo.id
17658
+ ))
17659
+ ] }),
17660
+ summary.running.length > 0 && /* @__PURE__ */ jsx57(SummarySection, { title: t("taskSummary.sections.running"), children: summary.running.slice(0, PREVIEW_SIZE).map((item) => /* @__PURE__ */ jsx57(
17661
+ SummaryButton,
17662
+ {
17663
+ title: item.title,
17664
+ description: item.description ?? item.status,
17665
+ leading: /* @__PURE__ */ jsx57(PlayCircle, { className: "size-4" }),
17666
+ trailing: item.resource ? /* @__PURE__ */ jsx57(ExternalLink, { className: "size-3.5" }) : void 0,
17667
+ onClick: () => item.resource && onOpenResource(item.resource, void 0, item.title)
17668
+ },
17669
+ item.id
17670
+ )) }),
17671
+ summary.agents.length > 0 && /* @__PURE__ */ jsxs39(SummarySection, { title: t("taskSummary.sections.agents"), children: [
17672
+ sectionItems("agents", summary.agents).map((item) => /* @__PURE__ */ jsx57(
17673
+ SummaryButton,
17674
+ {
17675
+ title: item.title,
17676
+ description: [item.status, formatElapsed(item.elapsedTime)].filter(Boolean).join(" \xB7 "),
17677
+ leading: /* @__PURE__ */ jsx57(Bot4, { className: "size-4" }),
17678
+ onClick: () => item.messageId ? onNavigateMessage(item.messageId) : onFocusComposer()
17679
+ },
17680
+ item.id
17681
+ )),
17682
+ sectionAction("agents", summary.totals.agents)
17683
+ ] }),
17684
+ summary.pending.length > 0 && /* @__PURE__ */ jsxs39(SummarySection, { title: t("taskSummary.sections.pending"), children: [
17685
+ sectionItems("pending", summary.pending).map((item) => /* @__PURE__ */ jsx57(
17686
+ SummaryButton,
17687
+ {
17688
+ title: item.title,
17689
+ description: item.description,
17690
+ leading: /* @__PURE__ */ jsx57(CircleEllipsis, { className: "size-4" }),
17691
+ onClick: () => item.messageId ? onNavigateMessage(item.messageId) : onFocusComposer()
17692
+ },
17693
+ item.id
17694
+ )),
17695
+ sectionAction("pending", summary.totals.pending)
17696
+ ] })
17697
+ ] });
17698
+ }
17699
+ function SummarySection({
17700
+ title,
17701
+ children
17702
+ }) {
17703
+ return /* @__PURE__ */ jsxs39("section", { "aria-label": title, className: "px-4 py-3", children: [
17704
+ /* @__PURE__ */ jsx57("div", { className: "flex min-h-7 items-center justify-between gap-3", children: /* @__PURE__ */ jsx57("h3", { className: "text-sm font-medium text-muted-foreground", children: title }) }),
17705
+ /* @__PURE__ */ jsx57("div", { className: "mt-1 space-y-0.5", children })
17706
+ ] });
17707
+ }
17708
+ function SummaryPrompt({
17709
+ children,
17710
+ onClick
17711
+ }) {
17712
+ return /* @__PURE__ */ jsx57(
17713
+ "button",
17714
+ {
17715
+ type: "button",
17716
+ className: "block rounded-md py-1 text-left text-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
17717
+ onClick,
17718
+ children
17719
+ }
17720
+ );
17721
+ }
17722
+ function SummaryButton({
17723
+ title,
17724
+ description,
17725
+ leading,
17726
+ trailing,
17727
+ onClick
17728
+ }) {
17729
+ return /* @__PURE__ */ jsxs39(
17730
+ "button",
17731
+ {
17732
+ type: "button",
17733
+ disabled: !onClick,
17734
+ onClick,
17735
+ className: cn(
17736
+ "flex w-full min-w-0 items-start gap-2.5 rounded-lg px-2 py-1.5 text-left transition-colors",
17737
+ onClick && "hover:bg-muted/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
17738
+ !onClick && "cursor-default"
17739
+ ),
17740
+ children: [
17741
+ leading && /* @__PURE__ */ jsx57("span", { className: "mt-0.5 shrink-0 text-muted-foreground", children: leading }),
17742
+ /* @__PURE__ */ jsxs39("span", { className: "min-w-0 flex-1", children: [
17743
+ /* @__PURE__ */ jsx57("span", { className: "block truncate text-sm font-medium leading-5 text-foreground", children: title }),
17744
+ description && /* @__PURE__ */ jsx57("span", { className: "mt-0.5 block line-clamp-2 text-xs text-muted-foreground", children: description })
17745
+ ] }),
17746
+ trailing && /* @__PURE__ */ jsx57("span", { className: "mt-0.5 text-muted-foreground", children: trailing })
17747
+ ]
17748
+ }
17749
+ );
17750
+ }
17751
+ function formatElapsed(value) {
17752
+ if (typeof value !== "number" || !Number.isFinite(value)) return "";
17753
+ if (value < 1e3) return `${Math.round(value)}ms`;
17754
+ return `${(value / 1e3).toFixed(1)}s`;
17755
+ }
17756
+
17757
+ // src/components/chat.tsx
17758
+ import { Fragment as Fragment9, jsx as jsx58, jsxs as jsxs40 } from "react/jsx-runtime";
17759
+ var defaultApiUrl2 = import.meta.env.VITE_XPERTAI_API_URL;
17760
+ var COMPOSER_INPUT_MAX_HEIGHT = 128;
17761
+ var LONG_TEXT_REFERENCE_THRESHOLD = 5e3;
17762
+ var GOAL_RUN_INPUT = "Continue working toward the active goal.";
17763
+ var TASK_SUMMARY_PANEL_WIDTH_REM = 20;
17764
+ var TASK_SUMMARY_PANEL_EDGE_INSET_REM = 1.25;
17765
+ var TASK_SUMMARY_PANEL_SAFE_GAP_REM = 0.75;
17766
+ function isGoalAdapter(value) {
17767
+ return Boolean(value) && typeof value === "object" && typeof value.getGoal === "function" && typeof value.setGoal === "function" && typeof value.updateGoal === "function" && typeof value.clearGoal === "function";
17768
+ }
17769
+ function formatGoalElapsed(seconds) {
17770
+ if (seconds < 60) {
17771
+ return `${seconds}s`;
17772
+ }
17773
+ const minutes = Math.floor(seconds / 60);
17774
+ const remainingSeconds = seconds % 60;
17775
+ return remainingSeconds ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
17776
+ }
17777
+ async function readImageDimensions(file) {
17778
+ if (typeof window === "undefined" || typeof URL === "undefined") {
17779
+ return {};
17780
+ }
17781
+ return new Promise((resolve) => {
17782
+ const objectUrl = URL.createObjectURL(file);
17783
+ const image = new window.Image();
17784
+ const cleanup = () => {
17785
+ URL.revokeObjectURL(objectUrl);
17786
+ };
17787
+ image.onload = () => {
17788
+ resolve({
17789
+ width: image.naturalWidth || void 0,
17790
+ height: image.naturalHeight || void 0
17791
+ });
17792
+ cleanup();
17793
+ };
17794
+ image.onerror = () => {
17795
+ resolve({});
17796
+ cleanup();
16573
17797
  };
16574
17798
  image.src = objectUrl;
16575
17799
  });
@@ -16638,7 +17862,7 @@ function ReferenceChip({
16638
17862
  const metaLine = getReferenceMetaLine(reference);
16639
17863
  const isComposer = variant === "composer";
16640
17864
  const Icon = reference.type === "quote" ? Quote : reference.type === "image" ? ImageIcon : FileText5;
16641
- return /* @__PURE__ */ jsxs39(
17865
+ return /* @__PURE__ */ jsxs40(
16642
17866
  "div",
16643
17867
  {
16644
17868
  className: cn(
@@ -16647,7 +17871,7 @@ function ReferenceChip({
16647
17871
  ),
16648
17872
  title: getReferenceTitle(reference),
16649
17873
  children: [
16650
- /* @__PURE__ */ jsx57(
17874
+ /* @__PURE__ */ jsx58(
16651
17875
  Icon,
16652
17876
  {
16653
17877
  size: isComposer ? 14 : 12,
@@ -16657,8 +17881,8 @@ function ReferenceChip({
16657
17881
  )
16658
17882
  }
16659
17883
  ),
16660
- /* @__PURE__ */ jsxs39("div", { className: "min-w-0 flex-1", children: [
16661
- /* @__PURE__ */ jsx57(
17884
+ /* @__PURE__ */ jsxs40("div", { className: "min-w-0 flex-1", children: [
17885
+ /* @__PURE__ */ jsx58(
16662
17886
  "div",
16663
17887
  {
16664
17888
  className: cn(
@@ -16668,7 +17892,7 @@ function ReferenceChip({
16668
17892
  children: getReferenceLabel(reference)
16669
17893
  }
16670
17894
  ),
16671
- metaLine && /* @__PURE__ */ jsx57(
17895
+ metaLine && /* @__PURE__ */ jsx58(
16672
17896
  "div",
16673
17897
  {
16674
17898
  className: cn(
@@ -16679,7 +17903,7 @@ function ReferenceChip({
16679
17903
  }
16680
17904
  )
16681
17905
  ] }),
16682
- onRemove && removeLabel && /* @__PURE__ */ jsx57(
17906
+ onRemove && removeLabel && /* @__PURE__ */ jsx58(
16683
17907
  "button",
16684
17908
  {
16685
17909
  type: "button",
@@ -16690,7 +17914,7 @@ function ReferenceChip({
16690
17914
  ),
16691
17915
  title: removeLabel,
16692
17916
  "aria-label": removeLabel,
16693
- children: /* @__PURE__ */ jsx57(X7, { size: 12 })
17917
+ children: /* @__PURE__ */ jsx58(X7, { size: 12 })
16694
17918
  }
16695
17919
  )
16696
17920
  ]
@@ -16721,7 +17945,7 @@ function Chat({
16721
17945
  clientSecret: effectiveClientSecret
16722
17946
  });
16723
17947
  const missingConfig = Boolean(missingConfigKind);
16724
- const missingConfigShortMessage = React52.useMemo(() => {
17948
+ const missingConfigShortMessage = React54.useMemo(() => {
16725
17949
  switch (missingConfigKind) {
16726
17950
  case "apiUrl":
16727
17951
  return t("chat.missingApiUrlShort");
@@ -16733,7 +17957,7 @@ function Chat({
16733
17957
  return t("chat.missingConfigShort");
16734
17958
  }
16735
17959
  }, [missingConfigKind, t]);
16736
- const missingConfigDetailMessage = React52.useMemo(() => {
17960
+ const missingConfigDetailMessage = React54.useMemo(() => {
16737
17961
  switch (missingConfigKind) {
16738
17962
  case "apiUrl":
16739
17963
  return t("chat.missingApiUrlDetail");
@@ -16745,26 +17969,26 @@ function Chat({
16745
17969
  return t("chat.missingConfigDetail");
16746
17970
  }
16747
17971
  }, [missingConfigKind, t]);
16748
- const [isHistoryLoading, setIsHistoryLoading] = React52.useState(false);
16749
- const [historyError, setHistoryError] = React52.useState(null);
16750
- const [assistantName, setAssistantName] = React52.useState(null);
16751
- const [assistantAvatar, setAssistantAvatar] = React52.useState(null);
16752
- const [threadGoal, setThreadGoal] = React52.useState(null);
16753
- const [goalError, setGoalError] = React52.useState(null);
16754
- const [isGoalLoading, setIsGoalLoading] = React52.useState(false);
16755
- const [isGoalPanelOpen, setIsGoalPanelOpen] = React52.useState(false);
16756
- const [isGoalObjectiveExpanded, setIsGoalObjectiveExpanded] = React52.useState(false);
16757
- const [goalElapsedStartedAt, setGoalElapsedStartedAt] = React52.useState(null);
17972
+ const [isHistoryLoading, setIsHistoryLoading] = React54.useState(false);
17973
+ const [historyError, setHistoryError] = React54.useState(null);
17974
+ const [assistantName, setAssistantName] = React54.useState(null);
17975
+ const [assistantAvatar, setAssistantAvatar] = React54.useState(null);
17976
+ const [threadGoal, setThreadGoal] = React54.useState(null);
17977
+ const [goalError, setGoalError] = React54.useState(null);
17978
+ const [isGoalLoading, setIsGoalLoading] = React54.useState(false);
17979
+ const [isGoalPanelOpen, setIsGoalPanelOpen] = React54.useState(false);
17980
+ const [isGoalObjectiveExpanded, setIsGoalObjectiveExpanded] = React54.useState(false);
17981
+ const [goalElapsedStartedAt, setGoalElapsedStartedAt] = React54.useState(null);
16758
17982
  const LOADING_DOTS_MIN_DURATION = 800;
16759
17983
  const STREAMING_STATUS_REFRESH_MS = 250;
16760
- const [showLoadingDots, setShowLoadingDots] = React52.useState(false);
16761
- const [streamingNow, setStreamingNow] = React52.useState(() => Date.now());
16762
- const loadingStartTimeRef = React52.useRef(null);
16763
- const lastStreamOutputAtRef = React52.useRef(null);
16764
- React52.useEffect(() => {
17984
+ const [showLoadingDots, setShowLoadingDots] = React54.useState(false);
17985
+ const [streamingNow, setStreamingNow] = React54.useState(() => Date.now());
17986
+ const loadingStartTimeRef = React54.useRef(null);
17987
+ const lastStreamOutputAtRef = React54.useRef(null);
17988
+ React54.useEffect(() => {
16765
17989
  setStream(stream);
16766
17990
  }, [setStream, stream]);
16767
- React52.useEffect(() => {
17991
+ React54.useEffect(() => {
16768
17992
  if (stream.isLoading) {
16769
17993
  if (!loadingStartTimeRef.current) {
16770
17994
  loadingStartTimeRef.current = Date.now();
@@ -16787,7 +18011,7 @@ function Chat({
16787
18011
  }
16788
18012
  }
16789
18013
  }, [stream.isLoading]);
16790
- React52.useEffect(() => {
18014
+ React54.useEffect(() => {
16791
18015
  if (!stream.isLoading) {
16792
18016
  lastStreamOutputAtRef.current = null;
16793
18017
  setStreamingNow(Date.now());
@@ -16797,7 +18021,7 @@ function Chat({
16797
18021
  lastStreamOutputAtRef.current = now;
16798
18022
  setStreamingNow(now);
16799
18023
  }, [stream.messages, stream.isLoading]);
16800
- React52.useEffect(() => {
18024
+ React54.useEffect(() => {
16801
18025
  if (!stream.isLoading) {
16802
18026
  return;
16803
18027
  }
@@ -16806,7 +18030,7 @@ function Chat({
16806
18030
  }, STREAMING_STATUS_REFRESH_MS);
16807
18031
  return () => window.clearInterval(timer);
16808
18032
  }, [stream.isLoading]);
16809
- React52.useEffect(() => {
18033
+ React54.useEffect(() => {
16810
18034
  if (threadGoal?.status === "active" && stream.isLoading) {
16811
18035
  setGoalElapsedStartedAt(Date.now());
16812
18036
  return;
@@ -16818,54 +18042,55 @@ function Chat({
16818
18042
  threadGoal?.id,
16819
18043
  threadGoal?.status
16820
18044
  ]);
16821
- React52.useEffect(() => {
18045
+ React54.useEffect(() => {
16822
18046
  setIsGoalObjectiveExpanded(false);
16823
18047
  }, [threadGoal?.id]);
16824
- const [composerParts, setComposerParts] = React52.useState([]);
16825
- const [renderedComposerParts, setRenderedComposerParts] = React52.useState([]);
16826
- const [composerDomVersion, setComposerDomVersion] = React52.useState(0);
16827
- const [selectedTool, setSelectedTool] = React52.useState(
18048
+ const [composerParts, setComposerParts] = React54.useState([]);
18049
+ const [renderedComposerParts, setRenderedComposerParts] = React54.useState([]);
18050
+ const [composerDomVersion, setComposerDomVersion] = React54.useState(0);
18051
+ const [selectedTool, setSelectedTool] = React54.useState(
16828
18052
  null
16829
18053
  );
16830
- const [planModeEnabled, setPlanModeEnabled] = React52.useState(false);
16831
- const [petSettingsOpen, setPetSettingsOpen] = React52.useState(false);
16832
- const [petLocalSettings, setPetLocalSettings] = React52.useState(() => readPetLocalSettings());
16833
- const [attachmentState, setAttachmentState] = React52.useState({
18054
+ const [planModeEnabled, setPlanModeEnabled] = React54.useState(false);
18055
+ const [petSettingsOpen, setPetSettingsOpen] = React54.useState(false);
18056
+ const [petLocalSettings, setPetLocalSettings] = React54.useState(() => readPetLocalSettings());
18057
+ const [attachmentState, setAttachmentState] = React54.useState({
16834
18058
  uploadedFiles: [],
16835
18059
  hasUploadingFiles: false,
16836
18060
  hasParsingFiles: false
16837
18061
  });
16838
- const [references, setReferences] = React52.useState([]);
16839
- const [isUploadingReferenceImages, setIsUploadingReferenceImages] = React52.useState(false);
16840
- const [quoteSelection, setQuoteSelection] = React52.useState(null);
16841
- const [isAtBottom, setIsAtBottom] = React52.useState(true);
16842
- const [hasUpdatesBelow, setHasUpdatesBelow] = React52.useState(false);
18062
+ const [references, setReferences] = React54.useState([]);
18063
+ const [isUploadingReferenceImages, setIsUploadingReferenceImages] = React54.useState(false);
18064
+ const [quoteSelection, setQuoteSelection] = React54.useState(null);
18065
+ const [isAtBottom, setIsAtBottom] = React54.useState(true);
18066
+ const [hasUpdatesBelow, setHasUpdatesBelow] = React54.useState(false);
16843
18067
  const {
16844
18068
  threads,
16845
18069
  deleteThread,
16846
18070
  refreshThreads,
16847
18071
  isLoading: isThreadsLoading
16848
18072
  } = useThreads();
16849
- const viewportRef = React52.useRef(null);
16850
- const messageNavigationAnchorsRef = React52.useRef(
18073
+ const viewportRef = React54.useRef(null);
18074
+ const chatColumnRef = React54.useRef(null);
18075
+ const messageNavigationAnchorsRef = React54.useRef(
16851
18076
  /* @__PURE__ */ new Map()
16852
18077
  );
16853
- const attachmentsRef = React52.useRef(null);
16854
- const composerInputRef = React52.useRef(null);
16855
- const slashPaletteRef = React52.useRef(null);
16856
- const slashPaletteOptionRefs = React52.useRef(
18078
+ const attachmentsRef = React54.useRef(null);
18079
+ const composerInputRef = React54.useRef(null);
18080
+ const slashPaletteRef = React54.useRef(null);
18081
+ const slashPaletteOptionRefs = React54.useRef(
16857
18082
  []
16858
18083
  );
16859
- const composerPartsRef = React52.useRef([]);
16860
- const pendingComposerCaretOffsetRef = React52.useRef(null);
16861
- const shouldAutoScrollRef = React52.useRef(true);
16862
- const forceFollowRef = React52.useRef(false);
16863
- const previousMessageCountRef = React52.useRef(0);
16864
- const previousScrollTopRef = React52.useRef(0);
16865
- const isPrependingHistoryMessagesRef = React52.useRef(false);
16866
- const autoScrollFrameRef = React52.useRef(null);
16867
- const isPointerDownRef = React52.useRef(false);
16868
- const lastTouchYRef = React52.useRef(null);
18084
+ const composerPartsRef = React54.useRef([]);
18085
+ const pendingComposerCaretOffsetRef = React54.useRef(null);
18086
+ const shouldAutoScrollRef = React54.useRef(true);
18087
+ const forceFollowRef = React54.useRef(false);
18088
+ const previousMessageCountRef = React54.useRef(0);
18089
+ const previousScrollTopRef = React54.useRef(0);
18090
+ const isPrependingHistoryMessagesRef = React54.useRef(false);
18091
+ const autoScrollFrameRef = React54.useRef(null);
18092
+ const isPointerDownRef = React54.useRef(false);
18093
+ const lastTouchYRef = React54.useRef(null);
16869
18094
  const {
16870
18095
  runtimeCapabilities,
16871
18096
  runtimeCapabilitiesReady,
@@ -16894,24 +18119,24 @@ function Chat({
16894
18119
  const resolvedPlaceholder = placeholder ?? t("chat.placeholder");
16895
18120
  const assistantTitle = assistantName || resolvedTitle;
16896
18121
  const petRequired = options?.displayMode === "pet";
16897
- const basePetSettings = React52.useMemo(
18122
+ const basePetSettings = React54.useMemo(
16898
18123
  () => derivePetLocalSettings(options?.pet),
16899
18124
  [options?.pet]
16900
18125
  );
16901
- const displayedPetSettings = React52.useMemo(
18126
+ const displayedPetSettings = React54.useMemo(
16902
18127
  () => ({
16903
18128
  ...petLocalSettings ?? basePetSettings,
16904
18129
  ...petRequired ? { enabled: true } : {}
16905
18130
  }),
16906
18131
  [basePetSettings, petLocalSettings, petRequired]
16907
18132
  );
16908
- const effectivePet = React52.useMemo(() => {
18133
+ const effectivePet = React54.useMemo(() => {
16909
18134
  if (petRequired || petLocalSettings) {
16910
18135
  return buildPetOptionsFromLocalSettings(displayedPetSettings);
16911
18136
  }
16912
18137
  return options?.pet ?? null;
16913
18138
  }, [displayedPetSettings, options?.pet, petLocalSettings, petRequired]);
16914
- const savePetLocalSettings = React52.useCallback(
18139
+ const savePetLocalSettings = React54.useCallback(
16915
18140
  (settings) => {
16916
18141
  const nextSettings = petRequired ? { ...settings, enabled: true } : settings;
16917
18142
  setPetLocalSettings(nextSettings);
@@ -16919,7 +18144,7 @@ function Chat({
16919
18144
  },
16920
18145
  [petRequired]
16921
18146
  );
16922
- const handlePetCommand = React52.useCallback(
18147
+ const handlePetCommand = React54.useCallback(
16923
18148
  (mode) => {
16924
18149
  if (mode === "settings") {
16925
18150
  setPetSettingsOpen(true);
@@ -16941,11 +18166,11 @@ function Chat({
16941
18166
  [displayedPetSettings, effectivePet, petRequired, savePetLocalSettings]
16942
18167
  );
16943
18168
  const inputPlaceholder = selectedTool?.placeholderOverride ?? composer?.placeholder ?? resolvedPlaceholder;
16944
- const messages = React52.useMemo(
18169
+ const messages = React54.useMemo(
16945
18170
  () => stream.messages ?? [],
16946
18171
  [stream.messages]
16947
18172
  );
16948
- const messageNavigationLabels = React52.useMemo(
18173
+ const messageNavigationLabels = React54.useMemo(
16949
18174
  () => ({
16950
18175
  user: t("chat.youLabel"),
16951
18176
  assistant: assistantTitle,
@@ -16964,7 +18189,7 @@ function Chat({
16964
18189
  }),
16965
18190
  [assistantTitle, t]
16966
18191
  );
16967
- const messageNavigationItems = React52.useMemo(
18192
+ const messageNavigationItems = React54.useMemo(
16968
18193
  () => messageNavigationEnabled ? buildMessageNavigationItems(
16969
18194
  messages,
16970
18195
  {
@@ -16987,7 +18212,7 @@ function Chat({
16987
18212
  historyMessagePagination?.isLoadingMore
16988
18213
  );
16989
18214
  const canLoadMoreMessages = Boolean(historyMessagePagination?.hasMore);
16990
- const draft = React52.useMemo(
18215
+ const draft = React54.useMemo(
16991
18216
  () => getComposerPlainText(composerParts),
16992
18217
  [composerParts]
16993
18218
  );
@@ -17001,7 +18226,7 @@ function Chat({
17001
18226
  isEmpty: isComposerInputEmpty,
17002
18227
  isStacked: isComposerStacked
17003
18228
  });
17004
- const pendingFollowUps = React52.useMemo(
18229
+ const pendingFollowUps = React54.useMemo(
17005
18230
  () => sortVisiblePendingFollowUps(stream.pendingFollowUps ?? []),
17006
18231
  [stream.pendingFollowUps]
17007
18232
  );
@@ -17010,7 +18235,7 @@ function Chat({
17010
18235
  const hasPendingHITLRequest = Boolean(stream.pendingHITLRequest);
17011
18236
  const hasPendingInteractiveRequest = hasPendingRequestUserInput || hasPendingHITLRequest;
17012
18237
  const hasPendingTodos = Boolean(stream.todos?.items.length);
17013
- const goalAdapter = React52.useMemo(() => {
18238
+ const goalAdapter = React54.useMemo(() => {
17014
18239
  if (isGoalAdapter(options?.goal)) {
17015
18240
  return options.goal;
17016
18241
  }
@@ -17023,10 +18248,10 @@ function Chat({
17023
18248
  "goal"
17024
18249
  );
17025
18250
  const showGoalStatus = goalCommandAvailable && !hasCompletedGoal && (Boolean(goalError) || threadGoal?.status === "active" && stream.isLoading);
17026
- const clearQuoteSelection = React52.useCallback(() => {
18251
+ const clearQuoteSelection = React54.useCallback(() => {
17027
18252
  setQuoteSelection(null);
17028
18253
  }, []);
17029
- const commitComposerParts = React52.useCallback(
18254
+ const commitComposerParts = React54.useCallback(
17030
18255
  (nextParts, options2) => {
17031
18256
  const normalized = normalizeComposerParts(nextParts);
17032
18257
  const previous = composerPartsRef.current;
@@ -17056,7 +18281,7 @@ function Chat({
17056
18281
  },
17057
18282
  [setRunRuntimeCapabilities]
17058
18283
  );
17059
- const setComposerText = React52.useCallback(
18284
+ const setComposerText = React54.useCallback(
17060
18285
  (text, caretOffset = text.length) => {
17061
18286
  commitComposerParts(createComposerTextParts(text), {
17062
18287
  caretOffset,
@@ -17066,7 +18291,7 @@ function Chat({
17066
18291
  },
17067
18292
  [commitComposerParts]
17068
18293
  );
17069
- const focusComposerAt = React52.useCallback((position) => {
18294
+ const focusComposerAt = React54.useCallback((position) => {
17070
18295
  const nextPosition = position ?? getComposerEditingLength(composerPartsRef.current);
17071
18296
  pendingComposerCaretOffsetRef.current = nextPosition;
17072
18297
  requestAnimationFrame(() => {
@@ -17095,7 +18320,7 @@ function Chat({
17095
18320
  focusComposerAt
17096
18321
  });
17097
18322
  const parentMessenger = useParentMessenger({
17098
- onSetComposerValue: React52.useCallback(
18323
+ onSetComposerValue: React54.useCallback(
17099
18324
  (payload) => {
17100
18325
  if (!payload) {
17101
18326
  return;
@@ -17123,16 +18348,16 @@ function Chat({
17123
18348
  },
17124
18349
  [applyComposerValueRuntimeCapabilities, composer?.tools, setComposerText]
17125
18350
  ),
17126
- onSetRuntimeCapabilities: React52.useCallback(
18351
+ onSetRuntimeCapabilities: React54.useCallback(
17127
18352
  (selection) => {
17128
18353
  applyExternalRuntimeCapabilities(selection);
17129
18354
  },
17130
18355
  [applyExternalRuntimeCapabilities]
17131
18356
  ),
17132
- onFocusComposer: React52.useCallback(() => {
18357
+ onFocusComposer: React54.useCallback(() => {
17133
18358
  composerInputRef.current?.focus();
17134
18359
  }, []),
17135
- onSetPetEnabled: React52.useCallback(
18360
+ onSetPetEnabled: React54.useCallback(
17136
18361
  (enabled) => {
17137
18362
  if (petRequired) {
17138
18363
  return;
@@ -17146,10 +18371,10 @@ function Chat({
17146
18371
  )
17147
18372
  });
17148
18373
  const canMinimizeToPet = parentMessenger?.isParentAvailable === true && isPetEnabled(effectivePet);
17149
- const handleMinimizeToPet = React52.useCallback(() => {
18374
+ const handleMinimizeToPet = React54.useCallback(() => {
17150
18375
  parentMessenger?.sendEvent("chat_minimize_change", { minimized: true });
17151
18376
  }, [parentMessenger]);
17152
- const syncQuoteSelection = React52.useCallback(() => {
18377
+ const syncQuoteSelection = React54.useCallback(() => {
17153
18378
  if (typeof window === "undefined") {
17154
18379
  clearQuoteSelection();
17155
18380
  return;
@@ -17194,23 +18419,23 @@ function Chat({
17194
18419
  left
17195
18420
  });
17196
18421
  }, [clearQuoteSelection]);
17197
- const cancelPendingAutoScroll = React52.useCallback(() => {
18422
+ const cancelPendingAutoScroll = React54.useCallback(() => {
17198
18423
  if (autoScrollFrameRef.current !== null) {
17199
18424
  cancelAnimationFrame(autoScrollFrameRef.current);
17200
18425
  autoScrollFrameRef.current = null;
17201
18426
  }
17202
18427
  }, []);
17203
- const disableAutoFollow = React52.useCallback(() => {
18428
+ const disableAutoFollow = React54.useCallback(() => {
17204
18429
  forceFollowRef.current = false;
17205
18430
  shouldAutoScrollRef.current = false;
17206
18431
  cancelPendingAutoScroll();
17207
18432
  }, [cancelPendingAutoScroll]);
17208
- const enableAutoFollow = React52.useCallback(() => {
18433
+ const enableAutoFollow = React54.useCallback(() => {
17209
18434
  forceFollowRef.current = true;
17210
18435
  shouldAutoScrollRef.current = true;
17211
18436
  setHasUpdatesBelow(false);
17212
18437
  }, []);
17213
- const scrollToBottom = React52.useCallback(
18438
+ const scrollToBottom = React54.useCallback(
17214
18439
  (smooth = false, force = false) => {
17215
18440
  if (force) {
17216
18441
  enableAutoFollow();
@@ -17237,7 +18462,7 @@ function Chat({
17237
18462
  },
17238
18463
  [cancelPendingAutoScroll, enableAutoFollow]
17239
18464
  );
17240
- const setMessageNavigationAnchor = React52.useCallback(
18465
+ const setMessageNavigationAnchor = React54.useCallback(
17241
18466
  (id, node) => {
17242
18467
  if (node) {
17243
18468
  messageNavigationAnchorsRef.current.set(id, node);
@@ -17247,15 +18472,165 @@ function Chat({
17247
18472
  },
17248
18473
  []
17249
18474
  );
17250
- const getMessageNavigationAnchor = React52.useCallback(
18475
+ const getMessageNavigationAnchor = React54.useCallback(
17251
18476
  (item) => messageNavigationAnchorsRef.current.get(item.id) ?? null,
17252
18477
  []
17253
18478
  );
17254
- const handleMessageNavigationNavigate = React52.useCallback(() => {
18479
+ const handleMessageNavigationNavigate = React54.useCallback(() => {
17255
18480
  disableAutoFollow();
17256
18481
  clearQuoteSelection();
17257
18482
  }, [clearQuoteSelection, disableAutoFollow]);
17258
- React52.useEffect(() => {
18483
+ const taskSummaryEnabled = options?.taskSummary?.enabled === true;
18484
+ const taskSummaryConversationId = stream.conversationId ?? null;
18485
+ const [taskSummaryDocked, setTaskSummaryDocked] = React54.useState(false);
18486
+ const [taskSummaryOpen, setTaskSummaryOpen] = React54.useState(false);
18487
+ const manuallyClosedTaskSummaryConversationIdsRef = React54.useRef(
18488
+ /* @__PURE__ */ new Set()
18489
+ );
18490
+ const liveTaskSummaryPending = React54.useMemo(() => {
18491
+ const followUps = pendingFollowUps.map((item) => ({
18492
+ id: `follow-up:${item.id}`,
18493
+ kind: "follow_up",
18494
+ title: item.mode === "steer" ? t("taskSummary.pending.steer") : t("taskSummary.pending.followUp"),
18495
+ messageId: item.clientMessageId,
18496
+ createdAt: new Date(item.createdAt).toISOString()
18497
+ }));
18498
+ const userInput = stream.pendingRequestUserInput ? [
18499
+ {
18500
+ id: `user-input:${stream.pendingRequestUserInput.id}`,
18501
+ kind: "user_input",
18502
+ title: stream.pendingRequestUserInput.params.questions[0]?.header || t("taskSummary.pending.userInput"),
18503
+ createdAt: new Date(
18504
+ stream.pendingRequestUserInput.createdAt
18505
+ ).toISOString()
18506
+ }
18507
+ ] : [];
18508
+ const approvals = stream.pendingHITLRequest ? [
18509
+ {
18510
+ id: `approval:${stream.pendingHITLRequest.id}`,
18511
+ kind: "approval",
18512
+ title: t("taskSummary.pending.approval"),
18513
+ createdAt: new Date(
18514
+ stream.pendingHITLRequest.createdAt
18515
+ ).toISOString()
18516
+ }
18517
+ ] : [];
18518
+ return [...approvals, ...userInput, ...followUps];
18519
+ }, [
18520
+ pendingFollowUps,
18521
+ stream.pendingHITLRequest,
18522
+ stream.pendingRequestUserInput,
18523
+ t
18524
+ ]);
18525
+ const liveTaskSummaryRunning = React54.useMemo(
18526
+ () => stream.runtimeActivities.sandboxServices.services.filter(
18527
+ (service) => service.status === "starting" || service.status === "running" || service.status === "stopping"
18528
+ ).map((service) => ({
18529
+ id: service.id ?? `${service.provider}:${service.name}:${service.actualPort ?? service.requestedPort ?? ""}`,
18530
+ title: service.name,
18531
+ status: service.status,
18532
+ description: service.actualPort || service.requestedPort ? `:${service.actualPort ?? service.requestedPort}` : void 0,
18533
+ resource: {
18534
+ type: "browser",
18535
+ serviceId: service.id,
18536
+ url: service.previewUrl ?? void 0
18537
+ },
18538
+ updatedAt: service.startedAt ?? void 0
18539
+ })),
18540
+ [stream.runtimeActivities.sandboxServices.services]
18541
+ );
18542
+ const taskSummaryAgentNames = React54.useMemo(() => {
18543
+ const names = /* @__PURE__ */ new Map();
18544
+ runtimeCapabilityOptions.forEach((option) => {
18545
+ if (option.type !== "subAgent") return;
18546
+ const name = option.capability.name?.trim();
18547
+ if (!name) return;
18548
+ names.set(option.id, name);
18549
+ const agentKey = option.capability.agentKey?.trim();
18550
+ if (agentKey) names.set(agentKey, name);
18551
+ });
18552
+ return names;
18553
+ }, [runtimeCapabilityOptions]);
18554
+ const liveTaskSummary = React54.useMemo(
18555
+ () => collectLiveTaskSummary({
18556
+ messages: messages.map(
18557
+ (message) => ({
18558
+ id: message.id,
18559
+ content: message.content,
18560
+ createdAt: message.createdAt,
18561
+ updatedAt: message.updatedAt,
18562
+ taskSummary: message.taskSummary,
18563
+ references: message.references,
18564
+ attachments: message.attachments,
18565
+ fileAssets: message.fileAssets,
18566
+ agentRuns: message.agentRuns,
18567
+ runtimeCapabilities: message.runtimeCapabilities
18568
+ })
18569
+ ),
18570
+ goal: threadGoal,
18571
+ todos: stream.todos,
18572
+ pending: liveTaskSummaryPending,
18573
+ running: liveTaskSummaryRunning,
18574
+ agentNames: taskSummaryAgentNames
18575
+ }),
18576
+ [
18577
+ liveTaskSummaryPending,
18578
+ liveTaskSummaryRunning,
18579
+ messages,
18580
+ stream.todos,
18581
+ taskSummaryAgentNames,
18582
+ threadGoal
18583
+ ]
18584
+ );
18585
+ const taskSummary = useTaskSummary({
18586
+ enabled: taskSummaryEnabled,
18587
+ conversationId: taskSummaryConversationId,
18588
+ client: stream.client,
18589
+ live: liveTaskSummary
18590
+ });
18591
+ const navigateToTaskSummaryMessage = React54.useCallback(
18592
+ async (messageId) => {
18593
+ try {
18594
+ let anchor = messageNavigationAnchorsRef.current.get(messageId);
18595
+ let pageCount = 0;
18596
+ while (!anchor && pageCount < 100) {
18597
+ const loaded = await stream.loadMoreConversationMessages();
18598
+ if (!loaded.length) break;
18599
+ pageCount += 1;
18600
+ await new Promise(
18601
+ (resolve) => requestAnimationFrame(() => resolve())
18602
+ );
18603
+ anchor = messageNavigationAnchorsRef.current.get(messageId);
18604
+ }
18605
+ if (!anchor) return;
18606
+ disableAutoFollow();
18607
+ clearQuoteSelection();
18608
+ anchor.scrollIntoView({ behavior: "smooth", block: "center" });
18609
+ } catch (error) {
18610
+ console.warn("Failed to locate task summary message", error);
18611
+ }
18612
+ },
18613
+ [clearQuoteSelection, disableAutoFollow, stream]
18614
+ );
18615
+ const openTaskSummaryResource = React54.useCallback(
18616
+ (resource, messageId, resourceTitle) => {
18617
+ const data = {
18618
+ resource,
18619
+ conversationId: taskSummaryConversationId ?? void 0,
18620
+ messageId,
18621
+ title: resourceTitle
18622
+ };
18623
+ parentMessenger.sendEvent("public_event", [
18624
+ "effect",
18625
+ {
18626
+ name: CHATKIT_TASK_SUMMARY_OPEN_RESOURCE_EFFECT,
18627
+ data
18628
+ }
18629
+ ]);
18630
+ },
18631
+ [parentMessenger, taskSummaryConversationId]
18632
+ );
18633
+ React54.useEffect(() => {
17259
18634
  const viewport = viewportRef.current;
17260
18635
  if (!viewport) return;
17261
18636
  previousScrollTopRef.current = viewport.scrollTop;
@@ -17336,14 +18711,14 @@ function Chat({
17336
18711
  window.removeEventListener("pointercancel", stopPointerTracking);
17337
18712
  };
17338
18713
  }, [cancelPendingAutoScroll, disableAutoFollow]);
17339
- React52.useEffect(() => {
18714
+ React54.useEffect(() => {
17340
18715
  shouldAutoScrollRef.current = true;
17341
18716
  forceFollowRef.current = false;
17342
18717
  previousScrollTopRef.current = 0;
17343
18718
  setIsAtBottom(true);
17344
18719
  setHasUpdatesBelow(false);
17345
18720
  }, [stream.threadId]);
17346
- React52.useEffect(() => {
18721
+ React54.useEffect(() => {
17347
18722
  const messageCountChanged = messages.length !== previousMessageCountRef.current;
17348
18723
  previousMessageCountRef.current = messages.length;
17349
18724
  if (isPrependingHistoryMessagesRef.current) {
@@ -17365,7 +18740,7 @@ function Chat({
17365
18740
  const isSubmissionBlocked = hasPendingInteractiveRequest || missingConfig || isHistoryLoading || hasUploadingFiles || isUploadingReferenceImages;
17366
18741
  const isSendDisabled = !trimmedDraft && !hasReferences || isSubmissionBlocked;
17367
18742
  const isPromptEditDisabled = hasPendingInteractiveRequest || missingConfig || isHistoryLoading;
17368
- const resizeComposerInput = React52.useCallback(() => {
18743
+ const resizeComposerInput = React54.useCallback(() => {
17369
18744
  const input = composerInputRef.current;
17370
18745
  if (!input) {
17371
18746
  return;
@@ -17373,7 +18748,7 @@ function Chat({
17373
18748
  input.style.maxHeight = `${COMPOSER_INPUT_MAX_HEIGHT}px`;
17374
18749
  input.style.overflowY = input.scrollHeight > COMPOSER_INPUT_MAX_HEIGHT ? "auto" : "hidden";
17375
18750
  }, []);
17376
- React52.useLayoutEffect(() => {
18751
+ React54.useLayoutEffect(() => {
17377
18752
  composerPartsRef.current = composerParts;
17378
18753
  resizeComposerInput();
17379
18754
  const caretOffset = pendingComposerCaretOffsetRef.current;
@@ -17385,13 +18760,13 @@ function Chat({
17385
18760
  }
17386
18761
  }
17387
18762
  }, [composerDomVersion, composerParts, resizeComposerInput]);
17388
- React52.useEffect(() => {
18763
+ React54.useEffect(() => {
17389
18764
  document.addEventListener("selectionchange", syncQuoteSelection);
17390
18765
  return () => {
17391
18766
  document.removeEventListener("selectionchange", syncQuoteSelection);
17392
18767
  };
17393
18768
  }, [syncQuoteSelection]);
17394
- React52.useEffect(() => {
18769
+ React54.useEffect(() => {
17395
18770
  const viewport = viewportRef.current;
17396
18771
  if (!viewport) {
17397
18772
  return;
@@ -17408,14 +18783,14 @@ function Chat({
17408
18783
  window.removeEventListener("resize", handleViewportScroll);
17409
18784
  };
17410
18785
  }, [clearQuoteSelection]);
17411
- React52.useEffect(() => {
18786
+ React54.useEffect(() => {
17412
18787
  clearQuoteSelection();
17413
18788
  }, [messages.length, stream.threadId, clearQuoteSelection]);
17414
- React52.useEffect(() => {
18789
+ React54.useEffect(() => {
17415
18790
  if (missingConfig) return;
17416
18791
  void refreshThreads();
17417
18792
  }, [missingConfig, refreshThreads]);
17418
- React52.useEffect(() => {
18793
+ React54.useEffect(() => {
17419
18794
  if (missingConfig || !stream.client || !stream.assistantId) {
17420
18795
  setAssistantName(null);
17421
18796
  setAssistantAvatar(null);
@@ -17438,10 +18813,10 @@ function Chat({
17438
18813
  cancelled = true;
17439
18814
  };
17440
18815
  }, [missingConfig, stream.client, stream.assistantId]);
17441
- React52.useEffect(() => {
18816
+ React54.useEffect(() => {
17442
18817
  setThreadGoal(stream.threadGoal);
17443
18818
  }, [stream.threadGoal]);
17444
- React52.useEffect(() => {
18819
+ React54.useEffect(() => {
17445
18820
  const threadId = stream.threadId?.trim();
17446
18821
  if (!threadId || !goalCommandAvailable) {
17447
18822
  setThreadGoal(null);
@@ -17482,7 +18857,7 @@ function Chat({
17482
18857
  return () => controller.abort();
17483
18858
  }, [goalAdapter, goalCommandAvailable, stream.threadId]);
17484
18859
  const uploadedFiles = attachmentState.uploadedFiles;
17485
- const syncComposerInputFromElement = React52.useCallback(
18860
+ const syncComposerInputFromElement = React54.useCallback(
17486
18861
  (input) => {
17487
18862
  const previousCapabilities = getComposerCapabilityPartMap(
17488
18863
  composerPartsRef.current
@@ -17500,25 +18875,25 @@ function Chat({
17500
18875
  },
17501
18876
  [commitComposerParts, updateRuntimeCapabilityPalette]
17502
18877
  );
17503
- const handleComposerInput = React52.useCallback(
18878
+ const handleComposerInput = React54.useCallback(
17504
18879
  (event) => {
17505
18880
  syncComposerInputFromElement(event.currentTarget);
17506
18881
  },
17507
18882
  [syncComposerInputFromElement]
17508
18883
  );
17509
- const handleComposerCompositionEnd = React52.useCallback(
18884
+ const handleComposerCompositionEnd = React54.useCallback(
17510
18885
  (event) => {
17511
18886
  syncComposerInputFromElement(event.currentTarget);
17512
18887
  },
17513
18888
  [syncComposerInputFromElement]
17514
18889
  );
17515
- const handleComposerSelect = React52.useCallback(() => {
18890
+ const handleComposerSelect = React54.useCallback(() => {
17516
18891
  updateRuntimeCapabilityPalette(
17517
18892
  composerPartsRef.current,
17518
18893
  composerInputRef.current ? getComposerSelectionOffset(composerInputRef.current) : void 0
17519
18894
  );
17520
18895
  }, [updateRuntimeCapabilityPalette]);
17521
- const submitDraft = React52.useCallback(
18896
+ const submitDraft = React54.useCallback(
17522
18897
  (submitOptions = {}) => {
17523
18898
  if (isSubmissionBlocked) return;
17524
18899
  const contentToSubmit = (submitOptions.inputText ?? trimmedDraft).trim();
@@ -17624,7 +18999,7 @@ function Chat({
17624
18999
  t
17625
19000
  ]
17626
19001
  );
17627
- const handleGoalCommand = React52.useCallback(
19002
+ const handleGoalCommand = React54.useCallback(
17628
19003
  async ({
17629
19004
  args,
17630
19005
  commandSource,
@@ -17730,7 +19105,7 @@ function Chat({
17730
19105
  t
17731
19106
  ]
17732
19107
  );
17733
- const handleGoalPanelOpenChange = React52.useCallback((open) => {
19108
+ const handleGoalPanelOpenChange = React54.useCallback((open) => {
17734
19109
  setIsGoalPanelOpen(open);
17735
19110
  }, []);
17736
19111
  const {
@@ -17774,7 +19149,7 @@ function Chat({
17774
19149
  plugin: t("composer.slashCommands.empty.loadingCapabilities"),
17775
19150
  subAgent: t("composer.slashCommands.empty.loadingCapabilities")
17776
19151
  };
17777
- React52.useEffect(() => {
19152
+ React54.useEffect(() => {
17778
19153
  if (!runtimeCapabilityPalette) {
17779
19154
  return;
17780
19155
  }
@@ -17793,7 +19168,7 @@ function Chat({
17793
19168
  );
17794
19169
  }
17795
19170
  }, [slashPaletteOptions.length, runtimeCapabilityPalette]);
17796
- React52.useLayoutEffect(() => {
19171
+ React54.useLayoutEffect(() => {
17797
19172
  if (!runtimeCapabilityPalette) {
17798
19173
  return;
17799
19174
  }
@@ -17810,7 +19185,7 @@ function Chat({
17810
19185
  container.scrollTop += optionRect.bottom - containerRect.bottom;
17811
19186
  }
17812
19187
  }, [runtimeCapabilityPalette, slashPaletteOptions.length]);
17813
- const submitGoalModeDraft = React52.useCallback(() => {
19188
+ const submitGoalModeDraft = React54.useCallback(() => {
17814
19189
  const objective = getComposerPlainText(composerPartsRef.current).trim();
17815
19190
  if (!isGoalModeOpen || !goalCommandAvailable || !objective) {
17816
19191
  return false;
@@ -17848,7 +19223,7 @@ function Chat({
17848
19223
  }
17849
19224
  submitDraft();
17850
19225
  };
17851
- const handleEditPendingFollowUp = React52.useCallback(
19226
+ const handleEditPendingFollowUp = React54.useCallback(
17852
19227
  (id) => {
17853
19228
  const item = pendingFollowUps.find(
17854
19229
  (entry) => entry.id === id && entry.mode === "queue"
@@ -17875,7 +19250,7 @@ function Chat({
17875
19250
  },
17876
19251
  [pendingFollowUps, setComposerText, stream]
17877
19252
  );
17878
- const handleQuoteSelection = React52.useCallback(() => {
19253
+ const handleQuoteSelection = React54.useCallback(() => {
17879
19254
  if (!quoteSelection) {
17880
19255
  return;
17881
19256
  }
@@ -17891,7 +19266,7 @@ function Chat({
17891
19266
  const handleAttachmentClick = () => {
17892
19267
  attachmentsRef.current?.openFilePicker();
17893
19268
  };
17894
- const uploadContextFile = React52.useCallback(
19269
+ const uploadContextFile = React54.useCallback(
17895
19270
  (file) => {
17896
19271
  const formData = new FormData();
17897
19272
  formData.append("file", file, file.name || "upload");
@@ -17910,13 +19285,13 @@ function Chat({
17910
19285
  },
17911
19286
  [stream.assistantId, stream.client, stream.threadId]
17912
19287
  );
17913
- const getContextFileStatus = React52.useCallback(
19288
+ const getContextFileStatus = React54.useCallback(
17914
19289
  (fileId) => stream.client.contexts.fetch(`/files/${fileId}/status`, {
17915
19290
  method: "GET"
17916
19291
  }),
17917
19292
  [stream.client]
17918
19293
  );
17919
- const deleteContextFile = React52.useCallback(
19294
+ const deleteContextFile = React54.useCallback(
17920
19295
  (storageFileId) => stream.client.contexts.deleteFile(storageFileId),
17921
19296
  [stream.client]
17922
19297
  );
@@ -18024,7 +19399,7 @@ function Chat({
18024
19399
  }
18025
19400
  submitDraft();
18026
19401
  };
18027
- const handleComposerPaste = React52.useCallback(
19402
+ const handleComposerPaste = React54.useCallback(
18028
19403
  (event) => {
18029
19404
  const clipboardData = event.clipboardData;
18030
19405
  if (!clipboardData) {
@@ -18126,13 +19501,13 @@ function Chat({
18126
19501
  const handleToolSelect = (tool) => {
18127
19502
  setSelectedTool((prev) => prev?.id === tool.id ? null : tool);
18128
19503
  };
18129
- const handlePromptClick = React52.useCallback(
19504
+ const handlePromptClick = React54.useCallback(
18130
19505
  (prompt) => {
18131
19506
  submitDraft({ inputText: prompt, displayText: prompt });
18132
19507
  },
18133
19508
  [submitDraft]
18134
19509
  );
18135
- const handlePromptEdit = React52.useCallback(
19510
+ const handlePromptEdit = React54.useCallback(
18136
19511
  (prompt) => {
18137
19512
  if (isPromptEditDisabled) return;
18138
19513
  setComposerText(prompt, prompt.length);
@@ -18141,7 +19516,7 @@ function Chat({
18141
19516
  },
18142
19517
  [focusComposerAt, isPromptEditDisabled, setComposerText]
18143
19518
  );
18144
- const loadConversationMessages = React52.useCallback(
19519
+ const loadConversationMessages = React54.useCallback(
18145
19520
  async (recordId) => {
18146
19521
  if (missingConfig) {
18147
19522
  setHistoryError(missingConfigShortMessage);
@@ -18162,7 +19537,7 @@ function Chat({
18162
19537
  },
18163
19538
  [missingConfig, missingConfigShortMessage, stream, t]
18164
19539
  );
18165
- const handleLoadMoreMessages = React52.useCallback(async () => {
19540
+ const handleLoadMoreMessages = React54.useCallback(async () => {
18166
19541
  if (!canLoadMoreMessages || isLoadingMoreMessages) {
18167
19542
  return;
18168
19543
  }
@@ -18271,19 +19646,19 @@ function Chat({
18271
19646
  };
18272
19647
  const acceptMimes = composer?.attachments?.accept ? Object.entries(composer.attachments.accept).map(([mime, exts]) => [mime, ...exts.map((e) => `.${e}`)].join(",")).join(",") : void 0;
18273
19648
  const canUploadDroppedFiles = composer?.attachments?.enabled === true && !missingConfig && !isHistoryLoading && !hasPendingInteractiveRequest;
18274
- const handleDroppedFiles = React52.useCallback((files) => {
19649
+ const handleDroppedFiles = React54.useCallback((files) => {
18275
19650
  return attachmentsRef.current?.queueFiles(files) ?? false;
18276
19651
  }, []);
18277
- const currentThread = React52.useMemo(
19652
+ const currentThread = React54.useMemo(
18278
19653
  () => threads.find((item) => item.id === stream.threadId),
18279
19654
  [threads, stream.threadId]
18280
19655
  );
18281
- const assistantStatusText = React52.useMemo(() => {
19656
+ const assistantStatusText = React54.useMemo(() => {
18282
19657
  if (!stream.threadId) return t("chat.statusOnline");
18283
19658
  return currentThread?.title?.trim() || t("chat.statusOnline");
18284
19659
  }, [currentThread?.title, stream.threadId, t]);
18285
19660
  const streamErrorMessage = stream.error instanceof Error ? stream.error.message : void 0;
18286
- const threadErrorMessage = React52.useMemo(() => {
19661
+ const threadErrorMessage = React54.useMemo(() => {
18287
19662
  if (streamErrorMessage?.trim()) return streamErrorMessage.trim();
18288
19663
  if (currentThread?.status !== "error") return void 0;
18289
19664
  const message = currentThread.error?.trim();
@@ -18314,777 +19689,883 @@ function Chat({
18314
19689
  fallbackTitle: t("history.threadFallback")
18315
19690
  });
18316
19691
  const layoutMaxWidth = options?.layout?.maxWidth;
18317
- const chatColumnStyle = React52.useMemo(() => {
19692
+ const chatColumnStyle = React54.useMemo(() => {
18318
19693
  if (layoutMaxWidth === void 0 || layoutMaxWidth === null || layoutMaxWidth === "") {
18319
19694
  return void 0;
18320
19695
  }
18321
19696
  return { maxWidth: layoutMaxWidth };
18322
19697
  }, [layoutMaxWidth]);
18323
- return /* @__PURE__ */ jsxs39(
18324
- UploadDroppedFiles,
18325
- {
18326
- ref: viewportRef,
18327
- "data-chatkit-root": "",
18328
- enabled: canUploadDroppedFiles,
18329
- dropTitle: t("chat.dropFilesTitle"),
18330
- dropHint: t("chat.dropFilesHint"),
18331
- activeClassName: "ring-2 ring-primary/40 ring-inset",
18332
- onFiles: handleDroppedFiles,
18333
- className: cn(
18334
- "relative flex h-full w-full flex-col flex-1 overflow-y-auto bg-background shadow-sm transition-[box-shadow] duration-150",
18335
- className
18336
- ),
18337
- children: [
18338
- /* @__PURE__ */ jsxs39(
18339
- "div",
18340
- {
18341
- "data-slot": "chatkit-chat-header",
18342
- className: "mx-auto flex w-full items-center justify-between border-b p-2 sticky top-0 z-10 bg-background",
18343
- style: chatColumnStyle,
18344
- children: [
18345
- /* @__PURE__ */ jsxs39("div", { className: "flex min-w-0 items-center gap-3 overflow-hidden", children: [
18346
- /* @__PURE__ */ jsxs39("div", { className: "relative shrink-0", children: [
18347
- /* @__PURE__ */ jsx57(
18348
- ChatkitAvatar,
18349
- {
18350
- avatar: assistantAvatar,
18351
- className: "h-9 w-9 border border-border/60",
18352
- label: assistantTitle
18353
- }
18354
- ),
18355
- /* @__PURE__ */ jsx57("span", { className: "absolute bottom-0 right-0 h-2.5 w-2.5 rounded-full border-2 border-background bg-green-500" })
18356
- ] }),
18357
- /* @__PURE__ */ jsxs39("div", { className: "min-w-0", children: [
18358
- /* @__PURE__ */ jsx57(
18359
- "h2",
18360
- {
18361
- className: "text-lg font-semibold truncate",
18362
- title: assistantTitle,
18363
- children: assistantTitle
18364
- }
18365
- ),
18366
- /* @__PURE__ */ jsx57(
18367
- "p",
18368
- {
18369
- className: "truncate text-xs text-muted-foreground",
18370
- title: assistantStatusText,
18371
- children: assistantStatusText
18372
- }
18373
- )
18374
- ] })
18375
- ] }),
18376
- /* @__PURE__ */ jsxs39("div", { className: "flex items-center gap-1", children: [
18377
- canMinimizeToPet && /* @__PURE__ */ jsxs39(Tooltip, { children: [
18378
- /* @__PURE__ */ jsx57(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx57("span", { className: "inline-flex h-8 w-8", children: /* @__PURE__ */ jsx57(
18379
- "button",
18380
- {
18381
- type: "button",
18382
- onClick: handleMinimizeToPet,
18383
- className: cn(
18384
- "flex h-8 w-8 cursor-pointer items-center justify-center rounded-md",
18385
- "text-muted-foreground hover:text-foreground hover:bg-muted",
18386
- "transition-colors duration-150"
18387
- ),
18388
- "aria-label": t("chat.minimizeToPet"),
18389
- children: /* @__PURE__ */ jsx57(Minus, { size: 16 })
18390
- }
18391
- ) }) }),
18392
- /* @__PURE__ */ jsx57(TooltipContent, { side: "bottom", children: t("chat.minimizeToPet") })
18393
- ] }),
18394
- /* @__PURE__ */ jsxs39(Tooltip, { children: [
18395
- /* @__PURE__ */ jsx57(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx57("span", { className: "inline-flex h-8 w-8", children: /* @__PURE__ */ jsx57(
18396
- "button",
18397
- {
18398
- type: "button",
18399
- onClick: () => setPetSettingsOpen(true),
18400
- className: cn(
18401
- "flex h-8 w-8 cursor-pointer items-center justify-center rounded-md",
18402
- "text-muted-foreground hover:text-foreground hover:bg-muted",
18403
- "transition-colors duration-150"
18404
- ),
18405
- "aria-label": t("settings.open"),
18406
- children: /* @__PURE__ */ jsx57(Settings2, { size: 16 })
18407
- }
18408
- ) }) }),
18409
- /* @__PURE__ */ jsx57(TooltipContent, { side: "bottom", children: t("settings.open") })
18410
- ] }),
18411
- history?.enabled !== false && /* @__PURE__ */ jsxs39(Fragment9, { children: [
18412
- /* @__PURE__ */ jsxs39(Tooltip, { children: [
18413
- /* @__PURE__ */ jsx57(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx57("span", { className: "inline-flex h-8 w-8", children: /* @__PURE__ */ jsx57(
18414
- "button",
18415
- {
18416
- type: "button",
18417
- onClick: handleNewThread,
18418
- disabled: missingConfig || isHistoryLoading,
18419
- className: cn(
18420
- "flex h-8 w-8 cursor-pointer items-center justify-center rounded-md",
18421
- "text-muted-foreground hover:text-foreground hover:bg-muted",
18422
- "transition-colors duration-150",
18423
- "disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed"
18424
- ),
18425
- "aria-label": t("history.newThread"),
18426
- children: /* @__PURE__ */ jsx57(Pencil4, { size: 16 })
18427
- }
18428
- ) }) }),
18429
- /* @__PURE__ */ jsx57(TooltipContent, { side: "bottom", children: t("history.newThread") })
18430
- ] }),
18431
- /* @__PURE__ */ jsx57(
18432
- HistorySidebar,
18433
- {
18434
- threads,
18435
- currentThreadId: stream.threadId ?? void 0,
18436
- onNewThread: handleNewThread,
18437
- onSelectThread: handleSelectThread,
18438
- onDeleteThread: handleDeleteThread,
18439
- showDelete: history?.showDelete !== false,
18440
- disabled: missingConfig || isThreadsLoading || isHistoryLoading
18441
- }
18442
- )
18443
- ] })
18444
- ] })
18445
- ]
18446
- }
18447
- ),
18448
- showMessageNavigation && /* @__PURE__ */ jsx57(
18449
- MessageNavigator,
18450
- {
18451
- items: messageNavigationItems,
18452
- viewportRef,
18453
- getAnchor: getMessageNavigationAnchor,
18454
- onNavigate: handleMessageNavigationNavigate,
18455
- label: t("message.navigation.label"),
18456
- tagsOverflowLabel: (count) => t("message.navigation.moreTags", { count })
18457
- }
18458
- ),
18459
- /* @__PURE__ */ jsxs39(
18460
- "div",
18461
- {
18462
- "data-slot": "chatkit-chat-content",
18463
- className: "mx-auto w-full flex-1 p-4",
18464
- style: chatColumnStyle,
18465
- children: [
18466
- errorMessage && /* @__PURE__ */ jsx57("div", { className: "mb-4 rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: errorMessage }),
18467
- historyError && /* @__PURE__ */ jsx57("div", { className: "mb-4 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900", children: historyError }),
18468
- showMissingConfig && /* @__PURE__ */ jsx57("div", { className: "mb-4 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900", children: missingConfigDetailMessage }),
18469
- isHistoryLoading && /* @__PURE__ */ jsx57("div", { className: "mb-4 rounded-lg border border-muted px-3 py-2 text-sm text-muted-foreground", children: t("chat.loadingThread") }),
18470
- messages.length === 0 && !canLoadMoreMessages ? /* @__PURE__ */ jsx57(
18471
- StartScreen,
18472
- {
18473
- startScreen,
18474
- onPromptClick: handlePromptClick,
18475
- onPromptEdit: handlePromptEdit,
18476
- promptSendDisabled: isSubmissionBlocked,
18477
- promptEditDisabled: isPromptEditDisabled
18478
- }
18479
- ) : /* @__PURE__ */ jsxs39("div", { className: "space-y-4", children: [
18480
- canLoadMoreMessages && /* @__PURE__ */ jsxs39("div", { className: "flex items-center gap-3 py-1", children: [
18481
- /* @__PURE__ */ jsx57("div", { className: "h-px min-w-8 flex-1 bg-border" }),
18482
- /* @__PURE__ */ jsx57(
18483
- Button,
18484
- {
18485
- type: "button",
18486
- variant: "ghost",
18487
- size: "sm",
18488
- onClick: handleLoadMoreMessages,
18489
- disabled: isLoadingMoreMessages,
18490
- className: "h-7 px-2 text-xs font-medium text-muted-foreground hover:text-foreground",
18491
- children: isLoadingMoreMessages ? t("chat.loadingMoreMessages") : t("chat.loadMoreMessages")
18492
- }
18493
- ),
18494
- /* @__PURE__ */ jsx57("div", { className: "h-px min-w-8 flex-1 bg-border" })
18495
- ] }),
18496
- messages.map((message, index) => {
18497
- const messageType = String(message.type);
18498
- const isAssistantMessage = messageType === "assistant" || messageType === "ai";
18499
- const isStreamingMessage = stream.isLoading && index === messages.length - 1;
18500
- const streamingStatus = isAssistantMessage ? getAssistantStreamingStatus(
18501
- {
18502
- ...message,
18503
- lastStreamOutputAt: lastStreamOutputAtRef.current
18504
- },
18505
- isStreamingMessage,
18506
- { now: streamingNow }
18507
- ) : null;
18508
- if (isAssistantMessage && !hasRenderableAssistantMessage(message) && !streamingStatus) {
18509
- return null;
18510
- }
18511
- const messageContent = typeof message.content === "string" ? message.content : Array.isArray(message.content) ? message.content.map((part) => formatMessageContent(part)).join("") : formatMessageContent(message.content);
18512
- const hasPlainRenderableContent = messageContent.trim().length > 0;
18513
- const humanMessage = message;
18514
- const humanReferences = humanMessage.references ?? [];
18515
- const humanAttachments = [
18516
- ...humanMessage.fileAssets ?? [],
18517
- ...humanMessage.attachments ?? []
18518
- ];
18519
- const humanRuntimeCapabilityOptions = message.type === "human" ? humanMessage.runtimeCapabilityOptions ?? getRuntimeCapabilityOptionsForSelection(
18520
- getRecommendedRuntimeCapabilitiesSelection(
18521
- humanMessage.runtimeCapabilities
18522
- ),
18523
- runtimeCapabilityOptions
18524
- ) : [];
18525
- const hasHumanAttachments = message.type === "human" && humanAttachments.length > 0;
18526
- const canQuoteMessage = message.type === "human" || isAssistantMessage;
18527
- const quoteSource = message.type === "human" ? t("chat.youLabel") : assistantTitle;
18528
- const messageNavigationId = getMessageNavigationItemId(
18529
- message,
18530
- index
18531
- );
18532
- if (!isAssistantMessage && !hasPlainRenderableContent && !hasHumanAttachments && humanRuntimeCapabilityOptions.length === 0 && humanReferences.length === 0) {
18533
- return null;
18534
- }
18535
- return /* @__PURE__ */ jsx57(
18536
- "div",
18537
- {
18538
- ref: (node) => setMessageNavigationAnchor(messageNavigationId, node),
18539
- "data-message-navigation-id": messageNavigationId,
18540
- className: cn(
18541
- "group flex gap-3",
18542
- message.type === "human" ? "justify-end" : "justify-start -ml-1"
18543
- // AI messages: slightly closer to left
18544
- ),
18545
- children: /* @__PURE__ */ jsxs39(
18546
- "div",
18547
- {
18548
- className: cn(
18549
- "flex flex-col px-3 overflow-hidden",
18550
- isAssistantMessage && "min-w-0 flex-1"
18551
- ),
18552
- children: [
18553
- /* @__PURE__ */ jsx57(
18554
- "div",
18555
- {
18556
- ...canQuoteMessage ? {
18557
- "data-quote-message-id": message.id,
18558
- "data-quote-source": quoteSource
18559
- } : {},
18560
- className: cn(
18561
- "max-w-full rounded-2xl",
18562
- 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"
18563
- // AI messages: use chat-specific foreground color
18564
- ),
18565
- children: isAssistantMessage ? /* @__PURE__ */ jsx57(
18566
- AssistantMessage,
18567
- {
18568
- message: {
18569
- ...message,
18570
- type: "assistant"
18571
- },
18572
- messages: messages.slice(0, index + 1).map(
18573
- (item) => ({
18574
- ...item,
18575
- type: String(item.type) === "ai" ? "assistant" : item.type
18576
- })
18577
- ),
18578
- isStreaming: isStreamingMessage,
18579
- streamingStatus,
18580
- isThreadRunning: currentThreadIsRunning,
18581
- organizationId: stream.organizationId,
18582
- apiUrl: stream.apiUrl,
18583
- pet: effectivePet
18584
- }
18585
- ) : /* @__PURE__ */ jsxs39(Fragment9, { children: [
18586
- message.type === "human" && humanRuntimeCapabilityOptions.length > 0 && /* @__PURE__ */ jsx57(
18587
- HumanRuntimeCapabilityChips,
18588
- {
18589
- options: humanRuntimeCapabilityOptions
18590
- }
18591
- ),
18592
- message.type === "human" && humanReferences.length > 0 && /* @__PURE__ */ jsx57("div", { className: "mb-2 flex flex-wrap gap-1.5", children: humanReferences.map((reference) => /* @__PURE__ */ jsx57(
18593
- ReferenceChip,
18594
- {
18595
- reference,
18596
- variant: "message"
18597
- },
18598
- getReferenceKey(reference)
18599
- )) }),
18600
- message.type === "human" && humanAttachments.length > 0 && /* @__PURE__ */ jsx57("div", { className: "flex flex-wrap gap-1.5 mb-2", children: humanAttachments.map((file, fileIndex) => /* @__PURE__ */ jsxs39(
18601
- "div",
18602
- {
18603
- className: "flex items-center gap-1.5 rounded-md bg-primary-foreground/20 px-2 py-1 text-xs",
18604
- children: [
18605
- /* @__PURE__ */ jsx57(FileText5, { size: 12 }),
18606
- /* @__PURE__ */ jsx57("span", { className: "max-w-[100px] truncate", children: file.originalName ?? file.id })
18607
- ]
18608
- },
18609
- fileIndex
18610
- )) }),
18611
- Array.isArray(message.content) ? message.content.map((part, partIndex) => /* @__PURE__ */ jsx57(
18612
- "p",
18613
- {
18614
- className: "wrap-break-word text-sm leading-relaxed",
18615
- children: formatMessageContent(part)
18616
- },
18617
- `${part.type}-${partIndex}`
18618
- )) : /* @__PURE__ */ jsx57("span", { className: "wrap-break-word text-sm leading-relaxed", children: formatMessageContent(message.content) })
18619
- ] })
18620
- }
18621
- ),
18622
- /* @__PURE__ */ jsx57(
18623
- MessageActions,
18624
- {
18625
- content: messageContent,
18626
- isAssistant: isAssistantMessage,
18627
- isStreaming: isStreamingMessage,
18628
- onRetry: isAssistantMessage && !stream.isLoading && index === messages.length - 1 ? () => handleRetry(index) : void 0
18629
- }
18630
- )
18631
- ]
18632
- }
18633
- )
18634
- },
18635
- message.id ?? `${message.type}-${index}`
18636
- );
18637
- }),
18638
- showLoadingDots && (() => {
18639
- const lastMessage = messages[messages.length - 1];
18640
- const lastMessageType = lastMessage ? String(lastMessage.type) : "";
18641
- const isLastMessageFromAI = lastMessageType === "ai" || lastMessageType === "assistant";
18642
- const lastAssistantStatus = isLastMessageFromAI ? getAssistantStreamingStatus(
18643
- {
18644
- ...lastMessage,
18645
- lastStreamOutputAt: lastStreamOutputAtRef.current
18646
- },
18647
- stream.isLoading,
18648
- { now: streamingNow }
18649
- ) : null;
18650
- if (lastAssistantStatus) return null;
18651
- const fallbackStreamingStatus = getAssistantStreamingStatus(
18652
- {
18653
- status: void 0,
18654
- reasoning: void 0,
18655
- lastStreamOutputAt: lastStreamOutputAtRef.current
18656
- },
18657
- stream.isLoading,
18658
- { now: streamingNow }
18659
- );
18660
- return /* @__PURE__ */ jsx57("div", { className: "flex justify-start gap-3 -ml-2", children: /* @__PURE__ */ jsx57("div", { className: "max-w-full rounded-2xl py-2.5", children: /* @__PURE__ */ jsx57(
18661
- AssistantStreamingIndicator,
18662
- {
18663
- status: fallbackStreamingStatus ?? "loading"
18664
- }
18665
- ) }) });
18666
- })()
18667
- ] })
18668
- ]
18669
- }
18670
- ),
18671
- !isAtBottom && messages.length > 0 && /* @__PURE__ */ jsx57("div", { className: "sticky bottom-20 z-20 flex justify-center px-4 pointer-events-none", children: /* @__PURE__ */ jsx57(
18672
- Button,
19698
+ React54.useLayoutEffect(() => {
19699
+ if (!taskSummaryEnabled) {
19700
+ setTaskSummaryDocked(false);
19701
+ return;
19702
+ }
19703
+ const viewport = viewportRef.current;
19704
+ const chatColumn = chatColumnRef.current;
19705
+ if (!viewport || !chatColumn) {
19706
+ setTaskSummaryDocked(false);
19707
+ return;
19708
+ }
19709
+ const updateDockedState = () => {
19710
+ const viewportRect = viewport.getBoundingClientRect();
19711
+ const chatColumnRect = chatColumn.getBoundingClientRect();
19712
+ const rootFontSize = Number.parseFloat(
19713
+ window.getComputedStyle(document.documentElement).fontSize
19714
+ );
19715
+ const remInPixels = Number.isFinite(rootFontSize) ? rootFontSize : 16;
19716
+ const requiredSideSpace = (TASK_SUMMARY_PANEL_WIDTH_REM + TASK_SUMMARY_PANEL_EDGE_INSET_REM + TASK_SUMMARY_PANEL_SAFE_GAP_REM) * remInPixels;
19717
+ const availableSideSpace = viewportRect.right - chatColumnRect.right;
19718
+ setTaskSummaryDocked(availableSideSpace >= requiredSideSpace);
19719
+ };
19720
+ updateDockedState();
19721
+ window.addEventListener("resize", updateDockedState);
19722
+ const resizeObserver = typeof ResizeObserver === "function" ? new ResizeObserver(updateDockedState) : null;
19723
+ resizeObserver?.observe(viewport);
19724
+ resizeObserver?.observe(chatColumn);
19725
+ return () => {
19726
+ window.removeEventListener("resize", updateDockedState);
19727
+ resizeObserver?.disconnect();
19728
+ };
19729
+ }, [layoutMaxWidth, taskSummaryEnabled]);
19730
+ const taskSummaryAvailable = Boolean(
19731
+ taskSummaryEnabled && stream.threadId && taskSummaryConversationId
19732
+ );
19733
+ const handleTaskSummaryOpenChange = React54.useCallback(
19734
+ (open) => {
19735
+ setTaskSummaryOpen(open);
19736
+ if (!taskSummaryConversationId) return;
19737
+ if (open) {
19738
+ manuallyClosedTaskSummaryConversationIdsRef.current.delete(
19739
+ taskSummaryConversationId
19740
+ );
19741
+ return;
19742
+ }
19743
+ manuallyClosedTaskSummaryConversationIdsRef.current.add(
19744
+ taskSummaryConversationId
19745
+ );
19746
+ },
19747
+ [taskSummaryConversationId]
19748
+ );
19749
+ React54.useEffect(() => {
19750
+ if (!taskSummaryDocked) {
19751
+ setTaskSummaryOpen(false);
19752
+ }
19753
+ }, [taskSummaryDocked]);
19754
+ React54.useEffect(() => {
19755
+ if (!taskSummaryDocked || !taskSummaryAvailable || !taskSummaryConversationId || manuallyClosedTaskSummaryConversationIdsRef.current.has(
19756
+ taskSummaryConversationId
19757
+ )) {
19758
+ return;
19759
+ }
19760
+ setTaskSummaryOpen(true);
19761
+ }, [taskSummaryAvailable, taskSummaryConversationId, taskSummaryDocked]);
19762
+ const taskSummaryProps = {
19763
+ summary: taskSummary.summary,
19764
+ historyError: taskSummary.historyError,
19765
+ loadingSections: taskSummary.loadingSections,
19766
+ loadedSectionCounts: taskSummary.loadedSectionCounts,
19767
+ onRetryHistory: taskSummary.retryHistory,
19768
+ onLoadSection: taskSummary.loadSection,
19769
+ onNavigateMessage: (messageId) => {
19770
+ void navigateToTaskSummaryMessage(messageId);
19771
+ },
19772
+ onFocusComposer: () => focusComposerAt(),
19773
+ onOpenResource: openTaskSummaryResource
19774
+ };
19775
+ return /* @__PURE__ */ jsxs40(
19776
+ "div",
19777
+ {
19778
+ className: "relative flex h-full w-full min-w-0 bg-background",
19779
+ "data-task-summary-layout": taskSummaryDocked ? "docked" : "popover",
19780
+ children: [
19781
+ /* @__PURE__ */ jsxs40(
19782
+ UploadDroppedFiles,
18673
19783
  {
18674
- type: "button",
18675
- size: "icon-sm",
18676
- variant: hasUpdatesBelow ? "default" : "outline",
19784
+ ref: viewportRef,
19785
+ "data-chatkit-root": "",
19786
+ enabled: canUploadDroppedFiles,
19787
+ dropTitle: t("chat.dropFilesTitle"),
19788
+ dropHint: t("chat.dropFilesHint"),
19789
+ activeClassName: "ring-2 ring-primary/40 ring-inset",
19790
+ onFiles: handleDroppedFiles,
18677
19791
  className: cn(
18678
- "pointer-events-auto rounded-full shadow-md dark:border-white/20 dark:ring-1 dark:ring-white/15 dark:shadow-[0_0_0_1px_rgba(255,255,255,0.06),0_10px_30px_rgba(0,0,0,0.45)]",
18679
- hasUpdatesBelow && "animate-bounce"
19792
+ "relative flex h-full w-full min-w-0 flex-col flex-1 overflow-y-auto bg-background shadow-sm transition-[box-shadow] duration-150",
19793
+ className
18680
19794
  ),
18681
- onClick: () => scrollToBottom(true, true),
18682
- "aria-label": t("chat.scrollToBottom"),
18683
- title: t("chat.scrollToBottom"),
18684
- children: /* @__PURE__ */ jsx57(ArrowDown2, { size: 16 })
18685
- }
18686
- ) }),
18687
- quoteSelection && /* @__PURE__ */ jsx57(
18688
- "div",
18689
- {
18690
- className: "pointer-events-none fixed z-50",
18691
- style: {
18692
- top: `${quoteSelection.top}px`,
18693
- left: `${quoteSelection.left}px`,
18694
- transform: "translateX(-50%)"
18695
- },
18696
- children: /* @__PURE__ */ jsxs39(
18697
- Button,
18698
- {
18699
- type: "button",
18700
- size: "sm",
18701
- variant: "secondary",
18702
- className: "pointer-events-auto shadow-lg",
18703
- onMouseDown: (event) => event.preventDefault(),
18704
- onClick: handleQuoteSelection,
18705
- "aria-label": t("composer.quoteSelection"),
18706
- title: t("composer.quoteSelection"),
18707
- children: [
18708
- /* @__PURE__ */ jsx57(Quote, { size: 14 }),
18709
- t("composer.quoteSelection")
18710
- ]
18711
- }
18712
- )
18713
- }
18714
- ),
18715
- /* @__PURE__ */ jsxs39(
18716
- "div",
18717
- {
18718
- "data-slot": "chatkit-chat-composer",
18719
- className: "mx-auto w-full p-2 sticky bottom-0 z-10 bg-background",
18720
- style: chatColumnStyle,
18721
19795
  children: [
18722
- threadErrorMessage && /* @__PURE__ */ jsx57("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 }),
18723
- /* @__PURE__ */ jsx57(
18724
- ChatAttachments,
18725
- {
18726
- ref: attachmentsRef,
18727
- accept: acceptMimes,
18728
- maxCount: composer?.attachments?.maxCount ?? 10,
18729
- maxSize: composer?.attachments?.maxSize ?? 100 * 1024 * 1024,
18730
- retryUploadLabel: t("chat.retryUpload"),
18731
- uploadFile: uploadContextFile,
18732
- deleteFile: deleteContextFile,
18733
- getFileStatus: getContextFileStatus,
18734
- onStateChange: setAttachmentState
18735
- }
18736
- ),
18737
- references.length > 0 && /* @__PURE__ */ jsx57("div", { className: "mb-3 flex flex-wrap gap-2", children: references.map((reference) => /* @__PURE__ */ jsx57(
18738
- ReferenceChip,
18739
- {
18740
- reference,
18741
- variant: "composer",
18742
- onRemove: () => setReferences(
18743
- (previous) => previous.filter(
18744
- (item) => getReferenceKey(item) !== getReferenceKey(reference)
18745
- )
18746
- ),
18747
- removeLabel: t("composer.removeReference")
18748
- },
18749
- getReferenceKey(reference)
18750
- )) }),
18751
- /* @__PURE__ */ jsx57(
18752
- DetachedRunRuntimeCapabilities,
18753
- {
18754
- options: detachedRunRuntimeCapabilityOptions,
18755
- runOnlyLabel: t("composer.capabilities.runOnly"),
18756
- removeLabel: t("composer.capabilities.removeRunCapability"),
18757
- onRemove: removeRunRuntimeCapability
18758
- }
18759
- ),
18760
- showGoalStatus && /* @__PURE__ */ jsxs39(
19796
+ /* @__PURE__ */ jsxs40(
18761
19797
  "div",
18762
19798
  {
18763
- className: cn(
18764
- "mb-2 flex min-h-10 gap-2 rounded-md border border-border bg-background px-2.5 py-2 text-xs text-foreground shadow-sm",
18765
- isGoalObjectiveExpanded ? "items-start" : "items-center"
18766
- ),
19799
+ ref: chatColumnRef,
19800
+ "data-slot": "chatkit-chat-header",
19801
+ className: "mx-auto flex w-full items-center justify-between border-b p-2 sticky top-0 z-10 bg-background",
19802
+ style: chatColumnStyle,
18767
19803
  children: [
18768
- /* @__PURE__ */ jsx57(
18769
- Target2,
18770
- {
18771
- className: cn(
18772
- "size-4 shrink-0 text-muted-foreground",
18773
- isGoalObjectiveExpanded && "mt-1"
18774
- )
18775
- }
18776
- ),
18777
- /* @__PURE__ */ jsxs39("div", { className: "min-w-0 flex-1", children: [
18778
- /* @__PURE__ */ jsxs39("div", { className: "flex min-w-0 items-center gap-2", children: [
18779
- /* @__PURE__ */ jsx57("span", { className: "font-medium", children: t("chat.goal.label") }),
18780
- threadGoal && /* @__PURE__ */ jsx57("span", { className: "shrink-0 rounded-md bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground", children: t(`chat.goal.status.${threadGoal.status}`) }),
18781
- isGoalLoading && /* @__PURE__ */ jsx57(Loader29, { className: "size-3 animate-spin text-muted-foreground" })
19804
+ /* @__PURE__ */ jsxs40("div", { className: "flex min-w-0 items-center gap-3 overflow-hidden", children: [
19805
+ /* @__PURE__ */ jsxs40("div", { className: "relative shrink-0", children: [
19806
+ /* @__PURE__ */ jsx58(
19807
+ ChatkitAvatar,
19808
+ {
19809
+ avatar: assistantAvatar,
19810
+ className: "h-9 w-9 border border-border/60",
19811
+ label: assistantTitle
19812
+ }
19813
+ ),
19814
+ /* @__PURE__ */ jsx58("span", { className: "absolute bottom-0 right-0 h-2.5 w-2.5 rounded-full border-2 border-background bg-green-500" })
18782
19815
  ] }),
18783
- /* @__PURE__ */ jsx57(
18784
- "div",
19816
+ /* @__PURE__ */ jsxs40("div", { className: "min-w-0", children: [
19817
+ /* @__PURE__ */ jsx58(
19818
+ "h2",
19819
+ {
19820
+ className: "text-lg font-semibold truncate",
19821
+ title: assistantTitle,
19822
+ children: assistantTitle
19823
+ }
19824
+ ),
19825
+ /* @__PURE__ */ jsx58(
19826
+ "p",
19827
+ {
19828
+ className: "truncate text-xs text-muted-foreground",
19829
+ title: assistantStatusText,
19830
+ children: assistantStatusText
19831
+ }
19832
+ )
19833
+ ] })
19834
+ ] }),
19835
+ /* @__PURE__ */ jsxs40("div", { className: "flex items-center gap-1", children: [
19836
+ taskSummaryAvailable && /* @__PURE__ */ jsx58(
19837
+ TaskSummaryTrigger,
18785
19838
  {
18786
- className: cn(
18787
- "mt-0.5 text-muted-foreground",
18788
- threadGoal?.objective && !goalError && isGoalObjectiveExpanded ? "whitespace-pre-wrap break-words" : "truncate"
18789
- ),
18790
- children: goalError || threadGoal?.objective
19839
+ ...taskSummaryProps,
19840
+ displayMode: taskSummaryDocked ? "docked" : "popover",
19841
+ open: taskSummaryOpen,
19842
+ onOpenChange: handleTaskSummaryOpenChange
18791
19843
  }
18792
19844
  ),
18793
- threadGoal && /* @__PURE__ */ jsx57("div", { className: "mt-1 flex flex-wrap gap-x-3 gap-y-1 text-[11px] text-muted-foreground", children: /* @__PURE__ */ jsx57("span", { children: t("chat.goal.elapsed", {
18794
- elapsed: formatGoalElapsed(displayedGoalElapsedSeconds)
18795
- }) }) })
18796
- ] }),
18797
- threadGoal && /* @__PURE__ */ jsxs39("div", { className: "flex shrink-0 items-center gap-1", children: [
18798
- /* @__PURE__ */ jsxs39(Tooltip, { children: [
18799
- /* @__PURE__ */ jsx57(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx57(
18800
- Button,
19845
+ canMinimizeToPet && /* @__PURE__ */ jsxs40(Tooltip, { children: [
19846
+ /* @__PURE__ */ jsx58(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx58("span", { className: "inline-flex h-8 w-8", children: /* @__PURE__ */ jsx58(
19847
+ "button",
18801
19848
  {
18802
19849
  type: "button",
18803
- variant: "ghost",
18804
- size: "icon-xs",
18805
- disabled: isGoalLoading,
18806
- onClick: () => {
18807
- const prefix = "/goal edit ";
18808
- setComposerText(`${prefix}${threadGoal.objective}`);
18809
- },
18810
- children: /* @__PURE__ */ jsx57(Pencil4, { className: "size-3" })
19850
+ onClick: handleMinimizeToPet,
19851
+ className: cn(
19852
+ "flex h-8 w-8 cursor-pointer items-center justify-center rounded-md",
19853
+ "text-muted-foreground hover:text-foreground hover:bg-muted",
19854
+ "transition-colors duration-150"
19855
+ ),
19856
+ "aria-label": t("chat.minimizeToPet"),
19857
+ children: /* @__PURE__ */ jsx58(Minus, { size: 16 })
18811
19858
  }
18812
- ) }),
18813
- /* @__PURE__ */ jsx57(TooltipContent, { children: t("chat.goal.edit") })
19859
+ ) }) }),
19860
+ /* @__PURE__ */ jsx58(TooltipContent, { side: "bottom", children: t("chat.minimizeToPet") })
18814
19861
  ] }),
18815
- /* @__PURE__ */ jsxs39(Tooltip, { children: [
18816
- /* @__PURE__ */ jsx57(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx57(
18817
- Button,
19862
+ /* @__PURE__ */ jsxs40(Tooltip, { children: [
19863
+ /* @__PURE__ */ jsx58(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx58("span", { className: "inline-flex h-8 w-8", children: /* @__PURE__ */ jsx58(
19864
+ "button",
18818
19865
  {
18819
19866
  type: "button",
18820
- variant: "ghost",
18821
- size: "icon-xs",
18822
- disabled: isGoalLoading,
18823
- onClick: () => void handleGoalCommand({
18824
- args: threadGoal.status === "paused" ? "resume" : "pause",
18825
- commandSource: {
18826
- type: "slash_command",
18827
- name: "goal",
18828
- source: "runtime",
18829
- executionType: "insert_invocation"
18830
- }
18831
- }),
18832
- children: threadGoal.status === "paused" ? /* @__PURE__ */ jsx57(Play, { className: "size-3" }) : /* @__PURE__ */ jsx57(Pause, { className: "size-3" })
19867
+ onClick: () => setPetSettingsOpen(true),
19868
+ className: cn(
19869
+ "flex h-8 w-8 cursor-pointer items-center justify-center rounded-md",
19870
+ "text-muted-foreground hover:text-foreground hover:bg-muted",
19871
+ "transition-colors duration-150"
19872
+ ),
19873
+ "aria-label": t("settings.open"),
19874
+ children: /* @__PURE__ */ jsx58(Settings2, { size: 16 })
18833
19875
  }
18834
- ) }),
18835
- /* @__PURE__ */ jsx57(TooltipContent, { children: threadGoal.status === "paused" ? t("chat.goal.resume") : t("chat.goal.pause") })
19876
+ ) }) }),
19877
+ /* @__PURE__ */ jsx58(TooltipContent, { side: "bottom", children: t("settings.open") })
18836
19878
  ] }),
18837
- /* @__PURE__ */ jsxs39(Tooltip, { children: [
18838
- /* @__PURE__ */ jsx57(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx57(
19879
+ history?.enabled !== false && /* @__PURE__ */ jsxs40(Fragment9, { children: [
19880
+ /* @__PURE__ */ jsxs40(Tooltip, { children: [
19881
+ /* @__PURE__ */ jsx58(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx58("span", { className: "inline-flex h-8 w-8", children: /* @__PURE__ */ jsx58(
19882
+ "button",
19883
+ {
19884
+ type: "button",
19885
+ onClick: handleNewThread,
19886
+ disabled: missingConfig || isHistoryLoading,
19887
+ className: cn(
19888
+ "flex h-8 w-8 cursor-pointer items-center justify-center rounded-md",
19889
+ "text-muted-foreground hover:text-foreground hover:bg-muted",
19890
+ "transition-colors duration-150",
19891
+ "disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed"
19892
+ ),
19893
+ "aria-label": t("history.newThread"),
19894
+ children: /* @__PURE__ */ jsx58(Pencil4, { size: 16 })
19895
+ }
19896
+ ) }) }),
19897
+ /* @__PURE__ */ jsx58(TooltipContent, { side: "bottom", children: t("history.newThread") })
19898
+ ] }),
19899
+ /* @__PURE__ */ jsx58(
19900
+ HistorySidebar,
19901
+ {
19902
+ threads,
19903
+ currentThreadId: stream.threadId ?? void 0,
19904
+ onNewThread: handleNewThread,
19905
+ onSelectThread: handleSelectThread,
19906
+ onDeleteThread: handleDeleteThread,
19907
+ showDelete: history?.showDelete !== false,
19908
+ disabled: missingConfig || isThreadsLoading || isHistoryLoading
19909
+ }
19910
+ )
19911
+ ] })
19912
+ ] })
19913
+ ]
19914
+ }
19915
+ ),
19916
+ showMessageNavigation && /* @__PURE__ */ jsx58(
19917
+ MessageNavigator,
19918
+ {
19919
+ items: messageNavigationItems,
19920
+ viewportRef,
19921
+ getAnchor: getMessageNavigationAnchor,
19922
+ onNavigate: handleMessageNavigationNavigate,
19923
+ label: t("message.navigation.label"),
19924
+ tagsOverflowLabel: (count) => t("message.navigation.moreTags", { count })
19925
+ }
19926
+ ),
19927
+ /* @__PURE__ */ jsxs40(
19928
+ "div",
19929
+ {
19930
+ "data-slot": "chatkit-chat-content",
19931
+ className: "mx-auto w-full flex-1 p-4",
19932
+ style: chatColumnStyle,
19933
+ children: [
19934
+ errorMessage && /* @__PURE__ */ jsx58("div", { className: "mb-4 rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: errorMessage }),
19935
+ historyError && /* @__PURE__ */ jsx58("div", { className: "mb-4 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900", children: historyError }),
19936
+ showMissingConfig && /* @__PURE__ */ jsx58("div", { className: "mb-4 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900", children: missingConfigDetailMessage }),
19937
+ isHistoryLoading && /* @__PURE__ */ jsx58("div", { className: "mb-4 rounded-lg border border-muted px-3 py-2 text-sm text-muted-foreground", children: t("chat.loadingThread") }),
19938
+ messages.length === 0 && !canLoadMoreMessages ? /* @__PURE__ */ jsx58(
19939
+ StartScreen,
19940
+ {
19941
+ startScreen,
19942
+ onPromptClick: handlePromptClick,
19943
+ onPromptEdit: handlePromptEdit,
19944
+ promptSendDisabled: isSubmissionBlocked,
19945
+ promptEditDisabled: isPromptEditDisabled
19946
+ }
19947
+ ) : /* @__PURE__ */ jsxs40("div", { className: "space-y-4", children: [
19948
+ canLoadMoreMessages && /* @__PURE__ */ jsxs40("div", { className: "flex items-center gap-3 py-1", children: [
19949
+ /* @__PURE__ */ jsx58("div", { className: "h-px min-w-8 flex-1 bg-border" }),
19950
+ /* @__PURE__ */ jsx58(
18839
19951
  Button,
18840
19952
  {
18841
19953
  type: "button",
18842
19954
  variant: "ghost",
18843
- size: "icon-xs",
18844
- disabled: isGoalLoading,
18845
- onClick: () => void handleGoalCommand({
18846
- args: "clear",
18847
- commandSource: {
18848
- type: "slash_command",
18849
- name: "goal",
18850
- source: "runtime",
18851
- executionType: "insert_invocation"
18852
- }
18853
- }),
18854
- children: /* @__PURE__ */ jsx57(Trash23, { className: "size-3" })
19955
+ size: "sm",
19956
+ onClick: handleLoadMoreMessages,
19957
+ disabled: isLoadingMoreMessages,
19958
+ className: "h-7 px-2 text-xs font-medium text-muted-foreground hover:text-foreground",
19959
+ children: isLoadingMoreMessages ? t("chat.loadingMoreMessages") : t("chat.loadMoreMessages")
18855
19960
  }
18856
- ) }),
18857
- /* @__PURE__ */ jsx57(TooltipContent, { children: t("chat.goal.clear") })
19961
+ ),
19962
+ /* @__PURE__ */ jsx58("div", { className: "h-px min-w-8 flex-1 bg-border" })
18858
19963
  ] }),
18859
- threadGoal.objective && !goalError && /* @__PURE__ */ jsxs39(Tooltip, { children: [
18860
- /* @__PURE__ */ jsx57(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx57(
18861
- Button,
19964
+ messages.map((message, index) => {
19965
+ const messageType = String(message.type);
19966
+ const isAssistantMessage = messageType === "assistant" || messageType === "ai";
19967
+ const isStreamingMessage = stream.isLoading && index === messages.length - 1;
19968
+ const streamingStatus = isAssistantMessage ? getAssistantStreamingStatus(
18862
19969
  {
18863
- type: "button",
18864
- variant: "ghost",
18865
- size: "icon-xs",
18866
- "aria-expanded": isGoalObjectiveExpanded,
18867
- "aria-label": isGoalObjectiveExpanded ? t("chat.goal.collapseObjective") : t("chat.goal.expandObjective"),
18868
- onClick: () => setIsGoalObjectiveExpanded((expanded) => !expanded),
18869
- children: /* @__PURE__ */ jsx57(
18870
- ChevronDown5,
19970
+ ...message,
19971
+ lastStreamOutputAt: lastStreamOutputAtRef.current
19972
+ },
19973
+ isStreamingMessage,
19974
+ { now: streamingNow }
19975
+ ) : null;
19976
+ if (isAssistantMessage && !hasRenderableAssistantMessage(message) && !streamingStatus) {
19977
+ return null;
19978
+ }
19979
+ const messageContent = typeof message.content === "string" ? message.content : Array.isArray(message.content) ? message.content.map((part) => formatMessageContent(part)).join("") : formatMessageContent(message.content);
19980
+ const hasPlainRenderableContent = messageContent.trim().length > 0;
19981
+ const humanMessage = message;
19982
+ const humanReferences = humanMessage.references ?? [];
19983
+ const humanAttachments = getVisibleHumanAttachments(
19984
+ [
19985
+ ...humanMessage.fileAssets ?? [],
19986
+ ...humanMessage.attachments ?? []
19987
+ ],
19988
+ humanReferences
19989
+ );
19990
+ const humanRuntimeCapabilityOptions = message.type === "human" ? humanMessage.runtimeCapabilityOptions ?? getRuntimeCapabilityOptionsForSelection(
19991
+ getRecommendedRuntimeCapabilitiesSelection(
19992
+ humanMessage.runtimeCapabilities
19993
+ ),
19994
+ runtimeCapabilityOptions
19995
+ ) : [];
19996
+ const hasHumanAttachments = message.type === "human" && humanAttachments.length > 0;
19997
+ const canQuoteMessage = message.type === "human" || isAssistantMessage;
19998
+ const quoteSource = message.type === "human" ? t("chat.youLabel") : assistantTitle;
19999
+ const messageNavigationId = getMessageNavigationItemId(
20000
+ message,
20001
+ index
20002
+ );
20003
+ if (!isAssistantMessage && !hasPlainRenderableContent && !hasHumanAttachments && humanRuntimeCapabilityOptions.length === 0 && humanReferences.length === 0) {
20004
+ return null;
20005
+ }
20006
+ return /* @__PURE__ */ jsx58(
20007
+ "div",
20008
+ {
20009
+ ref: (node) => setMessageNavigationAnchor(messageNavigationId, node),
20010
+ "data-message-navigation-id": messageNavigationId,
20011
+ className: cn(
20012
+ "group flex gap-3",
20013
+ message.type === "human" ? "justify-end" : "justify-start -ml-1"
20014
+ // AI messages: slightly closer to left
20015
+ ),
20016
+ children: /* @__PURE__ */ jsxs40(
20017
+ "div",
18871
20018
  {
18872
20019
  className: cn(
18873
- "size-3 transition-transform",
18874
- isGoalObjectiveExpanded && "rotate-180"
18875
- )
20020
+ "flex flex-col px-3 overflow-hidden",
20021
+ isAssistantMessage && "min-w-0 flex-1"
20022
+ ),
20023
+ children: [
20024
+ /* @__PURE__ */ jsx58(
20025
+ "div",
20026
+ {
20027
+ ...canQuoteMessage ? {
20028
+ "data-quote-message-id": message.id,
20029
+ "data-quote-source": quoteSource
20030
+ } : {},
20031
+ className: cn(
20032
+ "max-w-full rounded-2xl",
20033
+ 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"
20034
+ // AI messages: use chat-specific foreground color
20035
+ ),
20036
+ children: isAssistantMessage ? /* @__PURE__ */ jsx58(
20037
+ AssistantMessage,
20038
+ {
20039
+ message: {
20040
+ ...message,
20041
+ type: "assistant"
20042
+ },
20043
+ messages: messages.slice(0, index + 1).map(
20044
+ (item) => ({
20045
+ ...item,
20046
+ type: String(item.type) === "ai" ? "assistant" : item.type
20047
+ })
20048
+ ),
20049
+ isStreaming: isStreamingMessage,
20050
+ streamingStatus,
20051
+ isThreadRunning: currentThreadIsRunning,
20052
+ organizationId: stream.organizationId,
20053
+ apiUrl: stream.apiUrl,
20054
+ pet: effectivePet
20055
+ }
20056
+ ) : /* @__PURE__ */ jsxs40(Fragment9, { children: [
20057
+ message.type === "human" && humanRuntimeCapabilityOptions.length > 0 && /* @__PURE__ */ jsx58(
20058
+ HumanRuntimeCapabilityChips,
20059
+ {
20060
+ options: humanRuntimeCapabilityOptions
20061
+ }
20062
+ ),
20063
+ message.type === "human" && humanReferences.length > 0 && /* @__PURE__ */ jsx58("div", { className: "mb-2 flex flex-wrap gap-1.5", children: humanReferences.map((reference) => /* @__PURE__ */ jsx58(
20064
+ ReferenceChip,
20065
+ {
20066
+ reference,
20067
+ variant: "message"
20068
+ },
20069
+ getReferenceKey(reference)
20070
+ )) }),
20071
+ message.type === "human" && humanAttachments.length > 0 && /* @__PURE__ */ jsx58("div", { className: "flex flex-wrap gap-1.5 mb-2", children: humanAttachments.map((file, fileIndex) => /* @__PURE__ */ jsxs40(
20072
+ "div",
20073
+ {
20074
+ className: "flex items-center gap-1.5 rounded-md bg-primary-foreground/20 px-2 py-1 text-xs",
20075
+ children: [
20076
+ /* @__PURE__ */ jsx58(FileText5, { size: 12 }),
20077
+ /* @__PURE__ */ jsx58("span", { className: "max-w-[100px] truncate", children: file.originalName ?? file.id })
20078
+ ]
20079
+ },
20080
+ fileIndex
20081
+ )) }),
20082
+ Array.isArray(message.content) ? message.content.map((part, partIndex) => /* @__PURE__ */ jsx58(
20083
+ "p",
20084
+ {
20085
+ className: "wrap-break-word text-sm leading-relaxed",
20086
+ children: formatMessageContent(part)
20087
+ },
20088
+ `${part.type}-${partIndex}`
20089
+ )) : /* @__PURE__ */ jsx58("span", { className: "wrap-break-word text-sm leading-relaxed", children: formatMessageContent(message.content) })
20090
+ ] })
20091
+ }
20092
+ ),
20093
+ /* @__PURE__ */ jsx58(
20094
+ MessageActions,
20095
+ {
20096
+ content: messageContent,
20097
+ isAssistant: isAssistantMessage,
20098
+ isStreaming: isStreamingMessage,
20099
+ onRetry: isAssistantMessage && !stream.isLoading && index === messages.length - 1 ? () => handleRetry(index) : void 0
20100
+ }
20101
+ )
20102
+ ]
18876
20103
  }
18877
20104
  )
20105
+ },
20106
+ message.id ?? `${message.type}-${index}`
20107
+ );
20108
+ }),
20109
+ showLoadingDots && (() => {
20110
+ const lastMessage = messages[messages.length - 1];
20111
+ const lastMessageType = lastMessage ? String(lastMessage.type) : "";
20112
+ const isLastMessageFromAI = lastMessageType === "ai" || lastMessageType === "assistant";
20113
+ const lastAssistantStatus = isLastMessageFromAI ? getAssistantStreamingStatus(
20114
+ {
20115
+ ...lastMessage,
20116
+ lastStreamOutputAt: lastStreamOutputAtRef.current
20117
+ },
20118
+ stream.isLoading,
20119
+ { now: streamingNow }
20120
+ ) : null;
20121
+ if (lastAssistantStatus) return null;
20122
+ const fallbackStreamingStatus = getAssistantStreamingStatus(
20123
+ {
20124
+ status: void 0,
20125
+ reasoning: void 0,
20126
+ lastStreamOutputAt: lastStreamOutputAtRef.current
20127
+ },
20128
+ stream.isLoading,
20129
+ { now: streamingNow }
20130
+ );
20131
+ return /* @__PURE__ */ jsx58("div", { className: "flex justify-start gap-3 -ml-2", children: /* @__PURE__ */ jsx58("div", { className: "max-w-full rounded-2xl py-2.5", children: /* @__PURE__ */ jsx58(
20132
+ AssistantStreamingIndicator,
20133
+ {
20134
+ status: fallbackStreamingStatus ?? "loading"
18878
20135
  }
18879
- ) }),
18880
- /* @__PURE__ */ jsx57(TooltipContent, { children: isGoalObjectiveExpanded ? t("chat.goal.collapseObjective") : t("chat.goal.expandObjective") })
18881
- ] })
20136
+ ) }) });
20137
+ })()
18882
20138
  ] })
18883
20139
  ]
18884
20140
  }
18885
20141
  ),
18886
- /* @__PURE__ */ jsx57(
18887
- PendingRuntimeServices,
18888
- {
18889
- state: stream.runtimeActivities.sandboxServices,
18890
- onStopService: (serviceId) => stream.stopRuntimeActivityItem("sandbox-services", serviceId),
18891
- attachToComposer: !hasPendingTodos && !hasPendingFollowUps,
18892
- className: hasPendingTodos || hasPendingFollowUps ? "mb-2" : void 0
18893
- }
18894
- ),
18895
- /* @__PURE__ */ jsx57(
18896
- PendingTodos,
20142
+ !isAtBottom && messages.length > 0 && /* @__PURE__ */ jsx58("div", { className: "sticky bottom-20 z-20 flex justify-center px-4 pointer-events-none", children: /* @__PURE__ */ jsx58(
20143
+ Button,
18897
20144
  {
18898
- snapshot: stream.todos,
18899
- attachToComposer: !hasPendingFollowUps,
18900
- className: hasPendingFollowUps ? "mb-2" : void 0
18901
- }
18902
- ),
18903
- /* @__PURE__ */ jsx57(
18904
- PendingFollowUps,
18905
- {
18906
- items: pendingFollowUps,
18907
- isLoading: stream.isLoading,
18908
- onPromoteToSteer: (id) => stream.promotePendingFollowUpToSteer(id),
18909
- canSendNow: stream.canSendPendingFollowUpNow,
18910
- onSendNow: (id) => stream.sendPendingFollowUpNow(id),
18911
- onEdit: handleEditPendingFollowUp,
18912
- onRemove: stream.removePendingFollowUp,
18913
- attachToComposer: true
18914
- }
18915
- ),
18916
- /* @__PURE__ */ jsx57(
18917
- RequestUserInputPanel,
18918
- {
18919
- request: stream.pendingRequestUserInput,
18920
- onSubmit: stream.submitRequestUserInput,
18921
- onDismiss: stream.stop,
18922
- attachToComposer: true
18923
- }
18924
- ),
18925
- /* @__PURE__ */ jsx57(
18926
- HITLApprovalPanel,
18927
- {
18928
- request: stream.pendingHITLRequest,
18929
- onSubmit: stream.submitHITLDecision,
18930
- onDismiss: stream.stop,
18931
- attachToComposer: true
20145
+ type: "button",
20146
+ size: "icon-sm",
20147
+ variant: hasUpdatesBelow ? "default" : "outline",
20148
+ className: cn(
20149
+ "pointer-events-auto rounded-full shadow-md dark:border-white/20 dark:ring-1 dark:ring-white/15 dark:shadow-[0_0_0_1px_rgba(255,255,255,0.06),0_10px_30px_rgba(0,0,0,0.45)]",
20150
+ hasUpdatesBelow && "animate-bounce"
20151
+ ),
20152
+ onClick: () => scrollToBottom(true, true),
20153
+ "aria-label": t("chat.scrollToBottom"),
20154
+ title: t("chat.scrollToBottom"),
20155
+ children: /* @__PURE__ */ jsx58(ArrowDown2, { size: 16 })
18932
20156
  }
18933
- ),
18934
- runtimeCapabilityPalette && /* @__PURE__ */ jsx57(
18935
- SlashPalette,
20157
+ ) }),
20158
+ quoteSelection && /* @__PURE__ */ jsx58(
20159
+ "div",
18936
20160
  {
18937
- palette: runtimeCapabilityPalette,
18938
- options: slashPaletteOptions,
18939
- paletteRef: slashPaletteRef,
18940
- optionRefs: slashPaletteOptionRefs,
18941
- panelRoundedClass: getPanelRoundedClass(theme.radius),
18942
- itemRoundedClass: getMenuItemRoundedClass(theme.radius),
18943
- emptyLabel: slashPaletteEmptyLabel,
18944
- capabilityEmptyLabels: slashPaletteCapabilityEmptyLabels,
18945
- onSelect: selectSlashPaletteOption
20161
+ className: "pointer-events-none fixed z-50",
20162
+ style: {
20163
+ top: `${quoteSelection.top}px`,
20164
+ left: `${quoteSelection.left}px`,
20165
+ transform: "translateX(-50%)"
20166
+ },
20167
+ children: /* @__PURE__ */ jsxs40(
20168
+ Button,
20169
+ {
20170
+ type: "button",
20171
+ size: "sm",
20172
+ variant: "secondary",
20173
+ className: "pointer-events-auto shadow-lg",
20174
+ onMouseDown: (event) => event.preventDefault(),
20175
+ onClick: handleQuoteSelection,
20176
+ "aria-label": t("composer.quoteSelection"),
20177
+ title: t("composer.quoteSelection"),
20178
+ children: [
20179
+ /* @__PURE__ */ jsx58(Quote, { size: 14 }),
20180
+ t("composer.quoteSelection")
20181
+ ]
20182
+ }
20183
+ )
18946
20184
  }
18947
20185
  ),
18948
- /* @__PURE__ */ jsx57("form", { className: "flex items-end", onSubmit: handleSubmit, children: /* @__PURE__ */ jsxs39(
20186
+ /* @__PURE__ */ jsxs40(
18949
20187
  "div",
18950
20188
  {
18951
- "data-slot": "composer-input-shell",
18952
- "data-layout": isComposerStacked ? "stacked" : "inline",
18953
- className: cn(
18954
- "relative flex flex-1 overflow-hidden",
18955
- "bg-background border border-border shadow-sm",
18956
- isComposerStacked ? "min-h-[5.5rem] px-1.5 pt-1.5 pb-12" : "min-h-12 px-1.5 py-1",
18957
- "focus-within:border-muted-foreground/30 focus-within:shadow-md",
18958
- "transition-[min-height,padding,border-radius,box-shadow,border-color] duration-300 ease-[cubic-bezier(0.2,0.8,0.2,1)]",
18959
- composerInputRoundedClass
18960
- ),
20189
+ "data-slot": "chatkit-chat-composer",
20190
+ className: "mx-auto w-full p-2 sticky bottom-0 z-10 bg-background",
20191
+ style: chatColumnStyle,
18961
20192
  children: [
18962
- /* @__PURE__ */ jsx57(
18963
- "div",
20193
+ threadErrorMessage && /* @__PURE__ */ jsx58("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 }),
20194
+ /* @__PURE__ */ jsx58(
20195
+ ChatAttachments,
18964
20196
  {
18965
- ref: composerInputRef,
18966
- role: "textbox",
18967
- "aria-multiline": "true",
18968
- "aria-disabled": missingConfig || isHistoryLoading || hasPendingInteractiveRequest,
18969
- contentEditable: !(missingConfig || isHistoryLoading || hasPendingInteractiveRequest),
18970
- suppressContentEditableWarning: true,
18971
- onInput: handleComposerInput,
18972
- onCompositionEnd: handleComposerCompositionEnd,
18973
- onSelect: handleComposerSelect,
18974
- onPaste: handleComposerPaste,
18975
- onKeyDown: handleComposerKeyDown,
18976
- "data-placeholder": inputPlaceholder,
18977
- className: cn(
18978
- "min-h-8 max-h-32 w-full overflow-hidden whitespace-pre-wrap break-words bg-transparent text-sm leading-5 text-foreground outline-none transition-[padding,min-height] duration-300 ease-[cubic-bezier(0.2,0.8,0.2,1)]",
18979
- isComposerStacked ? "px-2 py-1.5" : "py-1 pr-11 pl-11 mt-1",
18980
- "empty:before:pointer-events-none empty:before:text-muted-foreground empty:before:content-[attr(data-placeholder)]",
18981
- (missingConfig || isHistoryLoading || hasPendingInteractiveRequest) && "cursor-not-allowed opacity-50"
20197
+ ref: attachmentsRef,
20198
+ accept: acceptMimes,
20199
+ maxCount: composer?.attachments?.maxCount ?? 10,
20200
+ maxSize: composer?.attachments?.maxSize ?? 100 * 1024 * 1024,
20201
+ retryUploadLabel: t("chat.retryUpload"),
20202
+ uploadFile: uploadContextFile,
20203
+ deleteFile: deleteContextFile,
20204
+ getFileStatus: getContextFileStatus,
20205
+ onStateChange: setAttachmentState
20206
+ }
20207
+ ),
20208
+ references.length > 0 && /* @__PURE__ */ jsx58("div", { className: "mb-3 flex flex-wrap gap-2", children: references.map((reference) => /* @__PURE__ */ jsx58(
20209
+ ReferenceChip,
20210
+ {
20211
+ reference,
20212
+ variant: "composer",
20213
+ onRemove: () => setReferences(
20214
+ (previous) => previous.filter(
20215
+ (item) => getReferenceKey(item) !== getReferenceKey(reference)
20216
+ )
18982
20217
  ),
18983
- children: renderedComposerParts.map(
18984
- (part, index) => part.type === "text" ? /* @__PURE__ */ jsx57(React52.Fragment, { children: part.text }, `text-${index}`) : /* @__PURE__ */ jsx57(ComposerCapabilityToken, { part }, part.key)
18985
- )
20218
+ removeLabel: t("composer.removeReference")
18986
20219
  },
18987
- composerDomVersion
20220
+ getReferenceKey(reference)
20221
+ )) }),
20222
+ /* @__PURE__ */ jsx58(
20223
+ DetachedRunRuntimeCapabilities,
20224
+ {
20225
+ options: detachedRunRuntimeCapabilityOptions,
20226
+ runOnlyLabel: t("composer.capabilities.runOnly"),
20227
+ removeLabel: t("composer.capabilities.removeRunCapability"),
20228
+ onRemove: removeRunRuntimeCapability
20229
+ }
18988
20230
  ),
18989
- /* @__PURE__ */ jsxs39(
20231
+ showGoalStatus && /* @__PURE__ */ jsxs40(
18990
20232
  "div",
18991
20233
  {
18992
- "data-slot": "composer-action-bar",
18993
- className: "pointer-events-none absolute inset-x-1.5 bottom-1 flex min-h-10 items-center justify-between gap-2",
20234
+ className: cn(
20235
+ "mb-2 flex min-h-10 gap-2 rounded-md border border-border bg-background px-2.5 py-2 text-xs text-foreground shadow-sm",
20236
+ isGoalObjectiveExpanded ? "items-start" : "items-center"
20237
+ ),
18994
20238
  children: [
18995
- /* @__PURE__ */ jsxs39("div", { className: "pointer-events-none flex min-w-0 flex-1 items-center gap-1.5", children: [
18996
- /* @__PURE__ */ jsx57("div", { className: "pointer-events-auto flex shrink-0 items-center gap-1.5", children: /* @__PURE__ */ jsx57(
18997
- ComposerMenu,
20239
+ /* @__PURE__ */ jsx58(
20240
+ Target3,
20241
+ {
20242
+ className: cn(
20243
+ "size-4 shrink-0 text-muted-foreground",
20244
+ isGoalObjectiveExpanded && "mt-1"
20245
+ )
20246
+ }
20247
+ ),
20248
+ /* @__PURE__ */ jsxs40("div", { className: "min-w-0 flex-1", children: [
20249
+ /* @__PURE__ */ jsxs40("div", { className: "flex min-w-0 items-center gap-2", children: [
20250
+ /* @__PURE__ */ jsx58("span", { className: "font-medium", children: t("chat.goal.label") }),
20251
+ threadGoal && /* @__PURE__ */ jsx58("span", { className: "shrink-0 rounded-md bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground", children: t(`chat.goal.status.${threadGoal.status}`) }),
20252
+ isGoalLoading && /* @__PURE__ */ jsx58(Loader210, { className: "size-3 animate-spin text-muted-foreground" })
20253
+ ] }),
20254
+ /* @__PURE__ */ jsx58(
20255
+ "div",
18998
20256
  {
18999
- composer,
19000
- onAttachmentClick: handleAttachmentClick,
19001
- onToolSelect: handleToolSelect,
19002
- selectedTool,
19003
- planModeEnabled,
19004
- onPlanModeChange: setPlanModeEnabled,
19005
- goalCommandAvailable,
19006
- goalPanelOpen: isGoalModeOpen,
19007
- onGoalPanelOpenChange: handleGoalPanelOpenChange,
19008
- runtimeCapabilities: runtimeCapabilitiesReady ? runtimeCapabilities : null,
19009
- selectedRuntimeCapabilities: effectiveSessionRuntimeCapabilities,
19010
- onRuntimeCapabilityToggle: handleSessionRuntimeCapabilityToggle,
19011
- disabled: missingConfig || isHistoryLoading || hasPendingInteractiveRequest
20257
+ className: cn(
20258
+ "mt-0.5 text-muted-foreground",
20259
+ threadGoal?.objective && !goalError && isGoalObjectiveExpanded ? "whitespace-pre-wrap break-words" : "truncate"
20260
+ ),
20261
+ children: goalError || threadGoal?.objective
19012
20262
  }
19013
- ) }),
19014
- selectedTool && /* @__PURE__ */ jsxs39("span", { className: "pointer-events-auto inline-flex h-8 min-w-0 max-w-[14rem] shrink items-center gap-1.5 rounded-full bg-primary/10 px-2 text-xs font-medium text-primary transition-all duration-200", children: [
19015
- /* @__PURE__ */ jsx57("span", { className: "truncate", children: selectedTool.shortLabel ?? selectedTool.label }),
19016
- /* @__PURE__ */ jsx57(
19017
- "button",
20263
+ ),
20264
+ threadGoal && /* @__PURE__ */ jsx58("div", { className: "mt-1 flex flex-wrap gap-x-3 gap-y-1 text-[11px] text-muted-foreground", children: /* @__PURE__ */ jsx58("span", { children: t("chat.goal.elapsed", {
20265
+ elapsed: formatGoalElapsed(displayedGoalElapsedSeconds)
20266
+ }) }) })
20267
+ ] }),
20268
+ threadGoal && /* @__PURE__ */ jsxs40("div", { className: "flex shrink-0 items-center gap-1", children: [
20269
+ /* @__PURE__ */ jsxs40(Tooltip, { children: [
20270
+ /* @__PURE__ */ jsx58(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx58(
20271
+ Button,
19018
20272
  {
19019
20273
  type: "button",
19020
- onClick: () => setSelectedTool(null),
19021
- className: "shrink-0 rounded-full p-0.5 text-primary/70 hover:bg-primary/10 hover:text-primary",
19022
- children: /* @__PURE__ */ jsx57(X7, { size: 12 })
20274
+ variant: "ghost",
20275
+ size: "icon-xs",
20276
+ disabled: isGoalLoading,
20277
+ onClick: () => {
20278
+ const prefix = "/goal edit ";
20279
+ setComposerText(`${prefix}${threadGoal.objective}`);
20280
+ },
20281
+ children: /* @__PURE__ */ jsx58(Pencil4, { className: "size-3" })
19023
20282
  }
19024
- )
19025
- ] })
19026
- ] }),
19027
- /* @__PURE__ */ jsx57("div", { className: "pointer-events-auto shrink-0", children: /* @__PURE__ */ jsx57(
19028
- SendButton,
19029
- {
19030
- disabled: isSendDisabled,
19031
- isLoading: stream.isLoading,
19032
- showStop: stream.isLoading && (!trimmedDraft || hasPendingInteractiveRequest),
19033
- onStop: () => stream.stop(),
19034
- stopLabel: t("chat.stop"),
19035
- sendLabel: t("chat.send"),
19036
- shortcuts: stream.isLoading && trimmedDraft ? [
20283
+ ) }),
20284
+ /* @__PURE__ */ jsx58(TooltipContent, { children: t("chat.goal.edit") })
20285
+ ] }),
20286
+ /* @__PURE__ */ jsxs40(Tooltip, { children: [
20287
+ /* @__PURE__ */ jsx58(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx58(
20288
+ Button,
20289
+ {
20290
+ type: "button",
20291
+ variant: "ghost",
20292
+ size: "icon-xs",
20293
+ disabled: isGoalLoading,
20294
+ onClick: () => void handleGoalCommand({
20295
+ args: threadGoal.status === "paused" ? "resume" : "pause",
20296
+ commandSource: {
20297
+ type: "slash_command",
20298
+ name: "goal",
20299
+ source: "runtime",
20300
+ executionType: "insert_invocation"
20301
+ }
20302
+ }),
20303
+ children: threadGoal.status === "paused" ? /* @__PURE__ */ jsx58(Play, { className: "size-3" }) : /* @__PURE__ */ jsx58(Pause, { className: "size-3" })
20304
+ }
20305
+ ) }),
20306
+ /* @__PURE__ */ jsx58(TooltipContent, { children: threadGoal.status === "paused" ? t("chat.goal.resume") : t("chat.goal.pause") })
20307
+ ] }),
20308
+ /* @__PURE__ */ jsxs40(Tooltip, { children: [
20309
+ /* @__PURE__ */ jsx58(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx58(
20310
+ Button,
19037
20311
  {
19038
- label: t("chat.followUps.queue"),
19039
- keys: "Enter"
20312
+ type: "button",
20313
+ variant: "ghost",
20314
+ size: "icon-xs",
20315
+ disabled: isGoalLoading,
20316
+ onClick: () => void handleGoalCommand({
20317
+ args: "clear",
20318
+ commandSource: {
20319
+ type: "slash_command",
20320
+ name: "goal",
20321
+ source: "runtime",
20322
+ executionType: "insert_invocation"
20323
+ }
20324
+ }),
20325
+ children: /* @__PURE__ */ jsx58(Trash23, { className: "size-3" })
19040
20326
  }
19041
- ] : void 0
20327
+ ) }),
20328
+ /* @__PURE__ */ jsx58(TooltipContent, { children: t("chat.goal.clear") })
20329
+ ] }),
20330
+ threadGoal.objective && !goalError && /* @__PURE__ */ jsxs40(Tooltip, { children: [
20331
+ /* @__PURE__ */ jsx58(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx58(
20332
+ Button,
20333
+ {
20334
+ type: "button",
20335
+ variant: "ghost",
20336
+ size: "icon-xs",
20337
+ "aria-expanded": isGoalObjectiveExpanded,
20338
+ "aria-label": isGoalObjectiveExpanded ? t("chat.goal.collapseObjective") : t("chat.goal.expandObjective"),
20339
+ onClick: () => setIsGoalObjectiveExpanded((expanded) => !expanded),
20340
+ children: /* @__PURE__ */ jsx58(
20341
+ ChevronDown5,
20342
+ {
20343
+ className: cn(
20344
+ "size-3 transition-transform",
20345
+ isGoalObjectiveExpanded && "rotate-180"
20346
+ )
20347
+ }
20348
+ )
20349
+ }
20350
+ ) }),
20351
+ /* @__PURE__ */ jsx58(TooltipContent, { children: isGoalObjectiveExpanded ? t("chat.goal.collapseObjective") : t("chat.goal.expandObjective") })
20352
+ ] })
20353
+ ] })
20354
+ ]
20355
+ }
20356
+ ),
20357
+ /* @__PURE__ */ jsx58(
20358
+ PendingRuntimeServices,
20359
+ {
20360
+ state: stream.runtimeActivities.sandboxServices,
20361
+ onStopService: (serviceId) => stream.stopRuntimeActivityItem("sandbox-services", serviceId),
20362
+ attachToComposer: !hasPendingTodos && !hasPendingFollowUps,
20363
+ className: hasPendingTodos || hasPendingFollowUps ? "mb-2" : void 0
20364
+ }
20365
+ ),
20366
+ /* @__PURE__ */ jsx58(
20367
+ PendingTodos,
20368
+ {
20369
+ snapshot: stream.todos,
20370
+ attachToComposer: !hasPendingFollowUps,
20371
+ className: hasPendingFollowUps ? "mb-2" : void 0
20372
+ }
20373
+ ),
20374
+ /* @__PURE__ */ jsx58(
20375
+ PendingFollowUps,
20376
+ {
20377
+ items: pendingFollowUps,
20378
+ isLoading: stream.isLoading,
20379
+ onPromoteToSteer: (id) => stream.promotePendingFollowUpToSteer(id),
20380
+ canSendNow: stream.canSendPendingFollowUpNow,
20381
+ onSendNow: (id) => stream.sendPendingFollowUpNow(id),
20382
+ onEdit: handleEditPendingFollowUp,
20383
+ onRemove: stream.removePendingFollowUp,
20384
+ attachToComposer: true
20385
+ }
20386
+ ),
20387
+ /* @__PURE__ */ jsx58(
20388
+ RequestUserInputPanel,
20389
+ {
20390
+ request: stream.pendingRequestUserInput,
20391
+ onSubmit: stream.submitRequestUserInput,
20392
+ onDismiss: stream.stop,
20393
+ attachToComposer: true
20394
+ }
20395
+ ),
20396
+ /* @__PURE__ */ jsx58(
20397
+ HITLApprovalPanel,
20398
+ {
20399
+ request: stream.pendingHITLRequest,
20400
+ onSubmit: stream.submitHITLDecision,
20401
+ onDismiss: stream.stop,
20402
+ attachToComposer: true
20403
+ }
20404
+ ),
20405
+ runtimeCapabilityPalette && /* @__PURE__ */ jsx58(
20406
+ SlashPalette,
20407
+ {
20408
+ palette: runtimeCapabilityPalette,
20409
+ options: slashPaletteOptions,
20410
+ paletteRef: slashPaletteRef,
20411
+ optionRefs: slashPaletteOptionRefs,
20412
+ panelRoundedClass: getPanelRoundedClass(theme.radius),
20413
+ itemRoundedClass: getMenuItemRoundedClass(theme.radius),
20414
+ emptyLabel: slashPaletteEmptyLabel,
20415
+ capabilityEmptyLabels: slashPaletteCapabilityEmptyLabels,
20416
+ onSelect: selectSlashPaletteOption
20417
+ }
20418
+ ),
20419
+ /* @__PURE__ */ jsx58("form", { className: "flex items-end", onSubmit: handleSubmit, children: /* @__PURE__ */ jsxs40(
20420
+ "div",
20421
+ {
20422
+ "data-slot": "composer-input-shell",
20423
+ "data-layout": isComposerStacked ? "stacked" : "inline",
20424
+ className: cn(
20425
+ "relative flex flex-1 overflow-hidden",
20426
+ "bg-background border border-border shadow-sm",
20427
+ isComposerStacked ? "min-h-[5.5rem] px-1.5 pt-1.5 pb-12" : "min-h-12 px-1.5 py-1",
20428
+ "focus-within:border-muted-foreground/30 focus-within:shadow-md",
20429
+ "transition-[min-height,padding,border-radius,box-shadow,border-color] duration-300 ease-[cubic-bezier(0.2,0.8,0.2,1)]",
20430
+ composerInputRoundedClass
20431
+ ),
20432
+ children: [
20433
+ /* @__PURE__ */ jsx58(
20434
+ "div",
20435
+ {
20436
+ ref: composerInputRef,
20437
+ role: "textbox",
20438
+ "aria-multiline": "true",
20439
+ "aria-disabled": missingConfig || isHistoryLoading || hasPendingInteractiveRequest,
20440
+ contentEditable: !(missingConfig || isHistoryLoading || hasPendingInteractiveRequest),
20441
+ suppressContentEditableWarning: true,
20442
+ onInput: handleComposerInput,
20443
+ onCompositionEnd: handleComposerCompositionEnd,
20444
+ onSelect: handleComposerSelect,
20445
+ onPaste: handleComposerPaste,
20446
+ onKeyDown: handleComposerKeyDown,
20447
+ "data-placeholder": inputPlaceholder,
20448
+ className: cn(
20449
+ "min-h-8 max-h-32 w-full overflow-hidden whitespace-pre-wrap break-words bg-transparent text-sm leading-5 text-foreground outline-none transition-[padding,min-height] duration-300 ease-[cubic-bezier(0.2,0.8,0.2,1)]",
20450
+ isComposerStacked ? "px-2 py-1.5" : "py-1 pr-11 pl-11 mt-1",
20451
+ "empty:before:pointer-events-none empty:before:text-muted-foreground empty:before:content-[attr(data-placeholder)]",
20452
+ (missingConfig || isHistoryLoading || hasPendingInteractiveRequest) && "cursor-not-allowed opacity-50"
20453
+ ),
20454
+ children: renderedComposerParts.map(
20455
+ (part, index) => part.type === "text" ? /* @__PURE__ */ jsx58(React54.Fragment, { children: part.text }, `text-${index}`) : /* @__PURE__ */ jsx58(ComposerCapabilityToken, { part }, part.key)
20456
+ )
20457
+ },
20458
+ composerDomVersion
20459
+ ),
20460
+ /* @__PURE__ */ jsxs40(
20461
+ "div",
20462
+ {
20463
+ "data-slot": "composer-action-bar",
20464
+ className: "pointer-events-none absolute inset-x-1.5 bottom-1 flex min-h-10 items-center justify-between gap-2",
20465
+ children: [
20466
+ /* @__PURE__ */ jsxs40("div", { className: "pointer-events-none flex min-w-0 flex-1 items-center gap-1.5", children: [
20467
+ /* @__PURE__ */ jsx58("div", { className: "pointer-events-auto flex shrink-0 items-center gap-1.5", children: /* @__PURE__ */ jsx58(
20468
+ ComposerMenu,
20469
+ {
20470
+ composer,
20471
+ onAttachmentClick: handleAttachmentClick,
20472
+ onToolSelect: handleToolSelect,
20473
+ selectedTool,
20474
+ planModeEnabled,
20475
+ onPlanModeChange: setPlanModeEnabled,
20476
+ goalCommandAvailable,
20477
+ goalPanelOpen: isGoalModeOpen,
20478
+ onGoalPanelOpenChange: handleGoalPanelOpenChange,
20479
+ runtimeCapabilities: runtimeCapabilitiesReady ? runtimeCapabilities : null,
20480
+ selectedRuntimeCapabilities: effectiveSessionRuntimeCapabilities,
20481
+ onRuntimeCapabilityToggle: handleSessionRuntimeCapabilityToggle,
20482
+ disabled: missingConfig || isHistoryLoading || hasPendingInteractiveRequest
20483
+ }
20484
+ ) }),
20485
+ selectedTool && /* @__PURE__ */ jsxs40("span", { className: "pointer-events-auto inline-flex h-8 min-w-0 max-w-[14rem] shrink items-center gap-1.5 rounded-full bg-primary/10 px-2 text-xs font-medium text-primary transition-all duration-200", children: [
20486
+ /* @__PURE__ */ jsx58("span", { className: "truncate", children: selectedTool.shortLabel ?? selectedTool.label }),
20487
+ /* @__PURE__ */ jsx58(
20488
+ "button",
20489
+ {
20490
+ type: "button",
20491
+ onClick: () => setSelectedTool(null),
20492
+ className: "shrink-0 rounded-full p-0.5 text-primary/70 hover:bg-primary/10 hover:text-primary",
20493
+ children: /* @__PURE__ */ jsx58(X7, { size: 12 })
20494
+ }
20495
+ )
20496
+ ] })
20497
+ ] }),
20498
+ /* @__PURE__ */ jsx58("div", { className: "pointer-events-auto shrink-0", children: /* @__PURE__ */ jsx58(
20499
+ SendButton,
20500
+ {
20501
+ disabled: isSendDisabled,
20502
+ isLoading: stream.isLoading,
20503
+ showStop: stream.isLoading && (!trimmedDraft || hasPendingInteractiveRequest),
20504
+ onStop: () => stream.stop(),
20505
+ stopLabel: t("chat.stop"),
20506
+ sendLabel: t("chat.send"),
20507
+ shortcuts: stream.isLoading && trimmedDraft ? [
20508
+ {
20509
+ label: t("chat.followUps.queue"),
20510
+ keys: "Enter"
20511
+ }
20512
+ ] : void 0
20513
+ }
20514
+ ) })
20515
+ ]
19042
20516
  }
19043
- ) })
20517
+ )
19044
20518
  ]
19045
20519
  }
19046
- )
20520
+ ) }),
20521
+ disclaimer?.text && /* @__PURE__ */ jsx58(
20522
+ "p",
20523
+ {
20524
+ className: cn(
20525
+ "mt-2 text-center text-xs",
20526
+ disclaimer.highContrast ? "text-foreground" : "text-muted-foreground"
20527
+ ),
20528
+ children: disclaimer.text
20529
+ }
20530
+ ),
20531
+ /* @__PURE__ */ jsxs40("div", { className: "mt-2 flex items-center justify-center gap-2 text-xs text-muted-foreground", children: [
20532
+ /* @__PURE__ */ jsx58("span", { children: t("chat.poweredBy") }),
20533
+ /* @__PURE__ */ jsx58(ContextUsageIndicator, { className: "absolute right-4" })
20534
+ ] })
19047
20535
  ]
19048
20536
  }
19049
- ) }),
19050
- disclaimer?.text && /* @__PURE__ */ jsx57(
19051
- "p",
20537
+ ),
20538
+ /* @__PURE__ */ jsx58(
20539
+ SettingsSheet,
19052
20540
  {
19053
- className: cn(
19054
- "mt-2 text-center text-xs",
19055
- disclaimer.highContrast ? "text-foreground" : "text-muted-foreground"
19056
- ),
19057
- children: disclaimer.text
20541
+ open: petSettingsOpen,
20542
+ settings: displayedPetSettings,
20543
+ petRequired,
20544
+ onOpenChange: setPetSettingsOpen,
20545
+ onSave: savePetLocalSettings
19058
20546
  }
19059
20547
  ),
19060
- /* @__PURE__ */ jsxs39("div", { className: "mt-2 flex items-center justify-center gap-2 text-xs text-muted-foreground", children: [
19061
- /* @__PURE__ */ jsx57("span", { children: t("chat.poweredBy") }),
19062
- /* @__PURE__ */ jsx57(ContextUsageIndicator, { className: "absolute right-4" })
19063
- ] })
20548
+ /* @__PURE__ */ jsx58(PetBridge, { pet: effectivePet, state: petAutoState })
19064
20549
  ]
19065
20550
  }
19066
20551
  ),
19067
- /* @__PURE__ */ jsx57(
19068
- SettingsSheet,
20552
+ taskSummaryAvailable && taskSummaryDocked && taskSummaryOpen && /* @__PURE__ */ jsx58("div", { className: "pointer-events-none absolute right-5 top-3 z-20 max-h-[calc(100%-1.5rem)] w-80", children: /* @__PURE__ */ jsx58(
20553
+ TaskSummaryPanel,
19069
20554
  {
19070
- open: petSettingsOpen,
19071
- settings: displayedPetSettings,
19072
- petRequired,
19073
- onOpenChange: setPetSettingsOpen,
19074
- onSave: savePetLocalSettings
20555
+ ...taskSummaryProps,
20556
+ className: "pointer-events-auto max-h-full"
19075
20557
  }
19076
- ),
19077
- /* @__PURE__ */ jsx57(PetBridge, { pet: effectivePet, state: petAutoState })
20558
+ ) })
19078
20559
  ]
19079
20560
  }
19080
20561
  );
19081
20562
  }
19082
20563
 
19083
20564
  // src/components/ui/separator.tsx
19084
- import * as React53 from "react";
19085
- import { jsx as jsx58 } from "react/jsx-runtime";
19086
- var Separator = React53.forwardRef(
19087
- ({ className, orientation = "horizontal", ...props }, ref) => /* @__PURE__ */ jsx58(
20565
+ import * as React55 from "react";
20566
+ import { jsx as jsx59 } from "react/jsx-runtime";
20567
+ var Separator = React55.forwardRef(
20568
+ ({ className, orientation = "horizontal", ...props }, ref) => /* @__PURE__ */ jsx59(
19088
20569
  "div",
19089
20570
  {
19090
20571
  ref,