opencami 1.0.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -3
- package/dist/client/analytics-dashboard.html +509 -0
- package/dist/client/analytics.json +598 -0
- package/dist/client/assets/_sessionKey-xUqdePGW.js +97 -0
- package/dist/client/assets/agents-BiadNAEz.js +2 -0
- package/dist/client/assets/agents-screen-C5TPJbry.js +1 -0
- package/dist/client/assets/button-seqh98ae.js +1 -0
- package/dist/client/assets/{connect-BRasuRbB.js → connect-DlVsi-ya.js} +2 -2
- package/dist/client/assets/file-explorer-screen-B0hwrjdF.js +1 -0
- package/dist/client/assets/files-dkr2U72N.js +2 -0
- package/dist/client/assets/index-CwoJpeG1.js +153 -0
- package/dist/client/assets/{index-DHGnKfAU.js → index-D1Et4XlM.js} +1 -1
- package/dist/client/assets/keyboard-shortcuts-dialog-zdnAmDiH.js +1 -0
- package/dist/client/assets/{main-BAHT5yqU.js → main-DOBfHXDF.js} +12 -12
- package/dist/client/assets/opencami-logo-Bxp_4d3X.js +1 -0
- package/dist/client/assets/react-DD8SkMJn.js +1 -0
- package/dist/client/assets/search-dialog-Ck1AQreu.js +1 -0
- package/dist/client/assets/session-export-dialog-Bh3zH4nZ.js +1 -0
- package/dist/client/assets/settings-dialog-CvUsgnnZ.js +1 -0
- package/dist/client/assets/styles-DogPvrGY.css +1 -0
- package/dist/client/assets/switch-BoGcWcnr.js +1 -0
- package/dist/client/assets/use-file-explorer-state-B5JLNsSa.js +12 -0
- package/dist/client/assets/useButton-csSB2uQJ.js +9 -0
- package/dist/client/manifest.json +8 -2
- package/dist/server/assets/{_sessionKey-qlAPF_Ft.js → _sessionKey-DQwkBUS7.js} +981 -229
- package/dist/server/assets/_tanstack-start-manifest_v-cW8K1Mnv.js +4 -0
- package/dist/server/assets/agents-Dz_i76VW.js +11 -0
- package/dist/server/assets/agents-screen-CqQPJndp.js +587 -0
- package/dist/server/assets/{connect-BWI_6rCm.js → connect-CIDOw12K.js} +34 -2
- package/dist/server/assets/{file-explorer-screen-DJXPEG_J.js → file-explorer-screen-BzvgvV8m.js} +7 -58
- package/dist/server/assets/{files-CONoVTGD.js → files-BxvRDIWU.js} +1 -1
- package/dist/server/assets/{index-Bp8QskbI.js → index-BwD7ufHE.js} +4 -3
- package/dist/server/assets/{index-COu2idHm.js → index-CmbNTqa2.js} +105 -14
- package/dist/server/assets/{keyboard-shortcuts-dialog-D5hqVX2v.js → keyboard-shortcuts-dialog-7OEtXUlW.js} +2 -2
- package/dist/server/assets/opencami-logo-C-43FL3R.js +24 -0
- package/dist/server/assets/{router-DbxyvprK.js → router-5qObg5aX.js} +368 -74
- package/dist/server/assets/{search-dialog-JY8C3mqa.js → search-dialog-BE2ZBkj0.js} +44 -12
- package/dist/server/assets/{session-export-dialog-D87uafPD.js → session-export-dialog-DRVbC8Q-.js} +2 -2
- package/dist/server/assets/{settings-dialog-CBj7njLM.js → settings-dialog-BBQcU55J.js} +204 -41
- package/dist/server/assets/switch-DnX0MjGS.js +28 -0
- package/dist/server/assets/tooltip-gbV6rEVv.js +60 -0
- package/dist/server/assets/{menu-D6n4DB0U.js → use-file-explorer-state-DMHdtb7D.js} +56 -57
- package/dist/server/server.js +2 -2
- package/package.json +1 -1
- package/dist/client/assets/_sessionKey-B-MBYHgD.js +0 -95
- package/dist/client/assets/abap-BdImnpbu.js +0 -1
- package/dist/client/assets/actionscript-3-CfeIJUat.js +0 -1
- package/dist/client/assets/ada-bCR0ucgS.js +0 -1
- package/dist/client/assets/andromeeda-C-Jbm3Hp.js +0 -1
- package/dist/client/assets/angular-html-CU67Zn6k.js +0 -1
- package/dist/client/assets/angular-ts-BwZT4LLn.js +0 -1
- package/dist/client/assets/apache-Pmp26Uib.js +0 -1
- package/dist/client/assets/apex-D8_7TLub.js +0 -1
- package/dist/client/assets/apl-dKokRX4l.js +0 -1
- package/dist/client/assets/applescript-Co6uUVPk.js +0 -1
- package/dist/client/assets/ara-BRHolxvo.js +0 -1
- package/dist/client/assets/asciidoc-Dv7Oe6Be.js +0 -1
- package/dist/client/assets/asm-D_Q5rh1f.js +0 -1
- package/dist/client/assets/astro-CbQHKStN.js +0 -1
- package/dist/client/assets/aurora-x-D-2ljcwZ.js +0 -1
- package/dist/client/assets/awk-DMzUqQB5.js +0 -1
- package/dist/client/assets/ayu-dark-CmMr59Fi.js +0 -1
- package/dist/client/assets/ballerina-BFfxhgS-.js +0 -1
- package/dist/client/assets/bat-BkioyH1T.js +0 -1
- package/dist/client/assets/beancount-k_qm7-4y.js +0 -1
- package/dist/client/assets/berry-uYugtg8r.js +0 -1
- package/dist/client/assets/bibtex-CHM0blh-.js +0 -1
- package/dist/client/assets/bicep-Bmn6On1c.js +0 -1
- package/dist/client/assets/blade-D4QpJJKB.js +0 -1
- package/dist/client/assets/bsl-BO_Y6i37.js +0 -1
- package/dist/client/assets/button-D_9OBT_f.js +0 -1
- package/dist/client/assets/c-BIGW1oBm.js +0 -1
- package/dist/client/assets/c3-VCDPK7BO.js +0 -1
- package/dist/client/assets/cadence-Bv_4Rxtq.js +0 -1
- package/dist/client/assets/cairo-KRGpt6FW.js +0 -1
- package/dist/client/assets/catppuccin-frappe-DFWUc33u.js +0 -1
- package/dist/client/assets/catppuccin-latte-C9dUb6Cb.js +0 -1
- package/dist/client/assets/catppuccin-macchiato-DQyhUUbL.js +0 -1
- package/dist/client/assets/catppuccin-mocha-D87Tk5Gz.js +0 -1
- package/dist/client/assets/clarity-D53aC0YG.js +0 -1
- package/dist/client/assets/clojure-P80f7IUj.js +0 -1
- package/dist/client/assets/cmake-D1j8_8rp.js +0 -1
- package/dist/client/assets/cobol-nwyudZeR.js +0 -1
- package/dist/client/assets/codeowners-Bp6g37R7.js +0 -1
- package/dist/client/assets/codeql-DsOJ9woJ.js +0 -1
- package/dist/client/assets/coffee-Ch7k5sss.js +0 -1
- package/dist/client/assets/common-lisp-Cg-RD9OK.js +0 -1
- package/dist/client/assets/coq-DkFqJrB1.js +0 -1
- package/dist/client/assets/cpp-CofmeUqb.js +0 -1
- package/dist/client/assets/crystal-tKQVLTB8.js +0 -1
- package/dist/client/assets/csharp-K5feNrxe.js +0 -1
- package/dist/client/assets/css-DPfMkruS.js +0 -1
- package/dist/client/assets/csv-fuZLfV_i.js +0 -1
- package/dist/client/assets/cue-D82EKSYY.js +0 -1
- package/dist/client/assets/cypher-COkxafJQ.js +0 -1
- package/dist/client/assets/d-85-TOEBH.js +0 -1
- package/dist/client/assets/dark-plus-C3mMm8J8.js +0 -1
- package/dist/client/assets/dart-CF10PKvl.js +0 -1
- package/dist/client/assets/dax-CEL-wOlO.js +0 -1
- package/dist/client/assets/desktop-BmXAJ9_W.js +0 -1
- package/dist/client/assets/diff-D97Zzqfu.js +0 -1
- package/dist/client/assets/docker-BcOcwvcX.js +0 -1
- package/dist/client/assets/dotenv-Da5cRb03.js +0 -1
- package/dist/client/assets/dracula-BzJJZx-M.js +0 -1
- package/dist/client/assets/dracula-soft-BXkSAIEj.js +0 -1
- package/dist/client/assets/dream-maker-BtqSS_iP.js +0 -1
- package/dist/client/assets/edge-BkV0erSs.js +0 -1
- package/dist/client/assets/elixir-CDX3lj18.js +0 -1
- package/dist/client/assets/elm-DbKCFpqz.js +0 -1
- package/dist/client/assets/emacs-lisp-C9XAeP06.js +0 -1
- package/dist/client/assets/erb-BOJIQeun.js +0 -1
- package/dist/client/assets/erlang-DsQrWhSR.js +0 -1
- package/dist/client/assets/everforest-dark-BgDCqdQA.js +0 -1
- package/dist/client/assets/everforest-light-C8M2exoo.js +0 -1
- package/dist/client/assets/fennel-BYunw83y.js +0 -1
- package/dist/client/assets/file-explorer-screen-Daf4rIq9.js +0 -1
- package/dist/client/assets/files-ByeIMLfw.js +0 -2
- package/dist/client/assets/fish-BvzEVeQv.js +0 -1
- package/dist/client/assets/fluent-C4IJs8-o.js +0 -1
- package/dist/client/assets/fortran-fixed-form-CkoXwp7k.js +0 -1
- package/dist/client/assets/fortran-free-form-BxgE0vQu.js +0 -1
- package/dist/client/assets/fsharp-CXgrBDvD.js +0 -1
- package/dist/client/assets/gdresource-B7Tvp0Sc.js +0 -1
- package/dist/client/assets/gdscript-DTMYz4Jt.js +0 -1
- package/dist/client/assets/gdshader-DkwncUOv.js +0 -1
- package/dist/client/assets/genie-D0YGMca9.js +0 -1
- package/dist/client/assets/gherkin-DyxjwDmM.js +0 -1
- package/dist/client/assets/git-commit-F4YmCXRG.js +0 -1
- package/dist/client/assets/git-rebase-r7XF79zn.js +0 -1
- package/dist/client/assets/github-dark-DHJKELXO.js +0 -1
- package/dist/client/assets/github-dark-default-Cuk6v7N8.js +0 -1
- package/dist/client/assets/github-dark-dimmed-DH5Ifo-i.js +0 -1
- package/dist/client/assets/github-dark-high-contrast-E3gJ1_iC.js +0 -1
- package/dist/client/assets/github-light-DAi9KRSo.js +0 -1
- package/dist/client/assets/github-light-default-D7oLnXFd.js +0 -1
- package/dist/client/assets/github-light-high-contrast-BfjtVDDH.js +0 -1
- package/dist/client/assets/gleam-BspZqrRM.js +0 -1
- package/dist/client/assets/glimmer-js-Rg0-pVw9.js +0 -1
- package/dist/client/assets/glimmer-ts-U6CK756n.js +0 -1
- package/dist/client/assets/glsl-DplSGwfg.js +0 -1
- package/dist/client/assets/gn-n2N0HUVH.js +0 -1
- package/dist/client/assets/gnuplot-DdkO51Og.js +0 -1
- package/dist/client/assets/go-Dn2_MT6a.js +0 -1
- package/dist/client/assets/graphql-ChdNCCLP.js +0 -1
- package/dist/client/assets/groovy-gcz8RCvz.js +0 -1
- package/dist/client/assets/gruvbox-dark-hard-CFHQjOhq.js +0 -1
- package/dist/client/assets/gruvbox-dark-medium-GsRaNv29.js +0 -1
- package/dist/client/assets/gruvbox-dark-soft-CVdnzihN.js +0 -1
- package/dist/client/assets/gruvbox-light-hard-CH1njM8p.js +0 -1
- package/dist/client/assets/gruvbox-light-medium-DRw_LuNl.js +0 -1
- package/dist/client/assets/gruvbox-light-soft-hJgmCMqR.js +0 -1
- package/dist/client/assets/hack-CaT9iCJl.js +0 -1
- package/dist/client/assets/haml-B8DHNrY2.js +0 -1
- package/dist/client/assets/handlebars-BL8al0AC.js +0 -1
- package/dist/client/assets/haskell-Df6bDoY_.js +0 -1
- package/dist/client/assets/haxe-CzTSHFRz.js +0 -1
- package/dist/client/assets/hcl-BWvSN4gD.js +0 -1
- package/dist/client/assets/hjson-D5-asLiD.js +0 -1
- package/dist/client/assets/hlsl-D3lLCCz7.js +0 -1
- package/dist/client/assets/houston-DnULxvSX.js +0 -1
- package/dist/client/assets/html-GMplVEZG.js +0 -1
- package/dist/client/assets/html-derivative-BFtXZ54Q.js +0 -1
- package/dist/client/assets/http-jrhK8wxY.js +0 -1
- package/dist/client/assets/hurl-irOxFIW8.js +0 -1
- package/dist/client/assets/hxml-Bvhsp5Yf.js +0 -1
- package/dist/client/assets/hy-DFXneXwc.js +0 -1
- package/dist/client/assets/imba-DGztddWO.js +0 -1
- package/dist/client/assets/index-ByUDBI-n.js +0 -14
- package/dist/client/assets/ini-BEwlwnbL.js +0 -1
- package/dist/client/assets/java-CylS5w8V.js +0 -1
- package/dist/client/assets/javascript-wDzz0qaB.js +0 -1
- package/dist/client/assets/jinja-4LBKfQ-Z.js +0 -1
- package/dist/client/assets/jison-wvAkD_A8.js +0 -1
- package/dist/client/assets/json-Cp-IABpG.js +0 -1
- package/dist/client/assets/json5-C9tS-k6U.js +0 -1
- package/dist/client/assets/jsonc-Des-eS-w.js +0 -1
- package/dist/client/assets/jsonl-DcaNXYhu.js +0 -1
- package/dist/client/assets/jsonnet-DFQXde-d.js +0 -1
- package/dist/client/assets/jssm-C2t-YnRu.js +0 -1
- package/dist/client/assets/jsx-g9-lgVsj.js +0 -1
- package/dist/client/assets/julia-CxzCAyBv.js +0 -1
- package/dist/client/assets/kanagawa-dragon-CkXjmgJE.js +0 -1
- package/dist/client/assets/kanagawa-lotus-CfQXZHmo.js +0 -1
- package/dist/client/assets/kanagawa-wave-DWedfzmr.js +0 -1
- package/dist/client/assets/kdl-DV7GczEv.js +0 -1
- package/dist/client/assets/keyboard-shortcuts-dialog-agsWJ36q.js +0 -1
- package/dist/client/assets/kotlin-BdnUsdx6.js +0 -1
- package/dist/client/assets/kusto-DZf3V79B.js +0 -1
- package/dist/client/assets/laserwave-DUszq2jm.js +0 -1
- package/dist/client/assets/latex-B4uzh10-.js +0 -1
- package/dist/client/assets/lean-BZvkOJ9d.js +0 -1
- package/dist/client/assets/less-B1dDrJ26.js +0 -1
- package/dist/client/assets/light-plus-B7mTdjB0.js +0 -1
- package/dist/client/assets/liquid-DYVedYrR.js +0 -1
- package/dist/client/assets/llvm-BtvRca6l.js +0 -1
- package/dist/client/assets/log-2UxHyX5q.js +0 -1
- package/dist/client/assets/logo-BtOb2qkB.js +0 -1
- package/dist/client/assets/lua-BbnMAYS6.js +0 -1
- package/dist/client/assets/luau-C-HG3fhB.js +0 -1
- package/dist/client/assets/make-CHLpvVh8.js +0 -1
- package/dist/client/assets/markdown-Cvjx9yec.js +0 -1
- package/dist/client/assets/marko-DZsq8hO1.js +0 -1
- package/dist/client/assets/material-theme-D5KoaKCx.js +0 -1
- package/dist/client/assets/material-theme-darker-BfHTSMKl.js +0 -1
- package/dist/client/assets/material-theme-lighter-B0m2ddpp.js +0 -1
- package/dist/client/assets/material-theme-ocean-CyktbL80.js +0 -1
- package/dist/client/assets/material-theme-palenight-Csfq5Kiy.js +0 -1
- package/dist/client/assets/matlab-D7o27uSR.js +0 -1
- package/dist/client/assets/mdc-DUICxH0z.js +0 -1
- package/dist/client/assets/mdx-Cmh6b_Ma.js +0 -1
- package/dist/client/assets/menu-BhVaz8Ly.js +0 -20
- package/dist/client/assets/mermaid-mWjccvbQ.js +0 -1
- package/dist/client/assets/min-dark-CafNBF8u.js +0 -1
- package/dist/client/assets/min-light-CTRr51gU.js +0 -1
- package/dist/client/assets/mipsasm-CKIfxQSi.js +0 -1
- package/dist/client/assets/mojo-B93PlW-d.js +0 -1
- package/dist/client/assets/monokai-D4h5O-jR.js +0 -1
- package/dist/client/assets/moonbit-Ba13S78F.js +0 -1
- package/dist/client/assets/move-Bu9oaDYs.js +0 -1
- package/dist/client/assets/narrat-DRg8JJMk.js +0 -1
- package/dist/client/assets/nextflow-BrzmwbiE.js +0 -1
- package/dist/client/assets/nginx-DknmC5AR.js +0 -1
- package/dist/client/assets/night-owl-C39BiMTA.js +0 -1
- package/dist/client/assets/nim-CVrawwO9.js +0 -1
- package/dist/client/assets/nix-CwoSXNpI.js +0 -1
- package/dist/client/assets/nord-Ddv68eIx.js +0 -1
- package/dist/client/assets/nushell-C-sUppwS.js +0 -1
- package/dist/client/assets/objective-c-DXmwc3jG.js +0 -1
- package/dist/client/assets/objective-cpp-CLxacb5B.js +0 -1
- package/dist/client/assets/ocaml-C0hk2d4L.js +0 -1
- package/dist/client/assets/one-dark-pro-DVMEJ2y_.js +0 -1
- package/dist/client/assets/one-light-PoHY5YXO.js +0 -1
- package/dist/client/assets/openscad-C4EeE6gA.js +0 -1
- package/dist/client/assets/pascal-D93ZcfNL.js +0 -1
- package/dist/client/assets/perl-C0TMdlhV.js +0 -1
- package/dist/client/assets/php-CDn_0X-4.js +0 -1
- package/dist/client/assets/pkl-u5AG7uiY.js +0 -1
- package/dist/client/assets/plastic-3e1v2bzS.js +0 -1
- package/dist/client/assets/plsql-ChMvpjG-.js +0 -1
- package/dist/client/assets/po-BTJTHyun.js +0 -1
- package/dist/client/assets/poimandres-CS3Unz2-.js +0 -1
- package/dist/client/assets/polar-C0HS_06l.js +0 -1
- package/dist/client/assets/postcss-CXtECtnM.js +0 -1
- package/dist/client/assets/powerquery-CEu0bR-o.js +0 -1
- package/dist/client/assets/powershell-Dpen1YoG.js +0 -1
- package/dist/client/assets/prisma-Dd19v3D-.js +0 -1
- package/dist/client/assets/prolog-CbFg5uaA.js +0 -1
- package/dist/client/assets/proto-C7zT0LnQ.js +0 -1
- package/dist/client/assets/pug-CGlum2m_.js +0 -1
- package/dist/client/assets/puppet-BMWR74SV.js +0 -1
- package/dist/client/assets/purescript-CklMAg4u.js +0 -1
- package/dist/client/assets/python-B6aJPvgy.js +0 -1
- package/dist/client/assets/qml-3beO22l8.js +0 -1
- package/dist/client/assets/qmldir-C8lEn-DE.js +0 -1
- package/dist/client/assets/qss-IeuSbFQv.js +0 -1
- package/dist/client/assets/r-Dspwwk_N.js +0 -1
- package/dist/client/assets/racket-BqYA7rlc.js +0 -1
- package/dist/client/assets/raku-DXvB9xmW.js +0 -1
- package/dist/client/assets/razor-C1TweQQi.js +0 -1
- package/dist/client/assets/red-bN70gL4F.js +0 -1
- package/dist/client/assets/reg-C-SQnVFl.js +0 -1
- package/dist/client/assets/regexp-CDVJQ6XC.js +0 -1
- package/dist/client/assets/rel-C3B-1QV4.js +0 -1
- package/dist/client/assets/riscv-BM1_JUlF.js +0 -1
- package/dist/client/assets/rose-pine-dawn-DHQR4-dF.js +0 -1
- package/dist/client/assets/rose-pine-moon-D4_iv3hh.js +0 -1
- package/dist/client/assets/rose-pine-qdsjHGoJ.js +0 -1
- package/dist/client/assets/rosmsg-BJDFO7_C.js +0 -1
- package/dist/client/assets/rst-B0xPkSld.js +0 -1
- package/dist/client/assets/ruby-BvKwtOVI.js +0 -1
- package/dist/client/assets/rust-B1yitclQ.js +0 -1
- package/dist/client/assets/sas-cz2c8ADy.js +0 -1
- package/dist/client/assets/sass-Cj5Yp3dK.js +0 -1
- package/dist/client/assets/scala-C151Ov-r.js +0 -1
- package/dist/client/assets/scheme-C98Dy4si.js +0 -1
- package/dist/client/assets/scss-OYdSNvt2.js +0 -1
- package/dist/client/assets/sdbl-DVxCFoDh.js +0 -1
- package/dist/client/assets/search-dialog-CHwnOyPS.js +0 -1
- package/dist/client/assets/session-export-dialog-uOlDUzgX.js +0 -1
- package/dist/client/assets/settings-dialog-D0aYDkAM.js +0 -1
- package/dist/client/assets/shaderlab-Dg9Lc6iA.js +0 -1
- package/dist/client/assets/shellscript-Yzrsuije.js +0 -1
- package/dist/client/assets/shellsession-BADoaaVG.js +0 -1
- package/dist/client/assets/slack-dark-BthQWCQV.js +0 -1
- package/dist/client/assets/slack-ochin-DqwNpetd.js +0 -1
- package/dist/client/assets/smalltalk-BERRCDM3.js +0 -1
- package/dist/client/assets/snazzy-light-Bw305WKR.js +0 -1
- package/dist/client/assets/solarized-dark-DXbdFlpD.js +0 -1
- package/dist/client/assets/solarized-light-L9t79GZl.js +0 -1
- package/dist/client/assets/solidity-rGO070M0.js +0 -1
- package/dist/client/assets/soy-Brmx7dQM.js +0 -1
- package/dist/client/assets/sparql-rVzFXLq3.js +0 -1
- package/dist/client/assets/splunk-BtCnVYZw.js +0 -1
- package/dist/client/assets/sql-BLtJtn59.js +0 -1
- package/dist/client/assets/ssh-config-_ykCGR6B.js +0 -1
- package/dist/client/assets/stata-BH5u7GGu.js +0 -1
- package/dist/client/assets/styles-7aVSlb6l.css +0 -1
- package/dist/client/assets/stylus-BEDo0Tqx.js +0 -1
- package/dist/client/assets/svelte-zxCyuUbr.js +0 -1
- package/dist/client/assets/swift-Dg5xB15N.js +0 -1
- package/dist/client/assets/synthwave-84-CbfX1IO0.js +0 -1
- package/dist/client/assets/system-verilog-CnnmHF94.js +0 -1
- package/dist/client/assets/systemd-4A_iFExJ.js +0 -1
- package/dist/client/assets/talonscript-CkByrt1z.js +0 -1
- package/dist/client/assets/tasl-QIJgUcNo.js +0 -1
- package/dist/client/assets/tcl-dwOrl1Do.js +0 -1
- package/dist/client/assets/templ-W15q3VgB.js +0 -1
- package/dist/client/assets/terraform-BETggiCN.js +0 -1
- package/dist/client/assets/tex-CvyZ59Mk.js +0 -1
- package/dist/client/assets/tokyo-night-hegEt444.js +0 -1
- package/dist/client/assets/toml-vGWfd6FD.js +0 -1
- package/dist/client/assets/ts-tags-zn1MmPIZ.js +0 -1
- package/dist/client/assets/tsv-B_m7g4N7.js +0 -1
- package/dist/client/assets/tsx-COt5Ahok.js +0 -1
- package/dist/client/assets/turtle-BsS91CYL.js +0 -1
- package/dist/client/assets/twig-CO9l9SDP.js +0 -1
- package/dist/client/assets/typescript-BPQ3VLAy.js +0 -1
- package/dist/client/assets/typespec-BGHnOYBU.js +0 -1
- package/dist/client/assets/typst-DHCkPAjA.js +0 -1
- package/dist/client/assets/v-BcVCzyr7.js +0 -1
- package/dist/client/assets/vala-CsfeWuGM.js +0 -1
- package/dist/client/assets/vb-D17OF-Vu.js +0 -1
- package/dist/client/assets/verilog-BQ8w6xss.js +0 -1
- package/dist/client/assets/vesper-DU1UobuO.js +0 -1
- package/dist/client/assets/vhdl-CeAyd5Ju.js +0 -1
- package/dist/client/assets/viml-CJc9bBzg.js +0 -1
- package/dist/client/assets/vitesse-black-Bkuqu6BP.js +0 -1
- package/dist/client/assets/vitesse-dark-D0r3Knsf.js +0 -1
- package/dist/client/assets/vitesse-light-CVO1_9PV.js +0 -1
- package/dist/client/assets/vue-DN_0RTcg.js +0 -1
- package/dist/client/assets/vue-html-AaS7Mt5G.js +0 -1
- package/dist/client/assets/vue-vine-CQOfvN7w.js +0 -1
- package/dist/client/assets/vyper-CDx5xZoG.js +0 -1
- package/dist/client/assets/wasm-CG6Dc4jp.js +0 -1
- package/dist/client/assets/wasm-MzD3tlZU.js +0 -1
- package/dist/client/assets/wenyan-BV7otONQ.js +0 -1
- package/dist/client/assets/wgsl-Dx-B1_4e.js +0 -1
- package/dist/client/assets/wikitext-BhOHFoWU.js +0 -1
- package/dist/client/assets/wit-5i3qLPDT.js +0 -1
- package/dist/client/assets/wolfram-lXgVvXCa.js +0 -1
- package/dist/client/assets/xml-sdJ4AIDG.js +0 -1
- package/dist/client/assets/xsl-CtQFsRM5.js +0 -1
- package/dist/client/assets/yaml-Buea-lGh.js +0 -1
- package/dist/client/assets/zenscript-DVFEvuxE.js +0 -1
- package/dist/client/assets/zig-VOosw3JB.js +0 -1
- package/dist/server/assets/_tanstack-start-manifest_v-El8F-kd-.js +0 -4
|
@@ -3,23 +3,25 @@ import { Link, useNavigate } from "@tanstack/react-router";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import React__default, { memo, useDeferredValue, useState, useMemo, useCallback, Suspense, lazy, useRef, useEffect, useId, useLayoutEffect, createContext, useContext } from "react";
|
|
5
5
|
import { useQueryClient, useMutation, useQuery } from "@tanstack/react-query";
|
|
6
|
-
import {
|
|
6
|
+
import { T as TooltipProvider, a as TooltipRoot, b as TooltipTrigger, c as TooltipContent, s as setChatUiState, d as chatUiQueryKey, g as getChatUiState } from "./tooltip-gbV6rEVv.js";
|
|
7
7
|
import { HugeiconsIcon } from "@hugeicons/react";
|
|
8
|
-
import { MoreHorizontalIcon, Pen01Icon, Upload01Icon, Delete01Icon, ArrowRight01Icon, SidebarLeft01Icon, PencilEdit02Icon, Folder01Icon, Search01Icon, Settings01Icon, Menu01Icon, Tick02Icon, Copy01Icon, Loading02Icon, StopIcon, VolumeHighIcon, ArrowDown01Icon, Loading03Icon, ArtificialIntelligence02Icon, CommandIcon,
|
|
8
|
+
import { Tick01Icon, Cancel01Icon, MoreHorizontalIcon, Pen01Icon, Upload01Icon, Delete01Icon, BotIcon, Clock01Icon, Chat01Icon, ArrowRight01Icon, SidebarLeft01Icon, PencilEdit02Icon, Folder01Icon, AiBrain01Icon, Search01Icon, Settings01Icon, Menu01Icon, Tick02Icon, Copy01Icon, Loading02Icon, StopIcon, VolumeHighIcon, ArrowDown01Icon, Loading03Icon, ArtificialIntelligence02Icon, CommandIcon, Attachment01Icon, File01Icon, Mic02Icon, ArrowUp02Icon } from "@hugeicons/core-free-icons";
|
|
9
9
|
import { motion, AnimatePresence } from "motion/react";
|
|
10
|
+
import { D as DialogRoot, a as DialogContent, b as DialogTitle, c as DialogDescription, d as DialogClose, M as MenuRoot, e as MenuTrigger, f as MenuContent, g as MenuItem, u as useFileExplorerState } from "./use-file-explorer-state-DMHdtb7D.js";
|
|
10
11
|
import { B as Button, c as cn, b as buttonVariants } from "./button-DtQ3rV1m.js";
|
|
11
12
|
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
12
13
|
import { Collapsible as Collapsible$1 } from "@base-ui/react/collapsible";
|
|
13
14
|
import { ScrollArea } from "@base-ui/react/scroll-area";
|
|
15
|
+
import { O as OpenCamiLogo, a as OpenCamiText } from "./opencami-logo-C-43FL3R.js";
|
|
14
16
|
import { marked } from "marked";
|
|
15
17
|
import ReactMarkdown from "react-markdown";
|
|
16
18
|
import remarkBreaks from "remark-breaks";
|
|
17
19
|
import remarkGfm from "remark-gfm";
|
|
18
|
-
import { C as CodeBlock,
|
|
20
|
+
import { r as resolveLanguage, u as useChatSettingsStore, C as CodeBlock, a as useChatSettings$1 } from "./index-CmbNTqa2.js";
|
|
19
21
|
import { create } from "zustand";
|
|
20
22
|
import { persist } from "zustand/middleware";
|
|
21
23
|
import { createPortal } from "react-dom";
|
|
22
|
-
import { a as Route } from "./router-
|
|
24
|
+
import { a as Route } from "./router-5qObg5aX.js";
|
|
23
25
|
function deriveFriendlyIdFromKey(key) {
|
|
24
26
|
if (!key) return "main";
|
|
25
27
|
const trimmed = key.trim();
|
|
@@ -39,7 +41,7 @@ function getToolCallsFromMessage(msg) {
|
|
|
39
41
|
(part) => part.type === "toolCall"
|
|
40
42
|
);
|
|
41
43
|
}
|
|
42
|
-
function normalizeTimestamp$
|
|
44
|
+
function normalizeTimestamp$2(value) {
|
|
43
45
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
44
46
|
if (value < 1e12) return value * 1e3;
|
|
45
47
|
return value;
|
|
@@ -59,7 +61,7 @@ function getMessageTimestamp(message) {
|
|
|
59
61
|
message.ts
|
|
60
62
|
];
|
|
61
63
|
for (const candidate of candidates) {
|
|
62
|
-
const normalized = normalizeTimestamp$
|
|
64
|
+
const normalized = normalizeTimestamp$2(candidate);
|
|
63
65
|
if (normalized) return normalized;
|
|
64
66
|
}
|
|
65
67
|
return Date.now();
|
|
@@ -93,6 +95,7 @@ function normalizeSessions(rows) {
|
|
|
93
95
|
const rawSession = session;
|
|
94
96
|
const totalTokens = typeof rawSession.totalTokens === "number" ? rawSession.totalTokens : void 0;
|
|
95
97
|
const contextTokens = typeof rawSession.contextTokens === "number" ? rawSession.contextTokens : void 0;
|
|
98
|
+
const status = typeof rawSession.status === "string" ? rawSession.status : void 0;
|
|
96
99
|
return {
|
|
97
100
|
key,
|
|
98
101
|
friendlyId: friendlyIdCandidate,
|
|
@@ -102,6 +105,7 @@ function normalizeSessions(rows) {
|
|
|
102
105
|
updatedAt: typeof session.updatedAt === "number" ? session.updatedAt : void 0,
|
|
103
106
|
lastMessage: session.lastMessage ?? null,
|
|
104
107
|
kind,
|
|
108
|
+
status,
|
|
105
109
|
totalTokens,
|
|
106
110
|
contextTokens
|
|
107
111
|
};
|
|
@@ -652,9 +656,74 @@ function ScrollAreaCorner({ className, ...props }) {
|
|
|
652
656
|
}
|
|
653
657
|
);
|
|
654
658
|
}
|
|
659
|
+
function getKindIcon(kind) {
|
|
660
|
+
if (kind === "subagent") return BotIcon;
|
|
661
|
+
if (kind === "cron") return Clock01Icon;
|
|
662
|
+
return Chat01Icon;
|
|
663
|
+
}
|
|
664
|
+
function previewFromMessage(message) {
|
|
665
|
+
if (!message || !Array.isArray(message.content)) return "";
|
|
666
|
+
const text = message.content.map((part) => part.type === "text" ? String(part.text ?? "") : "").join(" ").replace(/\s+/g, " ").trim();
|
|
667
|
+
return text;
|
|
668
|
+
}
|
|
669
|
+
function normalizeTimestamp$1(value) {
|
|
670
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
671
|
+
if (value < 1e12) return value * 1e3;
|
|
672
|
+
return value;
|
|
673
|
+
}
|
|
674
|
+
if (typeof value === "string") {
|
|
675
|
+
const parsed = Date.parse(value);
|
|
676
|
+
if (!Number.isNaN(parsed)) return parsed;
|
|
677
|
+
}
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
function getLastMessageTimestamp(message) {
|
|
681
|
+
if (!message) return null;
|
|
682
|
+
const candidates = [
|
|
683
|
+
message.createdAt,
|
|
684
|
+
message.created_at,
|
|
685
|
+
message.timestamp,
|
|
686
|
+
message.time,
|
|
687
|
+
message.ts
|
|
688
|
+
];
|
|
689
|
+
for (const candidate of candidates) {
|
|
690
|
+
const normalized = normalizeTimestamp$1(candidate);
|
|
691
|
+
if (normalized) return normalized;
|
|
692
|
+
}
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
function formatRelativeTime(timestamp) {
|
|
696
|
+
const diffMs = timestamp - Date.now();
|
|
697
|
+
const absMs = Math.abs(diffMs);
|
|
698
|
+
const units = [
|
|
699
|
+
["minute", 6e4],
|
|
700
|
+
["hour", 36e5],
|
|
701
|
+
["day", 864e5]
|
|
702
|
+
];
|
|
703
|
+
let unit = "minute";
|
|
704
|
+
let divisor = 6e4;
|
|
705
|
+
if (absMs >= units[2][1]) {
|
|
706
|
+
[unit, divisor] = units[2];
|
|
707
|
+
} else if (absMs >= units[1][1]) {
|
|
708
|
+
[unit, divisor] = units[1];
|
|
709
|
+
}
|
|
710
|
+
const value = Math.round(diffMs / divisor);
|
|
711
|
+
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
|
|
712
|
+
return rtf.format(value, unit);
|
|
713
|
+
}
|
|
714
|
+
function subagentStatusTone(status) {
|
|
715
|
+
const normalized = String(status ?? "").toLowerCase().trim();
|
|
716
|
+
if (!normalized) return null;
|
|
717
|
+
if (normalized === "error" || normalized === "failed") return "error";
|
|
718
|
+
if (normalized === "completed" || normalized === "ended" || normalized === "done") {
|
|
719
|
+
return "success";
|
|
720
|
+
}
|
|
721
|
+
return null;
|
|
722
|
+
}
|
|
655
723
|
function SessionItemComponent({
|
|
656
724
|
session,
|
|
657
725
|
active,
|
|
726
|
+
isGenerating = false,
|
|
658
727
|
isPinned,
|
|
659
728
|
selectionMode = false,
|
|
660
729
|
selected = false,
|
|
@@ -666,6 +735,11 @@ function SessionItemComponent({
|
|
|
666
735
|
onExport
|
|
667
736
|
}) {
|
|
668
737
|
const label = session.label || session.title || session.derivedTitle || session.friendlyId;
|
|
738
|
+
const KindIcon = getKindIcon(session.kind);
|
|
739
|
+
const subagentPreviewRaw = session.kind === "subagent" && (session.lastMessage?.role === "assistant" || session.lastMessage?.role === "toolResult") ? previewFromMessage(session.lastMessage) : "";
|
|
740
|
+
const subagentPreview = subagentPreviewRaw.length > 50 ? `${subagentPreviewRaw.slice(0, 50).trimEnd()}…` : subagentPreviewRaw;
|
|
741
|
+
const subagentStatus = session.kind === "subagent" ? subagentStatusTone(session.status) : null;
|
|
742
|
+
const cronLastRun = session.kind === "cron" ? getLastMessageTimestamp(session.lastMessage) : null;
|
|
669
743
|
return /* @__PURE__ */ jsxs(
|
|
670
744
|
Link,
|
|
671
745
|
{
|
|
@@ -682,7 +756,7 @@ function SessionItemComponent({
|
|
|
682
756
|
},
|
|
683
757
|
className: cn(
|
|
684
758
|
"group inline-flex items-center justify-between",
|
|
685
|
-
"w-full text-left pl-1.5 pr-0.5 h-8 rounded-lg transition-colors duration-0",
|
|
759
|
+
"w-full text-left pl-1.5 pr-0.5 min-h-8 py-1 rounded-lg transition-colors duration-0",
|
|
686
760
|
"select-none",
|
|
687
761
|
active ? "bg-primary-200 text-primary-950" : "bg-transparent text-primary-950 [&:hover:not(:has(button:hover))]:bg-primary-200"
|
|
688
762
|
),
|
|
@@ -699,10 +773,48 @@ function SessionItemComponent({
|
|
|
699
773
|
children: selected ? /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", className: "size-3", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { d: "M2.5 6l2.5 2.5 4.5-5" }) }) : null
|
|
700
774
|
}
|
|
701
775
|
) : null,
|
|
702
|
-
/* @__PURE__ */
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
776
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
777
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
778
|
+
/* @__PURE__ */ jsx(
|
|
779
|
+
HugeiconsIcon,
|
|
780
|
+
{
|
|
781
|
+
icon: KindIcon,
|
|
782
|
+
size: 12,
|
|
783
|
+
strokeWidth: 1.75,
|
|
784
|
+
className: "text-primary-500/70 shrink-0"
|
|
785
|
+
}
|
|
786
|
+
),
|
|
787
|
+
/* @__PURE__ */ jsxs("div", { className: "text-sm font-[450] line-clamp-1 min-w-0", children: [
|
|
788
|
+
isPinned ? /* @__PURE__ */ jsx("span", { className: "mr-1 text-xs text-primary-700", "aria-hidden": "true", children: "📌" }) : null,
|
|
789
|
+
label
|
|
790
|
+
] }),
|
|
791
|
+
session.kind === "subagent" ? isGenerating ? /* @__PURE__ */ jsx(
|
|
792
|
+
"span",
|
|
793
|
+
{
|
|
794
|
+
"aria-label": "Session active",
|
|
795
|
+
className: "size-1.5 rounded-full bg-green-500 shrink-0"
|
|
796
|
+
}
|
|
797
|
+
) : subagentStatus === "success" ? /* @__PURE__ */ jsx(
|
|
798
|
+
HugeiconsIcon,
|
|
799
|
+
{
|
|
800
|
+
icon: Tick01Icon,
|
|
801
|
+
size: 12,
|
|
802
|
+
strokeWidth: 1.8,
|
|
803
|
+
className: "text-green-600/80 shrink-0"
|
|
804
|
+
}
|
|
805
|
+
) : subagentStatus === "error" ? /* @__PURE__ */ jsx(
|
|
806
|
+
HugeiconsIcon,
|
|
807
|
+
{
|
|
808
|
+
icon: Cancel01Icon,
|
|
809
|
+
size: 12,
|
|
810
|
+
strokeWidth: 1.8,
|
|
811
|
+
className: "text-red-600/80 shrink-0"
|
|
812
|
+
}
|
|
813
|
+
) : null : null
|
|
814
|
+
] }),
|
|
815
|
+
subagentPreview ? /* @__PURE__ */ jsx("div", { className: "text-[11px] text-primary-600/80 line-clamp-1 mt-0.5 pl-[18px]", children: subagentPreview }) : null,
|
|
816
|
+
session.kind === "cron" && cronLastRun ? /* @__PURE__ */ jsx("div", { className: "text-[10px] text-primary-500/75 line-clamp-1 mt-0.5 pl-[18px] font-mono", children: formatRelativeTime(cronLastRun) }) : null
|
|
817
|
+
] })
|
|
706
818
|
] }),
|
|
707
819
|
selectionMode ? null : /* @__PURE__ */ jsxs(MenuRoot, { children: [
|
|
708
820
|
/* @__PURE__ */ jsx(
|
|
@@ -801,6 +913,7 @@ function SessionItemComponent({
|
|
|
801
913
|
}
|
|
802
914
|
function areSessionItemsEqual(prev, next) {
|
|
803
915
|
if (prev.active !== next.active) return false;
|
|
916
|
+
if (prev.isGenerating !== next.isGenerating) return false;
|
|
804
917
|
if (prev.isPinned !== next.isPinned) return false;
|
|
805
918
|
if (prev.selectionMode !== next.selectionMode) return false;
|
|
806
919
|
if (prev.selected !== next.selected) return false;
|
|
@@ -811,7 +924,7 @@ function areSessionItemsEqual(prev, next) {
|
|
|
811
924
|
if (prev.onDelete !== next.onDelete) return false;
|
|
812
925
|
if (prev.onExport !== next.onExport) return false;
|
|
813
926
|
if (prev.session === next.session) return true;
|
|
814
|
-
return prev.session.key === next.session.key && prev.session.friendlyId === next.session.friendlyId && prev.session.label === next.session.label && prev.session.title === next.session.title && prev.session.derivedTitle === next.session.derivedTitle && prev.session.updatedAt === next.session.updatedAt;
|
|
927
|
+
return prev.session.key === next.session.key && prev.session.friendlyId === next.session.friendlyId && prev.session.label === next.session.label && prev.session.title === next.session.title && prev.session.derivedTitle === next.session.derivedTitle && prev.session.updatedAt === next.session.updatedAt && prev.session.kind === next.session.kind && prev.session.status === next.session.status && prev.session.lastMessage === next.session.lastMessage;
|
|
815
928
|
}
|
|
816
929
|
const SessionItem = memo(SessionItemComponent, areSessionItemsEqual);
|
|
817
930
|
const PINNED_SESSIONS_KEY = "opencami-pinned-sessions";
|
|
@@ -900,10 +1013,22 @@ function isSessionActive(session, activeFriendlyId, activeSessionKey) {
|
|
|
900
1013
|
}
|
|
901
1014
|
return session.friendlyId === activeFriendlyId;
|
|
902
1015
|
}
|
|
1016
|
+
function isStatusGenerating(status) {
|
|
1017
|
+
if (!status) return false;
|
|
1018
|
+
const normalized = status.toLowerCase();
|
|
1019
|
+
return normalized.includes("running") || normalized.includes("active") || normalized.includes("stream") || normalized.includes("generat");
|
|
1020
|
+
}
|
|
1021
|
+
function isSessionGenerating(session, activeFriendlyId, activeSessionKey, isStreaming) {
|
|
1022
|
+
if (isSessionActive(session, activeFriendlyId, activeSessionKey) && isStreaming) {
|
|
1023
|
+
return true;
|
|
1024
|
+
}
|
|
1025
|
+
return isStatusGenerating(session.status);
|
|
1026
|
+
}
|
|
903
1027
|
const SidebarSessions = memo(function SidebarSessions2({
|
|
904
1028
|
sessions,
|
|
905
1029
|
activeFriendlyId,
|
|
906
1030
|
activeSessionKey,
|
|
1031
|
+
isStreaming = false,
|
|
907
1032
|
defaultOpen = true,
|
|
908
1033
|
onSelect,
|
|
909
1034
|
onRename,
|
|
@@ -1053,6 +1178,7 @@ const SidebarSessions = memo(function SidebarSessions2({
|
|
|
1053
1178
|
{
|
|
1054
1179
|
session,
|
|
1055
1180
|
active: isSessionActive(session, activeFriendlyId, activeSessionKey),
|
|
1181
|
+
isGenerating: isSessionGenerating(session, activeFriendlyId, activeSessionKey, isStreaming),
|
|
1056
1182
|
isPinned: false,
|
|
1057
1183
|
selectionMode,
|
|
1058
1184
|
selected: selectedSessionKeys.has(session.key),
|
|
@@ -1111,6 +1237,7 @@ const SidebarSessions = memo(function SidebarSessions2({
|
|
|
1111
1237
|
{
|
|
1112
1238
|
session,
|
|
1113
1239
|
active: isSessionActive(session, activeFriendlyId, activeSessionKey),
|
|
1240
|
+
isGenerating: isSessionGenerating(session, activeFriendlyId, activeSessionKey, isStreaming),
|
|
1114
1241
|
isPinned: true,
|
|
1115
1242
|
selectionMode,
|
|
1116
1243
|
selected: selectedSessionKeys.has(session.key),
|
|
@@ -1139,6 +1266,7 @@ const SidebarSessions = memo(function SidebarSessions2({
|
|
|
1139
1266
|
{
|
|
1140
1267
|
session,
|
|
1141
1268
|
active: isSessionActive(session, activeFriendlyId, activeSessionKey),
|
|
1269
|
+
isGenerating: isSessionGenerating(session, activeFriendlyId, activeSessionKey, isStreaming),
|
|
1142
1270
|
isPinned: false,
|
|
1143
1271
|
selectionMode,
|
|
1144
1272
|
selected: selectedSessionKeys.has(session.key),
|
|
@@ -1224,6 +1352,7 @@ const SidebarSessions = memo(function SidebarSessions2({
|
|
|
1224
1352
|
function areSidebarSessionsEqual(prev, next) {
|
|
1225
1353
|
if (prev.activeFriendlyId !== next.activeFriendlyId) return false;
|
|
1226
1354
|
if (prev.activeSessionKey !== next.activeSessionKey) return false;
|
|
1355
|
+
if (prev.isStreaming !== next.isStreaming) return false;
|
|
1227
1356
|
if (prev.defaultOpen !== next.defaultOpen) return false;
|
|
1228
1357
|
if (prev.onSelect !== next.onSelect) return false;
|
|
1229
1358
|
if (prev.onRename !== next.onRename) return false;
|
|
@@ -1241,6 +1370,8 @@ function areSidebarSessionsEqual(prev, next) {
|
|
|
1241
1370
|
if (prevSession.derivedTitle !== nextSession.derivedTitle) return false;
|
|
1242
1371
|
if (prevSession.updatedAt !== nextSession.updatedAt) return false;
|
|
1243
1372
|
if (prevSession.kind !== nextSession.kind) return false;
|
|
1373
|
+
if (prevSession.status !== nextSession.status) return false;
|
|
1374
|
+
if (prevSession.lastMessage !== nextSession.lastMessage) return false;
|
|
1244
1375
|
}
|
|
1245
1376
|
return true;
|
|
1246
1377
|
}
|
|
@@ -1517,30 +1648,11 @@ function useRenameSession() {
|
|
|
1517
1648
|
);
|
|
1518
1649
|
return { renameSession, renaming, error };
|
|
1519
1650
|
}
|
|
1520
|
-
function OpenCamiLogo({ className }) {
|
|
1521
|
-
return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx("span", { className: "text-xl", children: "🦎" }) });
|
|
1522
|
-
}
|
|
1523
|
-
function OpenCamiText({ className }) {
|
|
1524
|
-
return /* @__PURE__ */ jsx(
|
|
1525
|
-
"span",
|
|
1526
|
-
{
|
|
1527
|
-
className,
|
|
1528
|
-
style: {
|
|
1529
|
-
background: "linear-gradient(90deg, #10b981, #14b8a6, #06b6d4, #8b5cf6, #ec4899)",
|
|
1530
|
-
WebkitBackgroundClip: "text",
|
|
1531
|
-
WebkitTextFillColor: "transparent",
|
|
1532
|
-
backgroundClip: "text",
|
|
1533
|
-
fontWeight: 600
|
|
1534
|
-
},
|
|
1535
|
-
children: "OpenCami"
|
|
1536
|
-
}
|
|
1537
|
-
);
|
|
1538
|
-
}
|
|
1539
1651
|
const SettingsDialog = lazy(
|
|
1540
|
-
() => import("./settings-dialog-
|
|
1652
|
+
() => import("./settings-dialog-BBQcU55J.js").then((m) => ({ default: m.SettingsDialog }))
|
|
1541
1653
|
);
|
|
1542
1654
|
const SessionExportDialog = lazy(
|
|
1543
|
-
() => import("./session-export-dialog-
|
|
1655
|
+
() => import("./session-export-dialog-DRVbC8Q-.js").then((m) => ({
|
|
1544
1656
|
default: m.SessionExportDialog
|
|
1545
1657
|
}))
|
|
1546
1658
|
);
|
|
@@ -1548,6 +1660,7 @@ function ChatSidebarComponent({
|
|
|
1548
1660
|
sessions,
|
|
1549
1661
|
activeFriendlyId,
|
|
1550
1662
|
activeSessionKey,
|
|
1663
|
+
isStreaming = false,
|
|
1551
1664
|
creatingSession,
|
|
1552
1665
|
onCreateSession,
|
|
1553
1666
|
isCollapsed,
|
|
@@ -1779,6 +1892,48 @@ function ChatSidebarComponent({
|
|
|
1779
1892
|
}
|
|
1780
1893
|
) }),
|
|
1781
1894
|
isCollapsed && /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: "Files" })
|
|
1895
|
+
] }) }),
|
|
1896
|
+
(() => {
|
|
1897
|
+
try {
|
|
1898
|
+
return localStorage.getItem("opencami-agent-manager") === "true";
|
|
1899
|
+
} catch {
|
|
1900
|
+
return false;
|
|
1901
|
+
}
|
|
1902
|
+
})() && /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { children: [
|
|
1903
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
1904
|
+
Link,
|
|
1905
|
+
{
|
|
1906
|
+
to: "/agents",
|
|
1907
|
+
className: cn(
|
|
1908
|
+
buttonVariants({ variant: "ghost", size: "sm" }),
|
|
1909
|
+
"w-full pl-1.5 justify-start"
|
|
1910
|
+
),
|
|
1911
|
+
onClick: onSelectSession,
|
|
1912
|
+
children: [
|
|
1913
|
+
/* @__PURE__ */ jsx(
|
|
1914
|
+
HugeiconsIcon,
|
|
1915
|
+
{
|
|
1916
|
+
icon: AiBrain01Icon,
|
|
1917
|
+
size: 20,
|
|
1918
|
+
strokeWidth: 1.5,
|
|
1919
|
+
className: "min-w-5"
|
|
1920
|
+
}
|
|
1921
|
+
),
|
|
1922
|
+
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: !isCollapsed && /* @__PURE__ */ jsx(
|
|
1923
|
+
motion.span,
|
|
1924
|
+
{
|
|
1925
|
+
initial: { opacity: 0 },
|
|
1926
|
+
animate: { opacity: 1 },
|
|
1927
|
+
exit: { opacity: 0 },
|
|
1928
|
+
transition,
|
|
1929
|
+
className: "overflow-hidden whitespace-nowrap",
|
|
1930
|
+
children: "Agents"
|
|
1931
|
+
}
|
|
1932
|
+
) })
|
|
1933
|
+
]
|
|
1934
|
+
}
|
|
1935
|
+
) }),
|
|
1936
|
+
isCollapsed && /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: "Agents" })
|
|
1782
1937
|
] }) })
|
|
1783
1938
|
]
|
|
1784
1939
|
}
|
|
@@ -1837,6 +1992,7 @@ function ChatSidebarComponent({
|
|
|
1837
1992
|
sessions,
|
|
1838
1993
|
activeFriendlyId,
|
|
1839
1994
|
activeSessionKey,
|
|
1995
|
+
isStreaming,
|
|
1840
1996
|
onSelect: onSelectSession,
|
|
1841
1997
|
onRename: handleOpenRename,
|
|
1842
1998
|
onDelete: handleOpenDelete,
|
|
@@ -1945,12 +2101,16 @@ function areSessionsEqual(prevSessions, nextSessions) {
|
|
|
1945
2101
|
if (prev.title !== next.title) return false;
|
|
1946
2102
|
if (prev.derivedTitle !== next.derivedTitle) return false;
|
|
1947
2103
|
if (prev.updatedAt !== next.updatedAt) return false;
|
|
2104
|
+
if (prev.kind !== next.kind) return false;
|
|
2105
|
+
if (prev.status !== next.status) return false;
|
|
2106
|
+
if (prev.lastMessage !== next.lastMessage) return false;
|
|
1948
2107
|
}
|
|
1949
2108
|
return true;
|
|
1950
2109
|
}
|
|
1951
2110
|
function areSidebarPropsEqual(prevProps, nextProps) {
|
|
1952
2111
|
if (prevProps.activeFriendlyId !== nextProps.activeFriendlyId) return false;
|
|
1953
2112
|
if (prevProps.activeSessionKey !== nextProps.activeSessionKey) return false;
|
|
2113
|
+
if (prevProps.isStreaming !== nextProps.isStreaming) return false;
|
|
1954
2114
|
if (prevProps.creatingSession !== nextProps.creatingSession) return false;
|
|
1955
2115
|
if (prevProps.isCollapsed !== nextProps.isCollapsed) return false;
|
|
1956
2116
|
if (!areSessionsEqual(prevProps.sessions, nextProps.sessions)) return false;
|
|
@@ -2352,6 +2512,57 @@ function MessageActionsBar({
|
|
|
2352
2512
|
}
|
|
2353
2513
|
);
|
|
2354
2514
|
}
|
|
2515
|
+
function markdownHrefToFilePath(href) {
|
|
2516
|
+
if (!href?.startsWith("openclaw-file://")) return null;
|
|
2517
|
+
try {
|
|
2518
|
+
return decodeURIComponent(href.slice("openclaw-file://".length));
|
|
2519
|
+
} catch {
|
|
2520
|
+
return null;
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
const EXTENSION_LANGUAGE_MAP = {
|
|
2524
|
+
py: "python",
|
|
2525
|
+
ts: "typescript",
|
|
2526
|
+
js: "javascript",
|
|
2527
|
+
jsx: "jsx",
|
|
2528
|
+
tsx: "tsx",
|
|
2529
|
+
json: "json",
|
|
2530
|
+
md: "markdown",
|
|
2531
|
+
yml: "yaml",
|
|
2532
|
+
yaml: "yaml",
|
|
2533
|
+
sh: "bash",
|
|
2534
|
+
bash: "bash",
|
|
2535
|
+
zsh: "bash",
|
|
2536
|
+
html: "html",
|
|
2537
|
+
css: "css",
|
|
2538
|
+
sql: "sql",
|
|
2539
|
+
xml: "xml",
|
|
2540
|
+
toml: "toml",
|
|
2541
|
+
rs: "rust",
|
|
2542
|
+
go: "go",
|
|
2543
|
+
java: "java",
|
|
2544
|
+
c: "c",
|
|
2545
|
+
cpp: "cpp",
|
|
2546
|
+
cs: "csharp",
|
|
2547
|
+
php: "php",
|
|
2548
|
+
rb: "ruby",
|
|
2549
|
+
graphql: "graphql",
|
|
2550
|
+
diff: "diff",
|
|
2551
|
+
patch: "diff",
|
|
2552
|
+
env: "text"
|
|
2553
|
+
};
|
|
2554
|
+
function languageFromFilePath(path) {
|
|
2555
|
+
if (!path) return "text";
|
|
2556
|
+
const filename = path.split("/").pop() || "";
|
|
2557
|
+
const lower = filename.toLowerCase();
|
|
2558
|
+
if (lower === "dockerfile") return "dockerfile";
|
|
2559
|
+
if (lower === "makefile") return "text";
|
|
2560
|
+
const parts = lower.split(".");
|
|
2561
|
+
const extension = parts.length > 1 ? parts.pop() || "" : "";
|
|
2562
|
+
const mapped = EXTENSION_LANGUAGE_MAP[extension] || extension || "text";
|
|
2563
|
+
return resolveLanguage(mapped);
|
|
2564
|
+
}
|
|
2565
|
+
const INLINE_PREVIEW_MAX_BYTES = 100 * 1024;
|
|
2355
2566
|
function parseMarkdownIntoBlocks(markdown) {
|
|
2356
2567
|
const tokens = marked.lexer(markdown);
|
|
2357
2568
|
return tokens.map((token) => token.raw);
|
|
@@ -2361,7 +2572,7 @@ function extractLanguage(className) {
|
|
|
2361
2572
|
const match = className.match(/language-(\w+)/);
|
|
2362
2573
|
return match ? match[1] : "text";
|
|
2363
2574
|
}
|
|
2364
|
-
const
|
|
2575
|
+
const BASE_COMPONENTS = {
|
|
2365
2576
|
code: function CodeComponent({ className, children }) {
|
|
2366
2577
|
const isInline = !className?.includes("language-");
|
|
2367
2578
|
if (isInline) {
|
|
@@ -2401,18 +2612,6 @@ const INITIAL_COMPONENTS = {
|
|
|
2401
2612
|
li: function LiComponent({ children }) {
|
|
2402
2613
|
return /* @__PURE__ */ jsx("li", { className: "leading-relaxed", children });
|
|
2403
2614
|
},
|
|
2404
|
-
a: function AComponent({ children, href }) {
|
|
2405
|
-
return /* @__PURE__ */ jsx(
|
|
2406
|
-
"a",
|
|
2407
|
-
{
|
|
2408
|
-
href,
|
|
2409
|
-
className: "text-primary-950 underline decoration-primary-300 underline-offset-4 transition-colors hover:text-primary-950 hover:decoration-primary-500",
|
|
2410
|
-
target: "_blank",
|
|
2411
|
-
rel: "noopener noreferrer",
|
|
2412
|
-
children
|
|
2413
|
-
}
|
|
2414
|
-
);
|
|
2415
|
-
},
|
|
2416
2615
|
blockquote: function BlockquoteComponent({ children }) {
|
|
2417
2616
|
return /* @__PURE__ */ jsx("blockquote", { className: "border-l-2 border-primary-300 pl-4 text-primary-900 italic", children });
|
|
2418
2617
|
},
|
|
@@ -2444,10 +2643,56 @@ const INITIAL_COMPONENTS = {
|
|
|
2444
2643
|
return /* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-primary-950", children });
|
|
2445
2644
|
}
|
|
2446
2645
|
};
|
|
2646
|
+
function createDefaultComponents(onOpenFilePreview, inlineFilePreviewEnabled) {
|
|
2647
|
+
const FILE_PATH_RE = /^(?:~\/[\w.\-\/]+|\/(?:[\w.\-]+\/)+[\w.\-]+)$/;
|
|
2648
|
+
return {
|
|
2649
|
+
...BASE_COMPONENTS,
|
|
2650
|
+
a: function AComponent({ children, href }) {
|
|
2651
|
+
const filePath = markdownHrefToFilePath(href);
|
|
2652
|
+
if (inlineFilePreviewEnabled && filePath) {
|
|
2653
|
+
return /* @__PURE__ */ jsx(
|
|
2654
|
+
"button",
|
|
2655
|
+
{
|
|
2656
|
+
type: "button",
|
|
2657
|
+
onClick: () => onOpenFilePreview(filePath),
|
|
2658
|
+
className: "font-mono text-primary-900 underline decoration-primary-300 underline-offset-4 hover:decoration-primary-600 cursor-pointer",
|
|
2659
|
+
children
|
|
2660
|
+
}
|
|
2661
|
+
);
|
|
2662
|
+
}
|
|
2663
|
+
return /* @__PURE__ */ jsx(
|
|
2664
|
+
"a",
|
|
2665
|
+
{
|
|
2666
|
+
href,
|
|
2667
|
+
className: "text-primary-950 underline decoration-primary-300 underline-offset-4 transition-colors hover:text-primary-950 hover:decoration-primary-500",
|
|
2668
|
+
target: "_blank",
|
|
2669
|
+
rel: "noopener noreferrer",
|
|
2670
|
+
children
|
|
2671
|
+
}
|
|
2672
|
+
);
|
|
2673
|
+
},
|
|
2674
|
+
code: function InlineCodeComponent({ children, className }) {
|
|
2675
|
+
if (className) return /* @__PURE__ */ jsx("code", { className, children });
|
|
2676
|
+
const text = typeof children === "string" ? children : Array.isArray(children) ? children.filter((c) => typeof c === "string").join("") : String(children ?? "");
|
|
2677
|
+
if (inlineFilePreviewEnabled && text && FILE_PATH_RE.test(text)) {
|
|
2678
|
+
return /* @__PURE__ */ jsx(
|
|
2679
|
+
"button",
|
|
2680
|
+
{
|
|
2681
|
+
type: "button",
|
|
2682
|
+
onClick: () => onOpenFilePreview(text),
|
|
2683
|
+
className: "font-mono text-sm bg-primary-100 rounded px-1.5 py-0.5 text-primary-900 underline decoration-primary-300 underline-offset-4 hover:decoration-primary-600 cursor-pointer",
|
|
2684
|
+
children
|
|
2685
|
+
}
|
|
2686
|
+
);
|
|
2687
|
+
}
|
|
2688
|
+
return /* @__PURE__ */ jsx("code", { className: "font-mono text-sm bg-primary-100 rounded px-1.5 py-0.5 text-primary-900", children });
|
|
2689
|
+
}
|
|
2690
|
+
};
|
|
2691
|
+
}
|
|
2447
2692
|
const MemoizedMarkdownBlock = memo(
|
|
2448
2693
|
function MarkdownBlock({
|
|
2449
2694
|
content,
|
|
2450
|
-
components
|
|
2695
|
+
components
|
|
2451
2696
|
}) {
|
|
2452
2697
|
return /* @__PURE__ */ jsx(
|
|
2453
2698
|
ReactMarkdown,
|
|
@@ -2463,23 +2708,132 @@ const MemoizedMarkdownBlock = memo(
|
|
|
2463
2708
|
}
|
|
2464
2709
|
);
|
|
2465
2710
|
MemoizedMarkdownBlock.displayName = "MemoizedMarkdownBlock";
|
|
2711
|
+
function fileErrorMessageFromResponse(status, code) {
|
|
2712
|
+
if (code === "NOT_FOUND" || status === 404) return "File not found";
|
|
2713
|
+
if (code === "UNSUPPORTED_TYPE") return "Binary file";
|
|
2714
|
+
if (code === "FILE_TOO_LARGE" || status === 413) return "File too large";
|
|
2715
|
+
return "Failed to load file preview";
|
|
2716
|
+
}
|
|
2466
2717
|
function MarkdownComponent({
|
|
2467
2718
|
children,
|
|
2468
2719
|
id,
|
|
2469
2720
|
className,
|
|
2470
|
-
components
|
|
2721
|
+
components
|
|
2471
2722
|
}) {
|
|
2472
2723
|
const generatedId = useId();
|
|
2473
2724
|
const blockId = id ?? generatedId;
|
|
2474
2725
|
const blocks = useMemo(() => parseMarkdownIntoBlocks(children), [children]);
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2726
|
+
const [filePreview, setFilePreview] = useState({ status: "idle" });
|
|
2727
|
+
const inlineFilePreviewEnabled = useChatSettingsStore(
|
|
2728
|
+
(state) => state.settings.inlineFilePreview
|
|
2729
|
+
);
|
|
2730
|
+
const defaultComponents = useMemo(
|
|
2731
|
+
() => createDefaultComponents(
|
|
2732
|
+
(path) => setFilePreview({ status: "loading", path }),
|
|
2733
|
+
inlineFilePreviewEnabled
|
|
2734
|
+
),
|
|
2735
|
+
[inlineFilePreviewEnabled]
|
|
2736
|
+
);
|
|
2737
|
+
const mergedComponents = useMemo(
|
|
2738
|
+
() => ({ ...defaultComponents, ...components || {} }),
|
|
2739
|
+
[defaultComponents, components]
|
|
2740
|
+
);
|
|
2741
|
+
useEffect(() => {
|
|
2742
|
+
if (filePreview.status !== "loading") return;
|
|
2743
|
+
const path = filePreview.path;
|
|
2744
|
+
const controller = new AbortController();
|
|
2745
|
+
fetch(`/api/files/read?path=${encodeURIComponent(path)}`, {
|
|
2746
|
+
signal: controller.signal
|
|
2747
|
+
}).then(async (response) => {
|
|
2748
|
+
const payload = await response.json().catch(() => ({}));
|
|
2749
|
+
if (!response.ok) {
|
|
2750
|
+
const error = fileErrorMessageFromResponse(response.status, payload.code);
|
|
2751
|
+
setFilePreview({ status: "error", path, message: error });
|
|
2752
|
+
return;
|
|
2753
|
+
}
|
|
2754
|
+
const size = Number(payload.size ?? 0);
|
|
2755
|
+
if (size > INLINE_PREVIEW_MAX_BYTES) {
|
|
2756
|
+
setFilePreview({ status: "error", path, message: "File too large" });
|
|
2757
|
+
return;
|
|
2758
|
+
}
|
|
2759
|
+
const content = String(payload.content ?? "");
|
|
2760
|
+
setFilePreview({
|
|
2761
|
+
status: "success",
|
|
2762
|
+
path,
|
|
2763
|
+
content,
|
|
2764
|
+
language: languageFromFilePath(path)
|
|
2765
|
+
});
|
|
2766
|
+
}).catch(() => {
|
|
2767
|
+
if (controller.signal.aborted) return;
|
|
2768
|
+
setFilePreview({ status: "error", path, message: "Failed to load file preview" });
|
|
2769
|
+
});
|
|
2770
|
+
return () => controller.abort();
|
|
2771
|
+
}, [filePreview]);
|
|
2772
|
+
const previewOpen = filePreview.status !== "idle";
|
|
2773
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2774
|
+
/* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-2", className), children: blocks.map((block, index) => /* @__PURE__ */ jsx(
|
|
2775
|
+
MemoizedMarkdownBlock,
|
|
2776
|
+
{
|
|
2777
|
+
content: block,
|
|
2778
|
+
components: mergedComponents
|
|
2779
|
+
},
|
|
2780
|
+
`${blockId}-block-${index}`
|
|
2781
|
+
)) }),
|
|
2782
|
+
/* @__PURE__ */ jsx(
|
|
2783
|
+
DialogRoot,
|
|
2784
|
+
{
|
|
2785
|
+
open: previewOpen,
|
|
2786
|
+
onOpenChange: (open) => {
|
|
2787
|
+
if (!open) setFilePreview({ status: "idle" });
|
|
2788
|
+
},
|
|
2789
|
+
children: /* @__PURE__ */ jsxs(DialogContent, { className: "w-[min(1000px,95vw)] max-h-[88vh] overflow-hidden p-0", children: [
|
|
2790
|
+
/* @__PURE__ */ jsxs("div", { className: "border-b border-primary-200 px-4 py-3 flex items-start justify-between gap-3", children: [
|
|
2791
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
2792
|
+
/* @__PURE__ */ jsx(DialogTitle, { className: "text-base", children: "File Preview" }),
|
|
2793
|
+
filePreview.status !== "idle" && /* @__PURE__ */ jsx("p", { className: "text-xs text-primary-600 font-mono truncate", children: filePreview.path })
|
|
2794
|
+
] }),
|
|
2795
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2796
|
+
filePreview.status !== "idle" && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", asChild: true, children: /* @__PURE__ */ jsx(
|
|
2797
|
+
Link,
|
|
2798
|
+
{
|
|
2799
|
+
to: "/files",
|
|
2800
|
+
onClick: () => {
|
|
2801
|
+
let p = filePreview.status !== "idle" ? filePreview.path : "";
|
|
2802
|
+
if (p) {
|
|
2803
|
+
const prefixes = ["/root/clawd/", "/root/"];
|
|
2804
|
+
for (const prefix of prefixes) {
|
|
2805
|
+
if (p.startsWith(prefix)) {
|
|
2806
|
+
p = "/" + p.slice(prefix.length);
|
|
2807
|
+
break;
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
const dir = p.includes("/") ? p.slice(0, p.lastIndexOf("/")) || "/" : "/";
|
|
2811
|
+
useFileExplorerState.getState().navigateTo(dir);
|
|
2812
|
+
}
|
|
2813
|
+
setFilePreview({ status: "idle" });
|
|
2814
|
+
},
|
|
2815
|
+
children: "Open in File Explorer"
|
|
2816
|
+
}
|
|
2817
|
+
) }),
|
|
2818
|
+
/* @__PURE__ */ jsx(DialogClose, { children: "Close" })
|
|
2819
|
+
] })
|
|
2820
|
+
] }),
|
|
2821
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4 overflow-auto max-h-[calc(88vh-72px)]", children: [
|
|
2822
|
+
filePreview.status === "loading" && /* @__PURE__ */ jsx("p", { className: "text-sm text-primary-600", children: "Loading preview…" }),
|
|
2823
|
+
filePreview.status === "error" && /* @__PURE__ */ jsx("p", { className: "text-sm text-red-600", children: filePreview.message }),
|
|
2824
|
+
filePreview.status === "success" && /* @__PURE__ */ jsx(
|
|
2825
|
+
CodeBlock,
|
|
2826
|
+
{
|
|
2827
|
+
content: filePreview.content,
|
|
2828
|
+
language: filePreview.language,
|
|
2829
|
+
className: "w-full"
|
|
2830
|
+
}
|
|
2831
|
+
)
|
|
2832
|
+
] })
|
|
2833
|
+
] })
|
|
2834
|
+
}
|
|
2835
|
+
)
|
|
2836
|
+
] });
|
|
2483
2837
|
}
|
|
2484
2838
|
const Markdown = memo(MarkdownComponent);
|
|
2485
2839
|
Markdown.displayName = "Markdown";
|
|
@@ -2544,27 +2898,25 @@ function Thinking({ content }) {
|
|
|
2544
2898
|
}
|
|
2545
2899
|
function Tool({ toolPart, defaultOpen = false }) {
|
|
2546
2900
|
const { state, input, output, toolCallId } = toolPart;
|
|
2547
|
-
const
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
if (typeof
|
|
2901
|
+
const serialize = (value, maxLength = 3200) => {
|
|
2902
|
+
const normalized = value === void 0 ? "undefined" : value;
|
|
2903
|
+
let raw;
|
|
2904
|
+
if (typeof normalized === "string") {
|
|
2551
2905
|
try {
|
|
2552
|
-
|
|
2553
|
-
return parsed;
|
|
2906
|
+
raw = JSON.stringify(JSON.parse(normalized), null, 2);
|
|
2554
2907
|
} catch {
|
|
2555
|
-
|
|
2908
|
+
raw = normalized;
|
|
2556
2909
|
}
|
|
2910
|
+
} else {
|
|
2911
|
+
raw = JSON.stringify(normalized, null, 2);
|
|
2557
2912
|
}
|
|
2558
|
-
return
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
const formatted = formatValue(value);
|
|
2562
|
-
if (typeof formatted === "object" && formatted !== null) {
|
|
2563
|
-
return /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap break-all font-mono text-xs leading-relaxed", children: JSON.stringify(formatted, null, 2) });
|
|
2564
|
-
}
|
|
2565
|
-
return /* @__PURE__ */ jsx("span", { className: "break-all", children: String(formatted) });
|
|
2913
|
+
if (raw.length <= maxLength) return raw;
|
|
2914
|
+
return `${raw.slice(0, maxLength).trimEnd()}
|
|
2915
|
+
…[truncated]`;
|
|
2566
2916
|
};
|
|
2567
|
-
|
|
2917
|
+
const statusIcon = state === "output-error" ? Cancel01Icon : state === "output-available" ? Tick01Icon : Loading03Icon;
|
|
2918
|
+
const statusClassName = state === "output-error" ? "text-red-600/80" : state === "output-available" ? "text-green-600/80" : "text-primary-500/80";
|
|
2919
|
+
return /* @__PURE__ */ jsx("div", { className: "inline-flex flex-col w-full", children: /* @__PURE__ */ jsxs(Collapsible, { defaultOpen, children: [
|
|
2568
2920
|
/* @__PURE__ */ jsxs(
|
|
2569
2921
|
CollapsibleTrigger,
|
|
2570
2922
|
{
|
|
@@ -2572,10 +2924,19 @@ function Tool({ toolPart, defaultOpen = false }) {
|
|
|
2572
2924
|
Button,
|
|
2573
2925
|
{
|
|
2574
2926
|
variant: "ghost",
|
|
2575
|
-
className: "h-auto gap-1.5 px-1.5 py-
|
|
2927
|
+
className: "h-auto w-full justify-start gap-1.5 rounded-md px-1.5 py-1"
|
|
2576
2928
|
}
|
|
2577
2929
|
),
|
|
2578
2930
|
children: [
|
|
2931
|
+
/* @__PURE__ */ jsx(
|
|
2932
|
+
HugeiconsIcon,
|
|
2933
|
+
{
|
|
2934
|
+
icon: statusIcon,
|
|
2935
|
+
size: 12,
|
|
2936
|
+
strokeWidth: 1.7,
|
|
2937
|
+
className: statusClassName
|
|
2938
|
+
}
|
|
2939
|
+
),
|
|
2579
2940
|
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-primary-900", children: toolPart.type }),
|
|
2580
2941
|
/* @__PURE__ */ jsx(
|
|
2581
2942
|
HugeiconsIcon,
|
|
@@ -2583,41 +2944,130 @@ function Tool({ toolPart, defaultOpen = false }) {
|
|
|
2583
2944
|
icon: ArrowDown01Icon,
|
|
2584
2945
|
size: 14,
|
|
2585
2946
|
strokeWidth: 1.5,
|
|
2586
|
-
className: "text-primary-
|
|
2947
|
+
className: "ml-auto text-primary-700/80 transition-transform duration-150 group-data-panel-open:rotate-180"
|
|
2587
2948
|
}
|
|
2588
2949
|
)
|
|
2589
2950
|
]
|
|
2590
2951
|
}
|
|
2591
2952
|
),
|
|
2592
|
-
/* @__PURE__ */ jsx(CollapsiblePanel, { className: "mt-1", children: /* @__PURE__ */ jsxs("div", { className: "space-y-2 bg-primary-100 p-2
|
|
2593
|
-
|
|
2594
|
-
/* @__PURE__ */ jsx("
|
|
2595
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
" ",
|
|
2601
|
-
/* @__PURE__ */ jsx("span", { className: "text-primary-700", children: renderValue(value) })
|
|
2602
|
-
] }, key)) })
|
|
2953
|
+
/* @__PURE__ */ jsx(CollapsiblePanel, { className: "mt-1", children: /* @__PURE__ */ jsxs("div", { className: "space-y-2 rounded-md border border-primary-200 bg-primary-100/70 p-2", children: [
|
|
2954
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded border border-primary-200 bg-primary-50 px-2 py-1.5", children: [
|
|
2955
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium text-primary-600", children: "Tool" }),
|
|
2956
|
+
/* @__PURE__ */ jsx("div", { className: "font-mono text-xs text-primary-800 break-all", children: toolPart.type })
|
|
2957
|
+
] }),
|
|
2958
|
+
input && Object.keys(input).length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded border border-primary-200 bg-primary-50 px-2 py-1.5", children: [
|
|
2959
|
+
/* @__PURE__ */ jsx("h4", { className: "mb-1 text-[11px] font-medium text-primary-600", children: "Input" }),
|
|
2960
|
+
/* @__PURE__ */ jsx("pre", { className: "max-h-44 overflow-auto whitespace-pre-wrap break-all font-mono text-xs leading-relaxed text-primary-800", children: serialize(input) })
|
|
2603
2961
|
] }),
|
|
2604
|
-
output && /* @__PURE__ */ jsxs("div", { className: "border border-primary-200 bg-primary-50
|
|
2605
|
-
/* @__PURE__ */ jsx("h4", { className: "
|
|
2606
|
-
/* @__PURE__ */ jsx("
|
|
2962
|
+
output !== void 0 && output !== null && /* @__PURE__ */ jsxs("div", { className: "rounded border border-primary-200 bg-primary-50 px-2 py-1.5", children: [
|
|
2963
|
+
/* @__PURE__ */ jsx("h4", { className: "mb-1 text-[11px] font-medium text-primary-600", children: "Output" }),
|
|
2964
|
+
/* @__PURE__ */ jsx("pre", { className: "max-h-44 overflow-auto whitespace-pre-wrap break-all font-mono text-xs leading-relaxed text-primary-800", children: serialize(output) })
|
|
2607
2965
|
] }),
|
|
2608
|
-
state === "output-error" && toolPart.errorText && /* @__PURE__ */ jsxs("div", { className: "rounded-
|
|
2609
|
-
/* @__PURE__ */ jsx("h4", { className: "mb-1 text-
|
|
2966
|
+
state === "output-error" && toolPart.errorText && /* @__PURE__ */ jsxs("div", { className: "rounded border border-red-200 bg-red-50 px-2 py-1.5", children: [
|
|
2967
|
+
/* @__PURE__ */ jsx("h4", { className: "mb-1 text-[11px] font-medium text-red-600", children: "Error" }),
|
|
2610
2968
|
/* @__PURE__ */ jsx("div", { className: "text-xs text-red-700", children: toolPart.errorText })
|
|
2611
2969
|
] }),
|
|
2612
|
-
|
|
2613
|
-
toolCallId && /* @__PURE__ */ jsx("div", { className: "text-primary-400 text-xs", children: /* @__PURE__ */ jsxs("span", { className: "font-mono tabular-nums", children: [
|
|
2970
|
+
toolCallId && /* @__PURE__ */ jsxs("div", { className: "text-[11px] text-primary-500/80 font-mono tabular-nums", children: [
|
|
2614
2971
|
"ID: ",
|
|
2615
2972
|
toolCallId.slice(0, 16),
|
|
2616
2973
|
"..."
|
|
2617
|
-
] })
|
|
2974
|
+
] })
|
|
2618
2975
|
] }) })
|
|
2619
2976
|
] }) });
|
|
2620
2977
|
}
|
|
2978
|
+
function getDomain(url) {
|
|
2979
|
+
try {
|
|
2980
|
+
return new URL(url).hostname.replace("www.", "");
|
|
2981
|
+
} catch {
|
|
2982
|
+
return url;
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
function FaviconCircle({ domain }) {
|
|
2986
|
+
return /* @__PURE__ */ jsx(
|
|
2987
|
+
"div",
|
|
2988
|
+
{
|
|
2989
|
+
className: "flex items-center justify-center w-5 h-5 rounded-full bg-white dark:bg-zinc-800 border border-cyan-500/20 overflow-hidden",
|
|
2990
|
+
title: domain,
|
|
2991
|
+
children: /* @__PURE__ */ jsx(
|
|
2992
|
+
"img",
|
|
2993
|
+
{
|
|
2994
|
+
src: `https://www.google.com/s2/favicons?domain=${domain}&sz=32`,
|
|
2995
|
+
alt: "",
|
|
2996
|
+
className: "w-4 h-4 object-contain",
|
|
2997
|
+
loading: "lazy",
|
|
2998
|
+
onError: (e) => {
|
|
2999
|
+
const target = e.target;
|
|
3000
|
+
target.style.display = "none";
|
|
3001
|
+
const parent = target.parentElement;
|
|
3002
|
+
if (parent) {
|
|
3003
|
+
parent.textContent = domain.charAt(0).toUpperCase();
|
|
3004
|
+
parent.classList.add("text-[10px]", "font-medium", "text-cyan-400");
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
)
|
|
3009
|
+
}
|
|
3010
|
+
);
|
|
3011
|
+
}
|
|
3012
|
+
function SearchSourcesBadge({ sources }) {
|
|
3013
|
+
const [expanded, setExpanded] = useState(false);
|
|
3014
|
+
if (!sources.length) return null;
|
|
3015
|
+
const uniqueDomains = [...new Set(sources.map((s) => getDomain(s.url)))];
|
|
3016
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-2 w-full", children: [
|
|
3017
|
+
/* @__PURE__ */ jsxs(
|
|
3018
|
+
"button",
|
|
3019
|
+
{
|
|
3020
|
+
onClick: () => setExpanded(!expanded),
|
|
3021
|
+
className: cn(
|
|
3022
|
+
"inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs",
|
|
3023
|
+
"bg-cyan-500/10 hover:bg-cyan-500/20 border border-cyan-500/30",
|
|
3024
|
+
"text-cyan-300 transition-colors"
|
|
3025
|
+
),
|
|
3026
|
+
children: [
|
|
3027
|
+
/* @__PURE__ */ jsx(HugeiconsIcon, { icon: Search01Icon, size: 14 }),
|
|
3028
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Sources" }),
|
|
3029
|
+
/* @__PURE__ */ jsx("span", { className: "px-1.5 py-0.5 rounded-full bg-cyan-500/20 text-cyan-400 font-semibold", children: sources.length }),
|
|
3030
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 ml-1", children: [
|
|
3031
|
+
uniqueDomains.slice(0, 3).map((domain) => /* @__PURE__ */ jsx(FaviconCircle, { domain }, domain)),
|
|
3032
|
+
uniqueDomains.length > 3 && /* @__PURE__ */ jsxs("span", { className: "text-cyan-500/70 text-[10px] ml-0.5", children: [
|
|
3033
|
+
"+",
|
|
3034
|
+
uniqueDomains.length - 3
|
|
3035
|
+
] })
|
|
3036
|
+
] }),
|
|
3037
|
+
/* @__PURE__ */ jsx(
|
|
3038
|
+
HugeiconsIcon,
|
|
3039
|
+
{
|
|
3040
|
+
icon: ArrowRight01Icon,
|
|
3041
|
+
size: 12,
|
|
3042
|
+
className: cn("transition-transform", expanded && "rotate-90")
|
|
3043
|
+
}
|
|
3044
|
+
)
|
|
3045
|
+
]
|
|
3046
|
+
}
|
|
3047
|
+
),
|
|
3048
|
+
expanded && /* @__PURE__ */ jsx("div", { className: "mt-2 rounded-lg border border-cyan-500/20 bg-cyan-500/5 max-h-80 overflow-y-auto", children: sources.map((source, i) => {
|
|
3049
|
+
const domain = getDomain(source.url);
|
|
3050
|
+
return /* @__PURE__ */ jsxs(
|
|
3051
|
+
"a",
|
|
3052
|
+
{
|
|
3053
|
+
href: source.url,
|
|
3054
|
+
target: "_blank",
|
|
3055
|
+
rel: "noopener noreferrer",
|
|
3056
|
+
className: "flex items-start gap-2 p-2.5 border-b border-cyan-500/10 last:border-b-0 hover:bg-cyan-500/5 transition-colors",
|
|
3057
|
+
children: [
|
|
3058
|
+
/* @__PURE__ */ jsx(FaviconCircle, { domain }),
|
|
3059
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
3060
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-primary-900 hover:underline line-clamp-1", children: source.title || domain }),
|
|
3061
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: domain }),
|
|
3062
|
+
source.snippet && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground/80 line-clamp-2 mt-0.5", children: source.snippet })
|
|
3063
|
+
] })
|
|
3064
|
+
]
|
|
3065
|
+
},
|
|
3066
|
+
`${source.url}-${i}`
|
|
3067
|
+
);
|
|
3068
|
+
}) })
|
|
3069
|
+
] });
|
|
3070
|
+
}
|
|
2621
3071
|
function mapToolCallToToolPart(toolCall, resultMessage) {
|
|
2622
3072
|
const hasResult = resultMessage !== void 0;
|
|
2623
3073
|
const isError = resultMessage?.isError ?? false;
|
|
@@ -2633,11 +3083,13 @@ function mapToolCallToToolPart(toolCall, resultMessage) {
|
|
|
2633
3083
|
if (isError && resultMessage?.content?.[0]?.type === "text") {
|
|
2634
3084
|
errorText = resultMessage.content[0].text || "Unknown error";
|
|
2635
3085
|
}
|
|
3086
|
+
const outputText = resultMessage?.content?.map((part) => part.type === "text" ? String(part.text ?? "") : "").join("").trim();
|
|
3087
|
+
const output = resultMessage?.details ?? (outputText && outputText.length > 0 ? outputText : void 0);
|
|
2636
3088
|
return {
|
|
2637
3089
|
type: toolCall.name || "unknown",
|
|
2638
3090
|
state,
|
|
2639
3091
|
input: toolCall.arguments,
|
|
2640
|
-
output
|
|
3092
|
+
output,
|
|
2641
3093
|
toolCallId: toolCall.id,
|
|
2642
3094
|
errorText
|
|
2643
3095
|
};
|
|
@@ -2716,6 +3168,8 @@ function MessageItemComponent({
|
|
|
2716
3168
|
toolResultsByCallId,
|
|
2717
3169
|
forceActionsVisible = false,
|
|
2718
3170
|
isStreaming = false,
|
|
3171
|
+
isLastAssistant = false,
|
|
3172
|
+
aggregatedSearchSources,
|
|
2719
3173
|
wrapperRef,
|
|
2720
3174
|
wrapperClassName,
|
|
2721
3175
|
wrapperScrollMarginTop
|
|
@@ -2729,6 +3183,7 @@ function MessageItemComponent({
|
|
|
2729
3183
|
const timestamp = getMessageTimestamp(message);
|
|
2730
3184
|
const toolCalls = role === "assistant" ? getToolCallsFromMessage(message) : [];
|
|
2731
3185
|
const hasToolCalls = toolCalls.length > 0;
|
|
3186
|
+
const searchSources = isLastAssistant && !isStreaming && settings.showSearchSources && aggregatedSearchSources ? aggregatedSearchSources : [];
|
|
2732
3187
|
return /* @__PURE__ */ jsxs(
|
|
2733
3188
|
"div",
|
|
2734
3189
|
{
|
|
@@ -2783,6 +3238,7 @@ function MessageItemComponent({
|
|
|
2783
3238
|
toolCall.id || toolCall.name
|
|
2784
3239
|
);
|
|
2785
3240
|
}) }),
|
|
3241
|
+
searchSources.length > 0 && /* @__PURE__ */ jsx("div", { className: "w-full max-w-[900px]", children: /* @__PURE__ */ jsx(SearchSourcesBadge, { sources: searchSources }) }),
|
|
2786
3242
|
!hasToolCalls && /* @__PURE__ */ jsx(
|
|
2787
3243
|
MessageActionsBar,
|
|
2788
3244
|
{
|
|
@@ -2801,6 +3257,8 @@ function areMessagesEqual(prevProps, nextProps) {
|
|
|
2801
3257
|
return false;
|
|
2802
3258
|
}
|
|
2803
3259
|
if (prevProps.isStreaming !== nextProps.isStreaming) return false;
|
|
3260
|
+
if (prevProps.isLastAssistant !== nextProps.isLastAssistant) return false;
|
|
3261
|
+
if (prevProps.aggregatedSearchSources !== nextProps.aggregatedSearchSources) return false;
|
|
2804
3262
|
if (prevProps.wrapperClassName !== nextProps.wrapperClassName) return false;
|
|
2805
3263
|
if (prevProps.wrapperRef !== nextProps.wrapperRef) return false;
|
|
2806
3264
|
if (prevProps.wrapperScrollMarginTop !== nextProps.wrapperScrollMarginTop) {
|
|
@@ -3473,6 +3931,75 @@ function ChatMessageListComponent({
|
|
|
3473
3931
|
}
|
|
3474
3932
|
return map;
|
|
3475
3933
|
}, [messages]);
|
|
3934
|
+
const aggregatedSearchSources = useMemo(() => {
|
|
3935
|
+
const strip = (s) => {
|
|
3936
|
+
if (!s) return "";
|
|
3937
|
+
return s.replace(/SECURITY NOTICE:[\s\S]*?<<<EXTERNAL_UNTRUSTED_CONTENT>>>/g, "").replace(/<<<\/?EXTERNAL_UNTRUSTED_CONTENT>>>/g, "").replace(/<<<\/?END_EXTERNAL_UNTRUSTED_CONTENT>>>/g, "").replace(/Source: Web (?:Search|Fetch)\n---/g, "").replace(/\n{2,}/g, "\n").trim();
|
|
3938
|
+
};
|
|
3939
|
+
const extractResults = (text, sources2, seenUrls2) => {
|
|
3940
|
+
try {
|
|
3941
|
+
const parsed = JSON.parse(text);
|
|
3942
|
+
const items = Array.isArray(parsed) ? parsed : parsed?.results ?? parsed?.web?.results ?? [];
|
|
3943
|
+
if (!Array.isArray(items)) return false;
|
|
3944
|
+
let found = false;
|
|
3945
|
+
for (const item of items) {
|
|
3946
|
+
if (item?.url && item?.title && !seenUrls2.has(item.url)) {
|
|
3947
|
+
seenUrls2.add(item.url);
|
|
3948
|
+
sources2.push({
|
|
3949
|
+
title: strip(item.title),
|
|
3950
|
+
url: item.url,
|
|
3951
|
+
snippet: strip(item.description || item.snippet || item.content || "")
|
|
3952
|
+
});
|
|
3953
|
+
found = true;
|
|
3954
|
+
}
|
|
3955
|
+
}
|
|
3956
|
+
return found;
|
|
3957
|
+
} catch {
|
|
3958
|
+
return false;
|
|
3959
|
+
}
|
|
3960
|
+
};
|
|
3961
|
+
const sources = [];
|
|
3962
|
+
const seenUrls = /* @__PURE__ */ new Set();
|
|
3963
|
+
for (const msg of displayMessages) {
|
|
3964
|
+
if (msg.role !== "assistant") continue;
|
|
3965
|
+
const toolCalls = getToolCallsFromMessage(msg);
|
|
3966
|
+
for (const tc of toolCalls) {
|
|
3967
|
+
if (!tc.id) continue;
|
|
3968
|
+
const isSearch = tc.name === "web_search";
|
|
3969
|
+
const isFetch = tc.name === "web_fetch";
|
|
3970
|
+
const isExec = tc.name === "exec";
|
|
3971
|
+
if (!isSearch && !isFetch && !isExec) continue;
|
|
3972
|
+
const result = toolResultsByCallId.get(tc.id);
|
|
3973
|
+
if (!result) continue;
|
|
3974
|
+
const text = result.content?.map((p) => p.type === "text" ? String(p.text ?? "") : "").join("").trim();
|
|
3975
|
+
if (!text) continue;
|
|
3976
|
+
if (isSearch || isExec) {
|
|
3977
|
+
if (isExec) {
|
|
3978
|
+
if (!text.includes('"results"') || !text.includes('"url"')) continue;
|
|
3979
|
+
}
|
|
3980
|
+
let jsonText = text;
|
|
3981
|
+
const jsonStart = text.indexOf("{");
|
|
3982
|
+
if (jsonStart > 0) jsonText = text.slice(jsonStart);
|
|
3983
|
+
const jsonEnd = jsonText.lastIndexOf("}");
|
|
3984
|
+
if (jsonEnd > 0) jsonText = jsonText.slice(0, jsonEnd + 1);
|
|
3985
|
+
extractResults(jsonText, sources, seenUrls);
|
|
3986
|
+
} else if (isFetch) {
|
|
3987
|
+
const url = tc.arguments?.url;
|
|
3988
|
+
if (url && !seenUrls.has(url)) {
|
|
3989
|
+
seenUrls.add(url);
|
|
3990
|
+
let title;
|
|
3991
|
+
try {
|
|
3992
|
+
title = new URL(url).hostname;
|
|
3993
|
+
} catch {
|
|
3994
|
+
title = url;
|
|
3995
|
+
}
|
|
3996
|
+
sources.push({ title, url });
|
|
3997
|
+
}
|
|
3998
|
+
}
|
|
3999
|
+
}
|
|
4000
|
+
}
|
|
4001
|
+
return sources;
|
|
4002
|
+
}, [displayMessages, toolResultsByCallId]);
|
|
3476
4003
|
const lastAssistantIndex = displayMessages.map((message, index) => ({ message, index })).filter(({ message }) => message.role !== "user").map(({ index }) => index).pop();
|
|
3477
4004
|
const lastUserIndex = displayMessages.map((message, index) => ({ message, index })).filter(({ message }) => message.role === "user").map(({ index }) => index).pop();
|
|
3478
4005
|
const showTypingIndicator = waitingForResponse && (typeof lastUserIndex !== "number" || typeof lastAssistantIndex !== "number" || lastAssistantIndex < lastUserIndex);
|
|
@@ -3480,7 +4007,7 @@ function ChatMessageListComponent({
|
|
|
3480
4007
|
const hasGroup = pinToTop && groupStartIndex >= 0;
|
|
3481
4008
|
const lastAssistantMessage = typeof lastAssistantIndex === "number" ? displayMessages[lastAssistantIndex] : void 0;
|
|
3482
4009
|
const lastAssistantText = lastAssistantMessage ? textFromMessage(lastAssistantMessage) : "";
|
|
3483
|
-
const showFollowUps = !waitingForResponse && lastAssistantText.length > 0 && onFollowUpClick !== void 0 && (typeof lastUserIndex !== "number" || typeof lastAssistantIndex !== "number" || lastAssistantIndex > lastUserIndex);
|
|
4010
|
+
const showFollowUps = !waitingForResponse && !isStreaming && lastAssistantText.length > 0 && onFollowUpClick !== void 0 && (typeof lastUserIndex !== "number" || typeof lastAssistantIndex !== "number" || lastAssistantIndex > lastUserIndex);
|
|
3484
4011
|
useLayoutEffect(() => {
|
|
3485
4012
|
if (loading) return;
|
|
3486
4013
|
if (pinToTop) {
|
|
@@ -3512,7 +4039,7 @@ function ChatMessageListComponent({
|
|
|
3512
4039
|
notice && noticePosition === "start" ? notice : null,
|
|
3513
4040
|
empty && !notice ? emptyState ?? /* @__PURE__ */ jsx("div", { "aria-hidden": true }) : hasGroup ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3514
4041
|
displayMessages.slice(0, groupStartIndex).map((chatMessage, index) => {
|
|
3515
|
-
const messageKey =
|
|
4042
|
+
const messageKey = index;
|
|
3516
4043
|
const forceActionsVisible = typeof lastAssistantIndex === "number" && index === lastAssistantIndex;
|
|
3517
4044
|
const isLastAssistant = typeof lastAssistantIndex === "number" && index === lastAssistantIndex;
|
|
3518
4045
|
const hasToolCalls = chatMessage.role === "assistant" && getToolCallsFromMessage(chatMessage).length > 0;
|
|
@@ -3522,7 +4049,9 @@ function ChatMessageListComponent({
|
|
|
3522
4049
|
message: chatMessage,
|
|
3523
4050
|
toolResultsByCallId: hasToolCalls ? toolResultsByCallId : void 0,
|
|
3524
4051
|
forceActionsVisible,
|
|
3525
|
-
isStreaming: isLastAssistant && isStreaming
|
|
4052
|
+
isStreaming: isLastAssistant && isStreaming,
|
|
4053
|
+
isLastAssistant,
|
|
4054
|
+
aggregatedSearchSources: isLastAssistant ? aggregatedSearchSources : void 0
|
|
3526
4055
|
},
|
|
3527
4056
|
messageKey
|
|
3528
4057
|
);
|
|
@@ -3535,7 +4064,7 @@ function ChatMessageListComponent({
|
|
|
3535
4064
|
children: [
|
|
3536
4065
|
displayMessages.slice(groupStartIndex).map((chatMessage, index) => {
|
|
3537
4066
|
const realIndex = groupStartIndex + index;
|
|
3538
|
-
const messageKey =
|
|
4067
|
+
const messageKey = realIndex;
|
|
3539
4068
|
const forceActionsVisible = typeof lastAssistantIndex === "number" && realIndex === lastAssistantIndex;
|
|
3540
4069
|
const isLastAssistant = typeof lastAssistantIndex === "number" && realIndex === lastAssistantIndex;
|
|
3541
4070
|
const wrapperRef = realIndex === lastUserIndex ? lastUserRef : void 0;
|
|
@@ -3549,6 +4078,8 @@ function ChatMessageListComponent({
|
|
|
3549
4078
|
toolResultsByCallId: hasToolCalls ? toolResultsByCallId : void 0,
|
|
3550
4079
|
forceActionsVisible,
|
|
3551
4080
|
isStreaming: isLastAssistant && isStreaming,
|
|
4081
|
+
isLastAssistant,
|
|
4082
|
+
aggregatedSearchSources: isLastAssistant ? aggregatedSearchSources : void 0,
|
|
3552
4083
|
wrapperRef,
|
|
3553
4084
|
wrapperClassName,
|
|
3554
4085
|
wrapperScrollMarginTop
|
|
@@ -3570,7 +4101,7 @@ function ChatMessageListComponent({
|
|
|
3570
4101
|
)
|
|
3571
4102
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3572
4103
|
displayMessages.map((chatMessage, index) => {
|
|
3573
|
-
const messageKey =
|
|
4104
|
+
const messageKey = index;
|
|
3574
4105
|
const forceActionsVisible = typeof lastAssistantIndex === "number" && index === lastAssistantIndex;
|
|
3575
4106
|
const isLastAssistant = typeof lastAssistantIndex === "number" && index === lastAssistantIndex;
|
|
3576
4107
|
const hasToolCalls = chatMessage.role === "assistant" && getToolCallsFromMessage(chatMessage).length > 0;
|
|
@@ -3580,7 +4111,9 @@ function ChatMessageListComponent({
|
|
|
3580
4111
|
message: chatMessage,
|
|
3581
4112
|
toolResultsByCallId: hasToolCalls ? toolResultsByCallId : void 0,
|
|
3582
4113
|
forceActionsVisible,
|
|
3583
|
-
isStreaming: isLastAssistant && isStreaming
|
|
4114
|
+
isStreaming: isLastAssistant && isStreaming,
|
|
4115
|
+
isLastAssistant,
|
|
4116
|
+
aggregatedSearchSources: isLastAssistant ? aggregatedSearchSources : void 0
|
|
3584
4117
|
},
|
|
3585
4118
|
messageKey
|
|
3586
4119
|
);
|
|
@@ -4256,6 +4789,49 @@ async function compressImage(file) {
|
|
|
4256
4789
|
function isAcceptedImage(file) {
|
|
4257
4790
|
return ACCEPTED_IMAGE_TYPES.includes(file.type);
|
|
4258
4791
|
}
|
|
4792
|
+
async function createAttachmentFromFile(file) {
|
|
4793
|
+
const id = crypto.randomUUID();
|
|
4794
|
+
if (!isAcceptedImage(file)) {
|
|
4795
|
+
return {
|
|
4796
|
+
id,
|
|
4797
|
+
file,
|
|
4798
|
+
preview: null,
|
|
4799
|
+
type: "image",
|
|
4800
|
+
base64: null,
|
|
4801
|
+
error: "Unsupported file type. Please use PNG, JPG, GIF, or WebP images."
|
|
4802
|
+
};
|
|
4803
|
+
}
|
|
4804
|
+
if (file.size > MAX_FILE_SIZE) {
|
|
4805
|
+
return {
|
|
4806
|
+
id,
|
|
4807
|
+
file,
|
|
4808
|
+
preview: null,
|
|
4809
|
+
type: "image",
|
|
4810
|
+
base64: null,
|
|
4811
|
+
error: "Image is too large. Maximum size is 10MB."
|
|
4812
|
+
};
|
|
4813
|
+
}
|
|
4814
|
+
try {
|
|
4815
|
+
const base64 = await compressImage(file);
|
|
4816
|
+
const preview = URL.createObjectURL(file);
|
|
4817
|
+
return {
|
|
4818
|
+
id,
|
|
4819
|
+
file,
|
|
4820
|
+
preview,
|
|
4821
|
+
type: "image",
|
|
4822
|
+
base64
|
|
4823
|
+
};
|
|
4824
|
+
} catch (err) {
|
|
4825
|
+
return {
|
|
4826
|
+
id,
|
|
4827
|
+
file,
|
|
4828
|
+
preview: null,
|
|
4829
|
+
type: "image",
|
|
4830
|
+
base64: null,
|
|
4831
|
+
error: err instanceof Error ? err.message : "Failed to process image"
|
|
4832
|
+
};
|
|
4833
|
+
}
|
|
4834
|
+
}
|
|
4259
4835
|
function AttachmentButton({
|
|
4260
4836
|
onFileSelect,
|
|
4261
4837
|
disabled = false,
|
|
@@ -4270,49 +4846,8 @@ function AttachmentButton({
|
|
|
4270
4846
|
const file = event.target.files?.[0];
|
|
4271
4847
|
if (!file) return;
|
|
4272
4848
|
event.target.value = "";
|
|
4273
|
-
const
|
|
4274
|
-
|
|
4275
|
-
onFileSelect({
|
|
4276
|
-
id,
|
|
4277
|
-
file,
|
|
4278
|
-
preview: null,
|
|
4279
|
-
type: "image",
|
|
4280
|
-
base64: null,
|
|
4281
|
-
error: "Unsupported file type. Please use PNG, JPG, GIF, or WebP images."
|
|
4282
|
-
});
|
|
4283
|
-
return;
|
|
4284
|
-
}
|
|
4285
|
-
if (file.size > MAX_FILE_SIZE) {
|
|
4286
|
-
onFileSelect({
|
|
4287
|
-
id,
|
|
4288
|
-
file,
|
|
4289
|
-
preview: null,
|
|
4290
|
-
type: "image",
|
|
4291
|
-
base64: null,
|
|
4292
|
-
error: "Image is too large. Maximum size is 10MB."
|
|
4293
|
-
});
|
|
4294
|
-
return;
|
|
4295
|
-
}
|
|
4296
|
-
try {
|
|
4297
|
-
const base64 = await compressImage(file);
|
|
4298
|
-
const preview = URL.createObjectURL(file);
|
|
4299
|
-
onFileSelect({
|
|
4300
|
-
id,
|
|
4301
|
-
file,
|
|
4302
|
-
preview,
|
|
4303
|
-
type: "image",
|
|
4304
|
-
base64
|
|
4305
|
-
});
|
|
4306
|
-
} catch (err) {
|
|
4307
|
-
onFileSelect({
|
|
4308
|
-
id,
|
|
4309
|
-
file,
|
|
4310
|
-
preview: null,
|
|
4311
|
-
type: "image",
|
|
4312
|
-
base64: null,
|
|
4313
|
-
error: err instanceof Error ? err.message : "Failed to process image"
|
|
4314
|
-
});
|
|
4315
|
-
}
|
|
4849
|
+
const attachment = await createAttachmentFromFile(file);
|
|
4850
|
+
onFileSelect(attachment);
|
|
4316
4851
|
},
|
|
4317
4852
|
[onFileSelect]
|
|
4318
4853
|
);
|
|
@@ -4537,6 +5072,14 @@ function ChatComposerComponent({
|
|
|
4537
5072
|
const [attachments, setAttachments] = useState([]);
|
|
4538
5073
|
const [selectedCommandIndex, setSelectedCommandIndex] = useState(0);
|
|
4539
5074
|
const [slashMenuDismissed, setSlashMenuDismissed] = useState(false);
|
|
5075
|
+
const [isDragActive, setIsDragActive] = useState(false);
|
|
5076
|
+
const [isRecording, setIsRecording] = useState(false);
|
|
5077
|
+
const [recordingTime, setRecordingTime] = useState(0);
|
|
5078
|
+
const [sttLoading, setSttLoading] = useState(false);
|
|
5079
|
+
const mediaRecorderRef = useRef(null);
|
|
5080
|
+
const recordingChunksRef = useRef([]);
|
|
5081
|
+
const recordingTimerRef = useRef(null);
|
|
5082
|
+
const webSpeechRef = useRef(null);
|
|
4540
5083
|
const promptRef = useRef(null);
|
|
4541
5084
|
const showSlashCommands = useMemo(() => /^\/\S*$/.test(value) && !slashMenuDismissed, [value, slashMenuDismissed]);
|
|
4542
5085
|
const slashQuery = useMemo(() => showSlashCommands ? value.slice(1).toLowerCase() : "", [showSlashCommands, value]);
|
|
@@ -4577,6 +5120,30 @@ function ChatComposerComponent({
|
|
|
4577
5120
|
const handleRemoveAttachment = useCallback((id) => {
|
|
4578
5121
|
setAttachments((prev) => prev.filter((a) => a.id !== id));
|
|
4579
5122
|
}, []);
|
|
5123
|
+
const handleDragOver = useCallback((event) => {
|
|
5124
|
+
const hasFiles = Array.from(event.dataTransfer.types).includes("Files");
|
|
5125
|
+
if (!hasFiles) return;
|
|
5126
|
+
event.preventDefault();
|
|
5127
|
+
event.dataTransfer.dropEffect = "copy";
|
|
5128
|
+
setIsDragActive(true);
|
|
5129
|
+
}, []);
|
|
5130
|
+
const handleDragLeave = useCallback((event) => {
|
|
5131
|
+
event.preventDefault();
|
|
5132
|
+
const nextTarget = event.relatedTarget;
|
|
5133
|
+
if (nextTarget && event.currentTarget.contains(nextTarget)) return;
|
|
5134
|
+
setIsDragActive(false);
|
|
5135
|
+
}, []);
|
|
5136
|
+
const handleDrop = useCallback(async (event) => {
|
|
5137
|
+
event.preventDefault();
|
|
5138
|
+
setIsDragActive(false);
|
|
5139
|
+
const files = Array.from(event.dataTransfer.files ?? []);
|
|
5140
|
+
if (files.length === 0) return;
|
|
5141
|
+
const imageFiles = files.filter((file) => isAcceptedImage(file));
|
|
5142
|
+
if (imageFiles.length === 0) return;
|
|
5143
|
+
const newAttachments = await Promise.all(imageFiles.map((file) => createAttachmentFromFile(file)));
|
|
5144
|
+
setAttachments((prev) => [...prev, ...newAttachments]);
|
|
5145
|
+
focusPrompt();
|
|
5146
|
+
}, [focusPrompt]);
|
|
4580
5147
|
const setComposerValue = useCallback(
|
|
4581
5148
|
(nextValue) => {
|
|
4582
5149
|
setValue(nextValue);
|
|
@@ -4661,75 +5228,252 @@ function ChatComposerComponent({
|
|
|
4661
5228
|
},
|
|
4662
5229
|
[showSlashCommands, filteredSlashCommands, selectedCommandIndex, selectSlashCommand]
|
|
4663
5230
|
);
|
|
5231
|
+
useEffect(() => {
|
|
5232
|
+
return () => {
|
|
5233
|
+
if (recordingTimerRef.current) clearInterval(recordingTimerRef.current);
|
|
5234
|
+
if (mediaRecorderRef.current && mediaRecorderRef.current.state !== "inactive") {
|
|
5235
|
+
mediaRecorderRef.current.stop();
|
|
5236
|
+
}
|
|
5237
|
+
if (webSpeechRef.current) webSpeechRef.current.abort();
|
|
5238
|
+
};
|
|
5239
|
+
}, []);
|
|
5240
|
+
const getSttProvider = useCallback(() => {
|
|
5241
|
+
if (typeof window === "undefined") return "auto";
|
|
5242
|
+
try {
|
|
5243
|
+
return localStorage.getItem("opencami-stt-provider") || "auto";
|
|
5244
|
+
} catch {
|
|
5245
|
+
return "auto";
|
|
5246
|
+
}
|
|
5247
|
+
}, []);
|
|
5248
|
+
const stopRecording = useCallback(() => {
|
|
5249
|
+
if (mediaRecorderRef.current && mediaRecorderRef.current.state !== "inactive") {
|
|
5250
|
+
mediaRecorderRef.current.stop();
|
|
5251
|
+
}
|
|
5252
|
+
if (webSpeechRef.current) {
|
|
5253
|
+
webSpeechRef.current.stop();
|
|
5254
|
+
}
|
|
5255
|
+
if (recordingTimerRef.current) {
|
|
5256
|
+
clearInterval(recordingTimerRef.current);
|
|
5257
|
+
recordingTimerRef.current = null;
|
|
5258
|
+
}
|
|
5259
|
+
setIsRecording(false);
|
|
5260
|
+
setRecordingTime(0);
|
|
5261
|
+
}, []);
|
|
5262
|
+
const startRecording = useCallback(async () => {
|
|
5263
|
+
const provider = getSttProvider();
|
|
5264
|
+
if (provider === "browser") {
|
|
5265
|
+
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
5266
|
+
if (!SpeechRecognition) {
|
|
5267
|
+
alert("Web Speech API is not supported in this browser.");
|
|
5268
|
+
return;
|
|
5269
|
+
}
|
|
5270
|
+
const recognition = new SpeechRecognition();
|
|
5271
|
+
recognition.continuous = true;
|
|
5272
|
+
recognition.interimResults = false;
|
|
5273
|
+
recognition.lang = navigator.language || "en-US";
|
|
5274
|
+
webSpeechRef.current = recognition;
|
|
5275
|
+
setIsRecording(true);
|
|
5276
|
+
setRecordingTime(0);
|
|
5277
|
+
recordingTimerRef.current = setInterval(() => {
|
|
5278
|
+
setRecordingTime((t) => {
|
|
5279
|
+
if (t >= 119) {
|
|
5280
|
+
stopRecording();
|
|
5281
|
+
return 0;
|
|
5282
|
+
}
|
|
5283
|
+
return t + 1;
|
|
5284
|
+
});
|
|
5285
|
+
}, 1e3);
|
|
5286
|
+
let transcript = "";
|
|
5287
|
+
recognition.onresult = (event) => {
|
|
5288
|
+
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
5289
|
+
if (event.results[i].isFinal) {
|
|
5290
|
+
transcript += event.results[i][0].transcript;
|
|
5291
|
+
}
|
|
5292
|
+
}
|
|
5293
|
+
};
|
|
5294
|
+
recognition.onend = () => {
|
|
5295
|
+
setIsRecording(false);
|
|
5296
|
+
setRecordingTime(0);
|
|
5297
|
+
if (recordingTimerRef.current) clearInterval(recordingTimerRef.current);
|
|
5298
|
+
if (transcript.trim()) {
|
|
5299
|
+
setValue((prev) => prev + (prev ? " " : "") + transcript.trim());
|
|
5300
|
+
focusPrompt();
|
|
5301
|
+
}
|
|
5302
|
+
};
|
|
5303
|
+
recognition.onerror = () => {
|
|
5304
|
+
setIsRecording(false);
|
|
5305
|
+
setRecordingTime(0);
|
|
5306
|
+
if (recordingTimerRef.current) clearInterval(recordingTimerRef.current);
|
|
5307
|
+
};
|
|
5308
|
+
recognition.start();
|
|
5309
|
+
return;
|
|
5310
|
+
}
|
|
5311
|
+
try {
|
|
5312
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
5313
|
+
const mimeType = MediaRecorder.isTypeSupported("audio/webm") ? "audio/webm" : "audio/mp4";
|
|
5314
|
+
const recorder = new MediaRecorder(stream, { mimeType });
|
|
5315
|
+
mediaRecorderRef.current = recorder;
|
|
5316
|
+
recordingChunksRef.current = [];
|
|
5317
|
+
recorder.ondataavailable = (e) => {
|
|
5318
|
+
if (e.data.size > 0) recordingChunksRef.current.push(e.data);
|
|
5319
|
+
};
|
|
5320
|
+
recorder.onstop = async () => {
|
|
5321
|
+
stream.getTracks().forEach((t) => t.stop());
|
|
5322
|
+
const audioBlob = new Blob(recordingChunksRef.current, { type: mimeType });
|
|
5323
|
+
if (audioBlob.size === 0) return;
|
|
5324
|
+
setSttLoading(true);
|
|
5325
|
+
try {
|
|
5326
|
+
const formData = new FormData();
|
|
5327
|
+
formData.append("audio", audioBlob, `recording.${mimeType === "audio/webm" ? "webm" : "mp4"}`);
|
|
5328
|
+
if (provider !== "auto") formData.append("provider", provider);
|
|
5329
|
+
const res = await fetch("/api/stt", { method: "POST", body: formData });
|
|
5330
|
+
const data = await res.json();
|
|
5331
|
+
if (data.ok && data.text) {
|
|
5332
|
+
setValue((prev) => prev + (prev ? " " : "") + data.text);
|
|
5333
|
+
focusPrompt();
|
|
5334
|
+
} else if (!data.ok) {
|
|
5335
|
+
console.warn("STT failed:", data.error);
|
|
5336
|
+
alert(data.error || "Speech-to-text failed. Try the Browser provider in Settings.");
|
|
5337
|
+
}
|
|
5338
|
+
} catch (err) {
|
|
5339
|
+
console.warn("STT request failed:", err);
|
|
5340
|
+
alert("Could not reach speech-to-text service.");
|
|
5341
|
+
} finally {
|
|
5342
|
+
setSttLoading(false);
|
|
5343
|
+
}
|
|
5344
|
+
};
|
|
5345
|
+
setIsRecording(true);
|
|
5346
|
+
setRecordingTime(0);
|
|
5347
|
+
recordingTimerRef.current = setInterval(() => {
|
|
5348
|
+
setRecordingTime((t) => {
|
|
5349
|
+
if (t >= 119) {
|
|
5350
|
+
stopRecording();
|
|
5351
|
+
return 0;
|
|
5352
|
+
}
|
|
5353
|
+
return t + 1;
|
|
5354
|
+
});
|
|
5355
|
+
}, 1e3);
|
|
5356
|
+
recorder.start();
|
|
5357
|
+
} catch (err) {
|
|
5358
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
5359
|
+
if (msg.includes("NotAllowedError") || msg.includes("Permission")) {
|
|
5360
|
+
try {
|
|
5361
|
+
const status = await navigator.permissions.query({ name: "microphone" });
|
|
5362
|
+
if (status.state === "denied") {
|
|
5363
|
+
alert("Microphone access is blocked. Please enable it in your browser/app settings.");
|
|
5364
|
+
} else {
|
|
5365
|
+
alert("Microphone permission was not granted. Please try again and allow access when prompted.");
|
|
5366
|
+
}
|
|
5367
|
+
} catch {
|
|
5368
|
+
alert("Could not access microphone. Please check your browser settings and allow microphone access for this site.");
|
|
5369
|
+
}
|
|
5370
|
+
} else {
|
|
5371
|
+
alert("Could not access microphone: " + msg);
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5374
|
+
}, [getSttProvider, stopRecording, focusPrompt]);
|
|
5375
|
+
const handleMicClick = useCallback(() => {
|
|
5376
|
+
if (isRecording) {
|
|
5377
|
+
stopRecording();
|
|
5378
|
+
} else {
|
|
5379
|
+
startRecording();
|
|
5380
|
+
}
|
|
5381
|
+
}, [isRecording, stopRecording, startRecording]);
|
|
4664
5382
|
const validAttachments = attachments.filter((a) => !a.error && a.base64);
|
|
4665
5383
|
const submitDisabled = disabled || value.trim().length === 0 && validAttachments.length === 0;
|
|
4666
|
-
return /* @__PURE__ */
|
|
5384
|
+
return /* @__PURE__ */ jsxs(
|
|
4667
5385
|
"div",
|
|
4668
5386
|
{
|
|
4669
5387
|
className: "mx-auto w-full max-w-full px-2 md:px-5 sm:max-w-[768px] sm:min-w-[400px] relative pb-1 md:pb-3",
|
|
4670
5388
|
ref: wrapperRef,
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
{
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
5389
|
+
onDragOver: handleDragOver,
|
|
5390
|
+
onDragLeave: handleDragLeave,
|
|
5391
|
+
onDrop: handleDrop,
|
|
5392
|
+
children: [
|
|
5393
|
+
isDragActive && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-2 z-20 flex items-center justify-center rounded-2xl border-2 border-dashed border-primary-400 bg-primary-50/90 text-sm font-medium text-primary-700", children: "Drop image here" }),
|
|
5394
|
+
/* @__PURE__ */ jsxs(
|
|
5395
|
+
PromptInput,
|
|
5396
|
+
{
|
|
5397
|
+
value,
|
|
5398
|
+
onValueChange: handleValueChange,
|
|
5399
|
+
onSubmit: handleSubmit,
|
|
5400
|
+
isLoading,
|
|
5401
|
+
disabled,
|
|
5402
|
+
children: [
|
|
5403
|
+
/* @__PURE__ */ jsx(
|
|
5404
|
+
AttachmentPreviewList,
|
|
5405
|
+
{
|
|
5406
|
+
attachments,
|
|
5407
|
+
onRemove: handleRemoveAttachment
|
|
5408
|
+
}
|
|
5409
|
+
),
|
|
5410
|
+
showSlashCommands && filteredSlashCommands.length > 0 && /* @__PURE__ */ jsx(
|
|
5411
|
+
SlashCommandMenu,
|
|
5412
|
+
{
|
|
5413
|
+
commands: filteredSlashCommands,
|
|
5414
|
+
selectedIndex: Math.min(selectedCommandIndex, filteredSlashCommands.length - 1),
|
|
5415
|
+
onSelect: selectSlashCommand
|
|
5416
|
+
}
|
|
5417
|
+
),
|
|
5418
|
+
/* @__PURE__ */ jsx(
|
|
5419
|
+
PromptInputTextarea,
|
|
5420
|
+
{
|
|
5421
|
+
placeholder: "Type a message…",
|
|
5422
|
+
inputRef: setPromptRef,
|
|
5423
|
+
onKeyDown: handleComposerKeyDown
|
|
5424
|
+
}
|
|
5425
|
+
),
|
|
5426
|
+
/* @__PURE__ */ jsxs(PromptInputActions, { className: "justify-between px-3", children: [
|
|
5427
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
5428
|
+
/* @__PURE__ */ jsx(ModelSelector, { onModelChange: setSelectedModel }),
|
|
5429
|
+
/* @__PURE__ */ jsx(PersonaPicker, { onSelect: handlePersonaSelect }),
|
|
5430
|
+
/* @__PURE__ */ jsx(CommandHelp, { onCommandSelect: (cmd) => handleValueChange(cmd + " ") })
|
|
5431
|
+
] }),
|
|
5432
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
5433
|
+
/* @__PURE__ */ jsx(PromptInputAction, { tooltip: "Attach file", children: /* @__PURE__ */ jsx(
|
|
5434
|
+
AttachmentButton,
|
|
5435
|
+
{
|
|
5436
|
+
onFileSelect: handleFileSelect,
|
|
5437
|
+
disabled
|
|
5438
|
+
}
|
|
5439
|
+
) }),
|
|
5440
|
+
/* @__PURE__ */ jsx(PromptInputAction, { tooltip: isRecording ? "Stop recording" : "Voice input", children: /* @__PURE__ */ jsx(
|
|
5441
|
+
Button,
|
|
5442
|
+
{
|
|
5443
|
+
onClick: handleMicClick,
|
|
5444
|
+
disabled: disabled || sttLoading,
|
|
5445
|
+
size: "icon-sm",
|
|
5446
|
+
variant: isRecording ? "destructive" : "ghost",
|
|
5447
|
+
className: `rounded-full ${isRecording ? "animate-pulse" : ""}`,
|
|
5448
|
+
"aria-label": isRecording ? "Stop recording" : "Voice input",
|
|
5449
|
+
children: sttLoading ? /* @__PURE__ */ jsx("span", { className: "size-4 animate-spin rounded-full border-2 border-current border-t-transparent" }) : isRecording ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
5450
|
+
/* @__PURE__ */ jsx("span", { className: "size-2 rounded-full bg-red-500" }),
|
|
5451
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs tabular-nums", children: [
|
|
5452
|
+
Math.floor(recordingTime / 60),
|
|
5453
|
+
":",
|
|
5454
|
+
String(recordingTime % 60).padStart(2, "0")
|
|
5455
|
+
] }),
|
|
5456
|
+
/* @__PURE__ */ jsx(HugeiconsIcon, { icon: StopIcon, size: 14, strokeWidth: 2 })
|
|
5457
|
+
] }) : /* @__PURE__ */ jsx(HugeiconsIcon, { icon: Mic02Icon, size: 18, strokeWidth: 2 })
|
|
5458
|
+
}
|
|
5459
|
+
) }),
|
|
5460
|
+
/* @__PURE__ */ jsx(PromptInputAction, { tooltip: "Send message", children: /* @__PURE__ */ jsx(
|
|
5461
|
+
Button,
|
|
5462
|
+
{
|
|
5463
|
+
onClick: handleSubmit,
|
|
5464
|
+
disabled: submitDisabled,
|
|
5465
|
+
size: "icon-sm",
|
|
5466
|
+
className: "rounded-full",
|
|
5467
|
+
"aria-label": "Send message",
|
|
5468
|
+
children: /* @__PURE__ */ jsx(HugeiconsIcon, { icon: ArrowUp02Icon, size: 18, strokeWidth: 2 })
|
|
5469
|
+
}
|
|
5470
|
+
) })
|
|
5471
|
+
] })
|
|
4728
5472
|
] })
|
|
4729
|
-
]
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
5473
|
+
]
|
|
5474
|
+
}
|
|
5475
|
+
)
|
|
5476
|
+
]
|
|
4733
5477
|
}
|
|
4734
5478
|
);
|
|
4735
5479
|
}
|
|
@@ -5102,11 +5846,15 @@ function useStreaming(options) {
|
|
|
5102
5846
|
const onErrorRef = useRef(options.onError);
|
|
5103
5847
|
onDoneRef.current = options.onDone;
|
|
5104
5848
|
onErrorRef.current = options.onError;
|
|
5105
|
-
const stop = useCallback(() => {
|
|
5849
|
+
const stop = useCallback((options2) => {
|
|
5106
5850
|
if (eventSourceRef.current) {
|
|
5107
5851
|
eventSourceRef.current.close();
|
|
5108
5852
|
eventSourceRef.current = null;
|
|
5109
5853
|
}
|
|
5854
|
+
if (options2?.preserveState) {
|
|
5855
|
+
setState((prev) => ({ ...prev, active: false }));
|
|
5856
|
+
return;
|
|
5857
|
+
}
|
|
5110
5858
|
setState(INITIAL_STATE);
|
|
5111
5859
|
}, []);
|
|
5112
5860
|
const start = useCallback(
|
|
@@ -5154,7 +5902,7 @@ function useStreaming(options) {
|
|
|
5154
5902
|
const data = JSON.parse(e.data);
|
|
5155
5903
|
es.close();
|
|
5156
5904
|
eventSourceRef.current = null;
|
|
5157
|
-
setState(
|
|
5905
|
+
setState((prev) => ({ ...prev, active: false }));
|
|
5158
5906
|
onDoneRef.current(data.sessionKey);
|
|
5159
5907
|
} catch {
|
|
5160
5908
|
}
|
|
@@ -5313,12 +6061,12 @@ function useSwipeGesture(options) {
|
|
|
5313
6061
|
};
|
|
5314
6062
|
}
|
|
5315
6063
|
const KeyboardShortcutsDialog = lazy(
|
|
5316
|
-
() => import("./keyboard-shortcuts-dialog-
|
|
6064
|
+
() => import("./keyboard-shortcuts-dialog-7OEtXUlW.js").then((m) => ({
|
|
5317
6065
|
default: m.KeyboardShortcutsDialog
|
|
5318
6066
|
}))
|
|
5319
6067
|
);
|
|
5320
6068
|
const SearchDialog = lazy(
|
|
5321
|
-
() => import("./search-dialog-
|
|
6069
|
+
() => import("./search-dialog-BE2ZBkj0.js").then((m) => ({
|
|
5322
6070
|
default: m.SearchDialog
|
|
5323
6071
|
}))
|
|
5324
6072
|
);
|
|
@@ -5462,26 +6210,31 @@ function ChatScreen({
|
|
|
5462
6210
|
refreshHistoryRef.current();
|
|
5463
6211
|
}, FAST_POLL_MS);
|
|
5464
6212
|
}, [activeFriendlyId, isNewChat]);
|
|
5465
|
-
const
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
6213
|
+
const handleStreamDoneRef = useRef(() => {
|
|
6214
|
+
});
|
|
6215
|
+
const handleStreamErrorRef = useRef(() => {
|
|
6216
|
+
});
|
|
6217
|
+
const { streaming, startStream, stopStream } = useStreaming({
|
|
6218
|
+
onDone: (sk) => handleStreamDoneRef.current(sk),
|
|
6219
|
+
onError: (err) => handleStreamErrorRef.current(err)
|
|
6220
|
+
});
|
|
6221
|
+
handleStreamDoneRef.current = useCallback(
|
|
6222
|
+
async (_sk) => {
|
|
6223
|
+
await historyQuery.refetch();
|
|
6224
|
+
stopStream({ preserveState: true });
|
|
5469
6225
|
streamFinish();
|
|
6226
|
+
void queryClient.invalidateQueries({ queryKey: chatQueryKeys.sessions });
|
|
5470
6227
|
},
|
|
5471
|
-
[historyQuery, queryClient, streamFinish]
|
|
6228
|
+
[historyQuery, queryClient, stopStream, streamFinish]
|
|
5472
6229
|
);
|
|
5473
|
-
|
|
6230
|
+
handleStreamErrorRef.current = useCallback(
|
|
5474
6231
|
(_err) => {
|
|
5475
6232
|
console.warn("[stream] SSE error, falling back to polling");
|
|
5476
6233
|
},
|
|
5477
6234
|
[]
|
|
5478
6235
|
);
|
|
5479
|
-
const { streaming, startStream, stopStream } = useStreaming({
|
|
5480
|
-
onDone: handleStreamDone,
|
|
5481
|
-
onError: handleStreamError
|
|
5482
|
-
});
|
|
5483
6236
|
const streamingMessage = useMemo(() => {
|
|
5484
|
-
if (!streaming.
|
|
6237
|
+
if (!streaming.text) return null;
|
|
5485
6238
|
const content = [];
|
|
5486
6239
|
for (const tool of streaming.tools) {
|
|
5487
6240
|
content.push({
|
|
@@ -5494,23 +6247,22 @@ function ChatScreen({
|
|
|
5494
6247
|
return {
|
|
5495
6248
|
role: "assistant",
|
|
5496
6249
|
content,
|
|
6250
|
+
id: "__streaming__",
|
|
5497
6251
|
__streaming: true,
|
|
5498
6252
|
timestamp: Date.now()
|
|
5499
6253
|
};
|
|
5500
|
-
}, [streaming.
|
|
6254
|
+
}, [streaming.text, streaming.tools]);
|
|
5501
6255
|
const messagesWithStreaming = useMemo(() => {
|
|
5502
6256
|
if (!streamingMessage) return displayMessages;
|
|
5503
|
-
const
|
|
5504
|
-
|
|
5505
|
-
if (lastMsg?.role === "assistant" && streamingMessage) {
|
|
6257
|
+
const lastMsg = displayMessages[displayMessages.length - 1];
|
|
6258
|
+
if (lastMsg?.role === "assistant") {
|
|
5506
6259
|
const lastText = textFromMessage(lastMsg);
|
|
5507
|
-
if (
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
}
|
|
6260
|
+
if (lastText.length >= streaming.text.length) return displayMessages;
|
|
6261
|
+
const msgs = [...displayMessages];
|
|
6262
|
+
msgs[msgs.length - 1] = streamingMessage;
|
|
5511
6263
|
return msgs;
|
|
5512
6264
|
}
|
|
5513
|
-
return [...
|
|
6265
|
+
return [...displayMessages, streamingMessage];
|
|
5514
6266
|
}, [displayMessages, streamingMessage, streaming.text]);
|
|
5515
6267
|
const stableContentStyle = useMemo(() => ({}), []);
|
|
5516
6268
|
refreshHistoryRef.current = function refreshHistory() {
|