@qwen-code/qwen-code 0.19.12 → 0.20.0-nightly.20260720.0c271659d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. package/bundled/qc-helper/docs/integration-github-action.md +1 -1
  2. package/bundled/qc-helper/docs/qwen-serve.md +42 -5
  3. package/bundled/review/DESIGN.md +2 -2
  4. package/bundled/review/SKILL.md +13 -9
  5. package/chunks/{MaxSizedBox-QOXLJGAF.js → MaxSizedBox-ED3QND6V.js} +30 -27
  6. package/chunks/{StandaloneSessionPicker-FLV6CGYJ.js → StandaloneSessionPicker-NQVAOTKS.js} +50 -45
  7. package/chunks/{acpAgent-OB2CTF3P.js → acpAgent-HOBFF5B6.js} +353 -130
  8. package/chunks/{agent-CKSI7BTR.js → agent-J7EPFLA6.js} +22 -22
  9. package/chunks/{agent-headless-U36LIYTU.js → agent-headless-RRG3JU7Q.js} +22 -22
  10. package/chunks/{anthropicContentGenerator-ZZRGFEES.js → anthropicContentGenerator-HVKLXOOU.js} +6 -5
  11. package/chunks/{artifact-tool-PHO5XEGZ.js → artifact-tool-WBCAMD3O.js} +2 -2
  12. package/chunks/{askUserQuestion-CEPBT47X.js → askUserQuestion-6DZC4UV5.js} +2 -2
  13. package/chunks/{bridge-AIKTINJG.js → bridge-OW5FZ6BF.js} +25 -25
  14. package/chunks/build-SSCNEHZZ.js +62 -0
  15. package/chunks/{channel-worker-group-NEUVTPB2.js → channel-worker-group-53CMOPFT.js} +4 -4
  16. package/chunks/{channel-worker-manager-7CQVOVWV.js → channel-worker-manager-UTXILKC2.js} +4 -4
  17. package/chunks/{channel-worker-supervisor-3BU2KNCZ.js → channel-worker-supervisor-ZGO2W2MD.js} +3 -3
  18. package/chunks/chunk-27AJEU6G.js +442 -0
  19. package/chunks/{chunk-BABX5XRO.js → chunk-2HOVDT7W.js} +1 -1
  20. package/chunks/{chunk-GW7BONBU.js → chunk-2JOLZA6L.js} +5 -5
  21. package/chunks/{chunk-ZSDFNE6Y.js → chunk-2TDSM7I6.js} +3 -3
  22. package/chunks/{chunk-6IITZE7O.js → chunk-2YJLFCYI.js} +7 -7
  23. package/chunks/{chunk-VEFR4XJQ.js → chunk-37MGCVTS.js} +1 -1
  24. package/chunks/{chunk-3B6PSWHE.js → chunk-3ML52IFS.js} +4 -4
  25. package/chunks/{chunk-TKASNYDS.js → chunk-3QR5MOHP.js} +2 -2
  26. package/chunks/{chunk-KRMARA3A.js → chunk-3SNKL6L6.js} +29 -13
  27. package/chunks/{chunk-DJ4VHAFJ.js → chunk-3ZL6YMO2.js} +3 -3
  28. package/chunks/chunk-43T5WDQ7.js +127 -0
  29. package/chunks/{chunk-W6CQPLWM.js → chunk-4ODB7WIB.js} +1 -1
  30. package/chunks/{chunk-CHPQFLW6.js → chunk-4UH63YE5.js} +5 -5
  31. package/chunks/{chunk-2CCDMJM7.js → chunk-53OPIXUE.js} +3 -3
  32. package/chunks/{chunk-HTHUX2T5.js → chunk-5QWWOFGG.js} +0 -1
  33. package/chunks/{chunk-3DJY4IFO.js → chunk-5SCI6E3E.js} +1 -1
  34. package/chunks/{chunk-4CHDYDG3.js → chunk-6EFTQYW7.js} +1 -1
  35. package/chunks/{chunk-OBSLEYCD.js → chunk-6HQW55TM.js} +29 -2
  36. package/chunks/{chunk-N47VAEAJ.js → chunk-6MN6XJTR.js} +2379 -1291
  37. package/chunks/{chunk-UCTCDLDS.js → chunk-6VGRTGOG.js} +1 -1
  38. package/chunks/{chunk-KNGZ5EYL.js → chunk-7JQK6FXK.js} +198 -120
  39. package/chunks/{chunk-2476XGOU.js → chunk-A4TJMY65.js} +1 -1
  40. package/chunks/{chunk-67Q33DQY.js → chunk-AMRWCMX4.js} +4 -4
  41. package/chunks/{chunk-XAAEDML2.js → chunk-AYCDXHZB.js} +1 -1
  42. package/chunks/{chunk-VAJS2E2D.js → chunk-BDBMYST4.js} +1 -1
  43. package/chunks/{chunk-F2RR4HO2.js → chunk-BVLROR2T.js} +1 -1
  44. package/chunks/{chunk-UE5TZ55T.js → chunk-C27BYUX6.js} +29 -2
  45. package/chunks/{chunk-PK7COE5O.js → chunk-CL7IRYTA.js} +1 -1
  46. package/chunks/{chunk-KMJOMWHE.js → chunk-COWNNAWJ.js} +1 -1
  47. package/chunks/{chunk-UOA2IHRI.js → chunk-CPCVCKKF.js} +1 -1
  48. package/chunks/{chunk-4RPARQ5D.js → chunk-D2VIDMVM.js} +2 -2
  49. package/chunks/{chunk-4MPYGENG.js → chunk-DCCW7CRR.js} +6 -6
  50. package/chunks/chunk-DIKIJS6Z.js +114 -0
  51. package/chunks/{chunk-ETN2G32U.js → chunk-DR5AUNJ2.js} +4 -4
  52. package/chunks/{chunk-6ETOSWAO.js → chunk-DSBCU6JY.js} +3 -3
  53. package/chunks/{chunk-LKR7QQ63.js → chunk-EAUYY7SS.js} +3 -3
  54. package/chunks/{chunk-J2MKYJKZ.js → chunk-EIAK6Q2B.js} +2 -2
  55. package/chunks/{chunk-WEPXQKGP.js → chunk-EZVDJFZ7.js} +1 -1
  56. package/chunks/{chunk-WHQNBBWW.js → chunk-FLSVD6BS.js} +2 -2
  57. package/chunks/{chunk-3ESL7JXA.js → chunk-FODJ5Q5K.js} +3 -3
  58. package/chunks/{chunk-4XCVGEEX.js → chunk-FSL5W5TI.js} +3 -3
  59. package/chunks/{chunk-NE6HHLL3.js → chunk-FWT66O5E.js} +2 -2
  60. package/chunks/{chunk-OSSDHJDU.js → chunk-G45X5TRN.js} +1 -1
  61. package/chunks/{chunk-ZGT623SG.js → chunk-G6MDKXDP.js} +12 -12
  62. package/chunks/{chunk-KANTXY7B.js → chunk-GKY2OJ7R.js} +2 -2
  63. package/chunks/chunk-GMGDLUC7.js +37 -0
  64. package/chunks/{chunk-J6NT5YTN.js → chunk-H2XVO6NE.js} +1 -289
  65. package/chunks/{chunk-XSEWNUMZ.js → chunk-I4HZ4GOD.js} +8 -8
  66. package/chunks/{chunk-CPU6I5YV.js → chunk-I6JUVU7J.js} +34 -24
  67. package/chunks/{chunk-UZC5VPOJ.js → chunk-IDGTC5AS.js} +3 -3
  68. package/chunks/{chunk-QIFTJDBY.js → chunk-INL2RSLA.js} +1 -1
  69. package/chunks/{chunk-GSPWDTYY.js → chunk-INQQM52C.js} +18 -16
  70. package/chunks/{chunk-HVGJWOR6.js → chunk-JBCFW3IL.js} +2 -2
  71. package/chunks/{chunk-LPHGXXZX.js → chunk-JD3MKVKL.js} +1 -1
  72. package/chunks/{chunk-GCY7QTCE.js → chunk-JDPCOUZ3.js} +1602 -398
  73. package/chunks/{chunk-NUHSLBJZ.js → chunk-JNWZQ27S.js} +15 -9
  74. package/chunks/{chunk-KGWA7XYL.js → chunk-JRJ2LV6P.js} +6 -226
  75. package/chunks/{chunk-QSG4ZFG4.js → chunk-KTUQMDEP.js} +1 -1
  76. package/chunks/{chunk-RKUMFUFM.js → chunk-LTQ5C5AB.js} +4 -4
  77. package/chunks/{chunk-V4PCIS25.js → chunk-MAQQGNQ5.js} +44 -1
  78. package/chunks/{chunk-EISVEV45.js → chunk-NBMIC7DR.js} +2 -2
  79. package/chunks/{chunk-GEHSF7MS.js → chunk-NEEB7UEN.js} +2545 -1974
  80. package/chunks/{chunk-BKNPMEN6.js → chunk-NIJEXGV6.js} +93 -17
  81. package/chunks/{chunk-PR5XQ73G.js → chunk-NQVA6O7F.js} +2 -2
  82. package/chunks/{chunk-FUSMC3SZ.js → chunk-NT324EJ6.js} +13 -8
  83. package/chunks/{chunk-5N7M4XYN.js → chunk-O2SPEQFA.js} +5 -5
  84. package/chunks/{chunk-OEHCAWUA.js → chunk-OLMETXLX.js} +2 -2
  85. package/chunks/{chunk-JCJPZMJV.js → chunk-OOCI5VVU.js} +1 -1
  86. package/chunks/{chunk-XSPFQQRE.js → chunk-OONJNQ42.js} +3 -3
  87. package/chunks/{chunk-ANRANWVE.js → chunk-OP4MOGXF.js} +1 -1
  88. package/chunks/{chunk-SGPFJMRP.js → chunk-PBATSWUQ.js} +1 -1
  89. package/chunks/chunk-QKYTTBYW.js +624 -0
  90. package/chunks/{chunk-W4UN42YP.js → chunk-QOSKUG5P.js} +77 -20
  91. package/chunks/{chunk-76BFY7AF.js → chunk-QTERJVPZ.js} +1 -6
  92. package/chunks/{chunk-WIYV7CSF.js → chunk-RB7NXUP5.js} +3 -3
  93. package/chunks/{chunk-HCCR43AY.js → chunk-RFIAR4YL.js} +1 -1
  94. package/chunks/{chunk-GMUPIMHF.js → chunk-RS5JPH6Y.js} +3 -3
  95. package/chunks/chunk-RS7MT2QG.js +305 -0
  96. package/chunks/{chunk-GXFYV7MP.js → chunk-SG2PEESS.js} +1106 -592
  97. package/chunks/{chunk-PUKUUASO.js → chunk-SLLG5XXE.js} +1 -1
  98. package/chunks/{chunk-GLH2NTPB.js → chunk-SQMTULHJ.js} +1 -1
  99. package/chunks/{chunk-NPMVLWYL.js → chunk-STFP7PJR.js} +6 -6
  100. package/chunks/chunk-SV5PQVQE.js +71 -0
  101. package/chunks/{chunk-HZ4M2UQD.js → chunk-TFNZCC4B.js} +1 -1
  102. package/chunks/{chunk-5QSVANRT.js → chunk-THNJYTA6.js} +2 -2
  103. package/chunks/{chunk-MRE77ST5.js → chunk-TN2BYMNH.js} +69 -2216
  104. package/chunks/{chunk-64GC5EMF.js → chunk-TQBA6DVX.js} +1 -1
  105. package/chunks/{chunk-VLHQMOZK.js → chunk-U24E4R5U.js} +3 -3
  106. package/chunks/{chunk-4CA4WUMS.js → chunk-UEY4AYUL.js} +2 -2
  107. package/chunks/{chunk-42VIHAYT.js → chunk-UGRL5B5F.js} +1 -1
  108. package/chunks/chunk-V7RNNPGC.js +44 -0
  109. package/chunks/{chunk-R3EDIMYZ.js → chunk-VGFFYNBD.js} +1 -1
  110. package/chunks/chunk-VIOFKPPN.js +125 -0
  111. package/chunks/{chunk-BEZPRKD3.js → chunk-VLDBVLC4.js} +156 -2
  112. package/chunks/{chunk-HD6EGS5K.js → chunk-VWLLDHAY.js} +6 -6
  113. package/chunks/chunk-WCDH2CRI.js +1187 -0
  114. package/chunks/{chunk-7SX6WZNO.js → chunk-XVVH63JG.js} +3 -3
  115. package/chunks/{chunk-I7RRHHYG.js → chunk-Y2ENGUD6.js} +1 -1
  116. package/chunks/{chunk-NALRQ3SG.js → chunk-Y5534U4G.js} +332 -116
  117. package/chunks/{chunk-4SJJT466.js → chunk-YDZ6J2BY.js} +72 -159
  118. package/chunks/{chunk-APOFULHK.js → chunk-YNBP3YSU.js} +7 -6
  119. package/chunks/{chunk-EFAXBOQO.js → chunk-YWEW33JY.js} +7 -7
  120. package/chunks/{chunk-335ECZTA.js → chunk-ZEOZL37W.js} +1 -1
  121. package/chunks/{chunk-DUR7BZYK.js → chunk-ZGJ4LDD2.js} +53 -28
  122. package/chunks/{computer-use-4PUGCUQK.js → computer-use-ET5476VX.js} +22 -22
  123. package/chunks/{config-utils-6PJUXHLI.js → config-utils-AHQ6YZ66.js} +3 -3
  124. package/chunks/{contextCommand-C57KTWFV.js → contextCommand-QIULFDBF.js} +25 -26
  125. package/chunks/{create-sub-session-5Q42XR6I.js → create-sub-session-BVL2ZHTM.js} +22 -22
  126. package/chunks/{create-sub-session-DIJOV6HV.js → create-sub-session-P26FE5GG.js} +2 -2
  127. package/chunks/{cron-create-X462ERYA.js → cron-create-JWFHBDRQ.js} +4 -4
  128. package/chunks/{cron-delete-SL5UJUM3.js → cron-delete-GDX4E26G.js} +4 -4
  129. package/chunks/{cron-list-3MD6SVXI.js → cron-list-USMAIWPT.js} +4 -4
  130. package/chunks/{daemon-ZW6LHOXT.js → daemon-EE5T3KOW.js} +169 -84
  131. package/chunks/{daemon-status-provider-YPV3UXHT.js → daemon-status-provider-L5UW7TGV.js} +29 -29
  132. package/chunks/{dist-3DQNQJ6H.js → dist-2BHAYBKP.js} +1 -1
  133. package/chunks/{dist-J2H4KTLB.js → dist-2MIU4UUH.js} +1 -1
  134. package/chunks/{dist-IEQSDXS7.js → dist-53PZYC5B.js} +2 -2
  135. package/chunks/{dist-NUXRQHC5.js → dist-AU7NQQRP.js} +1 -1
  136. package/chunks/{dist-XLE6ODMB.js → dist-FUTEXY6A.js} +1 -1
  137. package/chunks/{dist-IGZMVS5R.js → dist-WGTQO7F2.js} +1 -1
  138. package/chunks/{earlyInputCapture-5VDWSYAM.js → earlyInputCapture-ZLAL5GTE.js} +23 -23
  139. package/chunks/{edit-GORZTX2U.js → edit-4ZOPT6OC.js} +23 -23
  140. package/chunks/{enter-worktree-LJB2AW4L.js → enter-worktree-DFP5CZYS.js} +22 -22
  141. package/chunks/{enterPlanMode-LIIPP37T.js → enterPlanMode-7VEJ7A2A.js} +22 -22
  142. package/chunks/{environment-HQ2UHJ35.js → environment-KHS35XJY.js} +24 -24
  143. package/chunks/{errors-6JD5VMVQ.js → errors-574WBU5R.js} +24 -24
  144. package/chunks/{exit-worktree-IEP2WHOV.js → exit-worktree-5Q7V6D4C.js} +22 -22
  145. package/chunks/{exitPlanMode-U5Z6XBLO.js → exitPlanMode-SX2F6PDJ.js} +22 -22
  146. package/chunks/{fast-path-HFKNMP23.js → fast-path-G7BLOZVF.js} +2 -2
  147. package/chunks/{gemini-C2SCJH3N.js → gemini-M4JWSTGU.js} +70 -68
  148. package/chunks/{geminiContentGenerator-ADZTXEKV.js → geminiContentGenerator-MKXLUFUH.js} +4 -4
  149. package/chunks/{glob-GOAPGD6G.js → glob-FPKZY5W6.js} +22 -22
  150. package/chunks/{grep-HZLSTX7D.js → grep-RS22OMZG.js} +22 -22
  151. package/chunks/{handleAutoUpdate-UF74WGFE.js → handleAutoUpdate-RFNQ36JC.js} +27 -28
  152. package/chunks/{i18n-FMXIYUOC.js → i18n-MAEWSKYF.js} +23 -23
  153. package/chunks/{initializer-ERDBM3DU.js → initializer-T2BFZJBP.js} +28 -28
  154. package/chunks/{installationInfo-LROMXYLX.js → installationInfo-3UETF773.js} +25 -23
  155. package/chunks/{keychain-token-storage-K23CFKGN.js → keychain-token-storage-DWRJMNH3.js} +2 -2
  156. package/chunks/{list-6JPJROU5.js → list-FWZUKWD2.js} +30 -30
  157. package/chunks/{loadedSettingsAdapter-QCWYUBBF.js → loadedSettingsAdapter-3DUNHAPX.js} +27 -27
  158. package/chunks/{loop-wakeup-6H7OENTB.js → loop-wakeup-5GLTUBHA.js} +5 -5
  159. package/chunks/{ls-APTSOOS5.js → ls-FHBY3Y7I.js} +4 -4
  160. package/chunks/{lsp-HPACPJAN.js → lsp-B6VMEW6Y.js} +2 -2
  161. package/chunks/{mcp-3P3KWYWO.js → mcp-POXS7QWD.js} +27 -27
  162. package/chunks/{monitor-LMYKCF6R.js → monitor-2ZZC2NKH.js} +22 -22
  163. package/chunks/nonInteractiveCli-WSJVCB2W.js +126 -0
  164. package/chunks/{notebook-edit-IBEOVZ6A.js → notebook-edit-BMQLME3Q.js} +23 -23
  165. package/chunks/{openaiContentGenerator-42PZKET5.js → openaiContentGenerator-GOREG72R.js} +11 -11
  166. package/chunks/{pidfile-VTBDIGOH.js → pidfile-MVZDE5TC.js} +23 -23
  167. package/chunks/{processUtils-L7ZKOGDG.js → processUtils-RH5KNLDH.js} +2 -2
  168. package/chunks/{qwenContentGenerator-VR2CNFGI.js → qwenContentGenerator-R55BCLRI.js} +24 -24
  169. package/chunks/{qwenOAuth2-6LS2T3Q6.js → qwenOAuth2-QZBI2SOZ.js} +11 -11
  170. package/chunks/react-SG7JAQSZ.js +8 -0
  171. package/chunks/{read-file-VSKOE22I.js → read-file-CPS2CYYG.js} +8 -8
  172. package/chunks/{read-mcp-resource-C6NT52T6.js → read-mcp-resource-AKCL7I43.js} +2 -2
  173. package/chunks/{record-artifact-ENCU7QCL.js → record-artifact-PEUB7727.js} +2 -2
  174. package/chunks/resumeHistoryUtils-YD6DSYHU.js +78 -0
  175. package/chunks/{ripGrep-5V5FLW2A.js → ripGrep-UKGJ7RHZ.js} +22 -22
  176. package/chunks/{run-qwen-serve-LSOPP4R2.js → run-qwen-serve-GFKSKLF6.js} +1442 -148
  177. package/chunks/{runtime-LT7R4CS5.js → runtime-4KGNL3TP.js} +31 -31
  178. package/chunks/{scheduler-YOWQ7KZP.js → scheduler-GJ3CELWI.js} +22 -22
  179. package/chunks/{send-message-5GZ4FX2V.js → send-message-3RHE7HSM.js} +3 -3
  180. package/chunks/{serve-VWLBXKGK.js → serve-UU6Z4C7W.js} +27 -27
  181. package/chunks/{server-3RW3FYOH.js → server-RTJUMN24.js} +393 -256
  182. package/chunks/{session-ZONXFOBQ.js → session-EYD3CEB5.js} +79 -163
  183. package/chunks/{settings-JC3VC53L.js → settings-H5O22TGQ.js} +26 -26
  184. package/chunks/{shell-2NGEMAVM.js → shell-KVNHDHMT.js} +22 -22
  185. package/chunks/{skill-3U2T6H3E.js → skill-32525KCE.js} +10 -10
  186. package/chunks/{spawnChannel-QEAUPARQ.js → spawnChannel-G7DUQKHL.js} +24 -24
  187. package/chunks/{src-75ZPXO7B.js → src-DUFUUEHE.js} +52 -22
  188. package/chunks/{standalone-update-UUJWJWYY.js → standalone-update-UC6CWBLH.js} +24 -24
  189. package/chunks/{startInteractiveUI-V7XISPQ6.js → startInteractiveUI-A5YYAWLF.js} +5451 -2045
  190. package/chunks/{syntheticOutput-ULOVVLY4.js → syntheticOutput-FG5PQKIR.js} +3 -3
  191. package/chunks/{task-create-DUE2PMNI.js → task-create-HX32YXO7.js} +7 -7
  192. package/chunks/{task-list-WVPNX7BZ.js → task-list-QWSY4ZIU.js} +5 -5
  193. package/chunks/{task-stop-CPEQWOT6.js → task-stop-GWC6UWAL.js} +2 -2
  194. package/chunks/{task-update-HY2LNFFB.js → task-update-NCTAB73Q.js} +7 -7
  195. package/chunks/{team-create-R6AXDYPG.js → team-create-LS2Q32Y4.js} +22 -22
  196. package/chunks/{team-delete-JJV6IUOA.js → team-delete-KK37HTOG.js} +5 -5
  197. package/chunks/{team-plan-approval-O2ZPPT64.js → team-plan-approval-DWCZABX6.js} +22 -22
  198. package/chunks/{theme-manager-YIX2IC2D.js → theme-manager-E22CNBIL.js} +23 -23
  199. package/chunks/{todoWrite-JHHIDOIV.js → todoWrite-ERCAMLFS.js} +4 -4
  200. package/chunks/{tool-search-5IE2VO7X.js → tool-search-MHXUDFD2.js} +9 -9
  201. package/chunks/{total-session-admission-K6APQYEF.js → total-session-admission-KOPTGDJZ.js} +25 -25
  202. package/chunks/{trustedFolders-GPSSPVBF.js → trustedFolders-ANQXYAQT.js} +23 -23
  203. package/chunks/{update-relaunch-4BVAPX6Y.js → update-relaunch-HFGRB7PE.js} +9 -9
  204. package/chunks/{updateCheck-AHTHWLAM.js → updateCheck-EKIPND4B.js} +33 -26
  205. package/chunks/useAutoAcceptIndicator-EE22V2F5.js +80 -0
  206. package/chunks/{validateNonInterActiveAuth-UKAPCWDM.js → validateNonInterActiveAuth-RUICXVPH.js} +61 -63
  207. package/chunks/{version-EXGWKKQE.js → version-QLT755OV.js} +1 -1
  208. package/chunks/{web-fetch-ZDNE6FF2.js → web-fetch-DINW4Z65.js} +10 -10
  209. package/chunks/{workflow-G7U6OQWS.js → workflow-GPMXRWKK.js} +23 -23
  210. package/chunks/{workspace-providers-status-W6CEA6YM.js → workspace-providers-status-XCQKBVSX.js} +30 -30
  211. package/chunks/{workspace-registration-store-OGBMWCLC.js → workspace-registration-store-4I4KL7TN.js} +1 -1
  212. package/chunks/{workspace-registry-ZUWQM44P.js → workspace-registry-N4J57SFQ.js} +25 -25
  213. package/chunks/{workspace-service-UXX5P7GU.js → workspace-service-JJNJWVH3.js} +32 -32
  214. package/chunks/{workspace-skills-status-635B5R7N.js → workspace-skills-status-CEHLAQ2Y.js} +28 -28
  215. package/chunks/{write-file-DR3HN7IH.js → write-file-XRGEJRCC.js} +23 -23
  216. package/cli.js +11 -11
  217. package/package.json +3 -3
  218. package/web-shell/assets/{arc-_dVIKMdB.js → arc-DwJhljn9.js} +1 -1
  219. package/web-shell/assets/{architectureDiagram-3BPJPVTR-MuN3nKpL.js → architectureDiagram-3BPJPVTR-qdxSRav-.js} +1 -1
  220. package/web-shell/assets/{blockDiagram-GPEHLZMM-BtmvJjzx.js → blockDiagram-GPEHLZMM-2-dKM5aM.js} +1 -1
  221. package/web-shell/assets/{c4Diagram-AAUBKEIU-Dvi58_BU.js → c4Diagram-AAUBKEIU-Dt_Nu2HD.js} +1 -1
  222. package/web-shell/assets/channel-C6uyh95L.js +1 -0
  223. package/web-shell/assets/{chunk-2J33WTMH-YqxOVhS1.js → chunk-2J33WTMH-CBCeeNfD.js} +1 -1
  224. package/web-shell/assets/{chunk-4BX2VUAB-DoBgbC9z.js → chunk-4BX2VUAB-DPAzjqNs.js} +1 -1
  225. package/web-shell/assets/{chunk-55IACEB6-3NEQrBAr.js → chunk-55IACEB6-yrqyxvIK.js} +1 -1
  226. package/web-shell/assets/{chunk-727SXJPM-DrCZQxp0.js → chunk-727SXJPM-DguD_BBT.js} +1 -1
  227. package/web-shell/assets/{chunk-AQP2D5EJ-m_g3zjgv.js → chunk-AQP2D5EJ-KRUOG9v0.js} +1 -1
  228. package/web-shell/assets/{chunk-FMBD7UC4-D1_crABJ.js → chunk-FMBD7UC4-C0lilT2U.js} +1 -1
  229. package/web-shell/assets/{chunk-ND2GUHAM-BdhgVtBx.js → chunk-ND2GUHAM-DG9epIWK.js} +1 -1
  230. package/web-shell/assets/{chunk-QZHKN3VN-BlmThhm-.js → chunk-QZHKN3VN-PdJDkYHw.js} +1 -1
  231. package/web-shell/assets/classDiagram-4FO5ZUOK-Cv8Ulf-B.js +1 -0
  232. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-Cv8Ulf-B.js +1 -0
  233. package/web-shell/assets/{cose-bilkent-S5V4N54A-Cbjm_00Z.js → cose-bilkent-S5V4N54A-BAOPPuJm.js} +1 -1
  234. package/web-shell/assets/{dagre-BM42HDAG-C39QNVgC.js → dagre-BM42HDAG-CDHJv82_.js} +1 -1
  235. package/web-shell/assets/{diagram-2AECGRRQ-DNXSAixC.js → diagram-2AECGRRQ-C_hkG5fN.js} +1 -1
  236. package/web-shell/assets/{diagram-5GNKFQAL-BCbGUPEA.js → diagram-5GNKFQAL-e9zo_eKt.js} +1 -1
  237. package/web-shell/assets/{diagram-KO2AKTUF-1eujKSDC.js → diagram-KO2AKTUF-BFN41SCb.js} +1 -1
  238. package/web-shell/assets/{diagram-LMA3HP47-DUMKXgql.js → diagram-LMA3HP47-DG72N0W0.js} +1 -1
  239. package/web-shell/assets/{diagram-OG6HWLK6-BFktU3_u.js → diagram-OG6HWLK6-Dkmp-tdv.js} +1 -1
  240. package/web-shell/assets/{erDiagram-TEJ5UH35-BvJC7DLk.js → erDiagram-TEJ5UH35-CyS0GnQV.js} +1 -1
  241. package/web-shell/assets/{flowDiagram-I6XJVG4X-Cgu3PlOt.js → flowDiagram-I6XJVG4X-Cg1SRmzV.js} +1 -1
  242. package/web-shell/assets/{ganttDiagram-6RSMTGT7-DLNXN5Xh.js → ganttDiagram-6RSMTGT7-CoNkSLs3.js} +1 -1
  243. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-BQFRDv6R.js → gitGraphDiagram-PVQCEYII-DEA6GWPa.js} +1 -1
  244. package/web-shell/assets/index-B49xd8_A.css +5 -0
  245. package/web-shell/assets/{index-CdC3pjP3.js → index-CMaZgs6B.js} +1 -1
  246. package/web-shell/assets/index-D-cDAZgO.js +1192 -0
  247. package/web-shell/assets/{infoDiagram-5YYISTIA-DT2mOSvp.js → infoDiagram-5YYISTIA-BZshyoGT.js} +1 -1
  248. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-9fy_K4bd.js → ishikawaDiagram-YF4QCWOH-CT2ssZqC.js} +1 -1
  249. package/web-shell/assets/{journeyDiagram-JHISSGLW-CoGSEuhE.js → journeyDiagram-JHISSGLW-BtMQ0rDG.js} +1 -1
  250. package/web-shell/assets/{kanban-definition-UN3LZRKU-BP9hHYIj.js → kanban-definition-UN3LZRKU-CoDbK5Db.js} +1 -1
  251. package/web-shell/assets/{linear-uIroDsmp.js → linear-CwhZ6u7u.js} +1 -1
  252. package/web-shell/assets/{mermaid.core-BUwoStsA.js → mermaid.core-C9nn0nrr.js} +5 -5
  253. package/web-shell/assets/{mindmap-definition-RKZ34NQL-DZB-FWim.js → mindmap-definition-RKZ34NQL-BXUbjTeL.js} +1 -1
  254. package/web-shell/assets/{pieDiagram-4H26LBE5-YPptloKl.js → pieDiagram-4H26LBE5-JddiYlWQ.js} +1 -1
  255. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-dgk3DSzm.js → quadrantDiagram-W4KKPZXB-DK5HKzXO.js} +1 -1
  256. package/web-shell/assets/{requirementDiagram-4Y6WPE33-BH2En2i9.js → requirementDiagram-4Y6WPE33-Y-uipa_6.js} +1 -1
  257. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-BB98feeI.js → sankeyDiagram-5OEKKPKP-BbWeqo8H.js} +1 -1
  258. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-CunAIGh8.js → sequenceDiagram-3UESZ5HK-tX2gOoo5.js} +1 -1
  259. package/web-shell/assets/{stateDiagram-AJRCARHV-DTJs_-I2.js → stateDiagram-AJRCARHV-CACN457G.js} +1 -1
  260. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DaUeO2zt.js +1 -0
  261. package/web-shell/assets/{timeline-definition-PNZ67QCA-Cd4AN7O0.js → timeline-definition-PNZ67QCA-DnHWKSOq.js} +1 -1
  262. package/web-shell/assets/{vennDiagram-CIIHVFJN-xIG-rUU9.js → vennDiagram-CIIHVFJN-BO8Yl2FG.js} +1 -1
  263. package/web-shell/assets/{wardley-L42UT6IY-D1UyjIcG.js → wardley-L42UT6IY-1NMqqrBi.js} +1 -1
  264. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-BVM0Mb99.js → wardleyDiagram-YWT4CUSO-C3eWgIvD.js} +1 -1
  265. package/web-shell/assets/{xychartDiagram-2RQKCTM6-BX31JDSz.js → xychartDiagram-2RQKCTM6-D0h8FgFX.js} +1 -1
  266. package/web-shell/index.html +2 -2
  267. package/chunks/chunk-EDFD7VOX.js +0 -368
  268. package/chunks/chunk-GFYFLDEG.js +0 -709
  269. package/chunks/chunk-LUJQUNKY.js +0 -3288
  270. package/chunks/nonInteractiveCli-YURFHZV5.js +0 -129
  271. package/web-shell/assets/channel-Bi5TehaT.js +0 -1
  272. package/web-shell/assets/classDiagram-4FO5ZUOK-BKhhRdd1.js +0 -1
  273. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BKhhRdd1.js +0 -1
  274. package/web-shell/assets/index-C_ouplMQ.js +0 -1187
  275. package/web-shell/assets/index-XGDFJE-X.css +0 -5
  276. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DrfFMYta.js +0 -1
@@ -1,3288 +0,0 @@
1
- // Force strict mode and setup for ESM
2
- "use strict";
3
- import {
4
- handleAtCommand,
5
- resolveAtCommandQuery,
6
- sanitizeDisplayText
7
- } from "./chunk-KGWA7XYL.js";
8
- import {
9
- isAtCommand,
10
- isBtwCommand,
11
- isSlashCommand,
12
- normalizePartList
13
- } from "./chunk-4SJJT466.js";
14
- import {
15
- findLastSafeSplitPoint,
16
- fitPendingSlice,
17
- getEnclosingFenceInfo,
18
- splitFencedMarkdown,
19
- useSessionStats
20
- } from "./chunk-GFYFLDEG.js";
21
- import {
22
- SHELL_COMMAND_NAME,
23
- isCollapsibleTool
24
- } from "./chunk-MRE77ST5.js";
25
- import {
26
- themeManager
27
- } from "./chunk-XAAEDML2.js";
28
- import {
29
- recordGoalStatusItem
30
- } from "./chunk-GXFYV7MP.js";
31
- import {
32
- require_react
33
- } from "./chunk-HTHUX2T5.js";
34
- import {
35
- formatMemoryUsage
36
- } from "./chunk-E5Z2AVNV.js";
37
- import {
38
- isInlineModelOverrideAllowed
39
- } from "./chunk-HVGJWOR6.js";
40
- import {
41
- t
42
- } from "./chunk-TKASNYDS.js";
43
- import {
44
- AutonomousLoopTickResolver,
45
- CoreToolScheduler,
46
- ShellExecutionService,
47
- activeGoalEquals,
48
- clampInlineMediaPart,
49
- clearActiveGoal,
50
- compactToolResultDisplayForHistory,
51
- convertToFunctionErrorResponse,
52
- createDuplicateProviderToolCallResponse,
53
- detectAutonomousSentinel,
54
- findRepeatedDuplicateProviderToolCall,
55
- generateToolUseSummary,
56
- getActiveGoal,
57
- getToolResponseDisplayText,
58
- isBinary,
59
- markDuplicateProviderToolCallResponseSent,
60
- parseAndFormatApiError,
61
- promptIdContext,
62
- refreshMemoryAfterManagedWrite,
63
- setActiveGoal
64
- } from "./chunk-GCY7QTCE.js";
65
- import {
66
- ApiCancelEvent,
67
- ConversationFinishedEvent,
68
- UserPromptEvent,
69
- UserRetryEvent,
70
- formatFullTurnVisionNotice,
71
- formatVisionBridgeNotice,
72
- getFullTurnVisionModelSelector,
73
- hasImageParts,
74
- logApiCancel,
75
- logConversationFinishedEvent,
76
- logUserPrompt,
77
- logUserRetry,
78
- runVisionBridge,
79
- shouldRunVisionBridge,
80
- splitImageParts
81
- } from "./chunk-CPU6I5YV.js";
82
- import {
83
- isAnyAutoMemPath
84
- } from "./chunk-LPHGXXZX.js";
85
- import {
86
- ToolNames,
87
- isShellProgressData
88
- } from "./chunk-ANRANWVE.js";
89
- import {
90
- getUnsupportedImageFormatWarning,
91
- isSupportedImageMimeType
92
- } from "./chunk-FEOZBUMT.js";
93
- import {
94
- FinishReason
95
- } from "./chunk-TYQMGACW.js";
96
- import {
97
- UnauthorizedError,
98
- createDebugLogger,
99
- getErrorMessage,
100
- isNodeError
101
- } from "./chunk-UE5TZ55T.js";
102
- import {
103
- init_esbuild_shims
104
- } from "./chunk-5O2XNYP6.js";
105
- import {
106
- __name,
107
- __toESM
108
- } from "./chunk-J2S4EL5Y.js";
109
-
110
- // packages/cli/src/dualOutput/DualOutputContext.tsx
111
- init_esbuild_shims();
112
- var import_react = __toESM(require_react(), 1);
113
- var DualOutputContext = (0, import_react.createContext)(null);
114
- function useDualOutput() {
115
- return (0, import_react.useContext)(DualOutputContext);
116
- }
117
- __name(useDualOutput, "useDualOutput");
118
-
119
- // packages/cli/src/ui/hooks/useGeminiStream.ts
120
- init_esbuild_shims();
121
- var import_react5 = __toESM(require_react(), 1);
122
-
123
- // packages/cli/src/ui/hooks/shellCommandProcessor.ts
124
- init_esbuild_shims();
125
- var import_react2 = __toESM(require_react(), 1);
126
- import crypto from "node:crypto";
127
- import path from "node:path";
128
- import os from "node:os";
129
- import fs from "node:fs";
130
- var OUTPUT_UPDATE_INTERVAL_MS = 1e3;
131
- var MAX_OUTPUT_LENGTH = 1e4;
132
- var debugLogger = createDebugLogger("SHELL_COMMAND_PROCESSOR");
133
- function copyString(value) {
134
- return value.split("").join("");
135
- }
136
- __name(copyString, "copyString");
137
- function addShellCommandToGeminiHistory(geminiClient, rawQuery, resultText) {
138
- const modelContent = resultText.length > MAX_OUTPUT_LENGTH ? copyString(resultText.substring(0, MAX_OUTPUT_LENGTH)) + "\n... (truncated)" : resultText;
139
- geminiClient.addHistory({
140
- role: "user",
141
- parts: [
142
- {
143
- text: `I ran the following shell command:
144
- \`\`\`sh
145
- ${rawQuery}
146
- \`\`\`
147
-
148
- This produced the following result:
149
- \`\`\`
150
- ${modelContent}
151
- \`\`\``
152
- }
153
- ]
154
- });
155
- }
156
- __name(addShellCommandToGeminiHistory, "addShellCommandToGeminiHistory");
157
- var useShellCommandProcessor = /* @__PURE__ */ __name((addItemToHistory, setPendingHistoryItem, onExec, onDebugMessage, config, geminiClient, setShellInputFocused, terminalWidth, terminalHeight) => {
158
- const [activeShellPtyId, setActiveShellPtyId] = (0, import_react2.useState)(null);
159
- const handleShellCommand = (0, import_react2.useCallback)(
160
- (rawQuery, abortSignal) => {
161
- if (typeof rawQuery !== "string" || rawQuery.trim() === "") {
162
- return false;
163
- }
164
- const userMessageTimestamp = Date.now();
165
- const callId = `shell-${userMessageTimestamp}`;
166
- addItemToHistory(
167
- { type: "user_shell", text: rawQuery },
168
- userMessageTimestamp
169
- );
170
- const isWindows = os.platform() === "win32";
171
- const targetDir = config.getTargetDir();
172
- let commandToExecute = rawQuery;
173
- let pwdFilePath;
174
- if (!isWindows) {
175
- let command = rawQuery.trim();
176
- const pwdFileName = `shell_pwd_${crypto.randomBytes(6).toString("hex")}.tmp`;
177
- pwdFilePath = path.join(os.tmpdir(), pwdFileName);
178
- if (!command.endsWith(";") && !command.endsWith("&")) {
179
- command += ";";
180
- }
181
- commandToExecute = `{ ${command} }; __code=$?; pwd > "${pwdFilePath}"; exit $__code`;
182
- }
183
- const executeCommand = /* @__PURE__ */ __name(async (resolve2) => {
184
- let lastUpdateTime = Date.now();
185
- let cumulativeStdout = "";
186
- let isBinaryStream = false;
187
- let binaryBytesReceived = 0;
188
- const initialToolDisplay = {
189
- callId,
190
- name: SHELL_COMMAND_NAME,
191
- description: rawQuery,
192
- status: "Executing" /* Executing */,
193
- resultDisplay: "",
194
- confirmationDetails: void 0
195
- };
196
- setPendingHistoryItem({
197
- type: "tool_group",
198
- tools: [initialToolDisplay],
199
- isUserInitiated: true
200
- });
201
- let executionPid;
202
- const abortHandler = /* @__PURE__ */ __name(() => {
203
- onDebugMessage(
204
- `Aborting shell command (PID: ${executionPid ?? "unknown"})`
205
- );
206
- }, "abortHandler");
207
- abortSignal.addEventListener("abort", abortHandler, { once: true });
208
- onDebugMessage(`Executing in ${targetDir}: ${commandToExecute}`);
209
- try {
210
- const activeTheme = themeManager.getActiveTheme();
211
- const shellExecutionConfig = {
212
- ...config.getShellExecutionConfig(),
213
- terminalWidth,
214
- terminalHeight,
215
- defaultFg: activeTheme.colors.Foreground,
216
- defaultBg: activeTheme.colors.Background
217
- };
218
- const { pid, result } = await ShellExecutionService.execute(
219
- commandToExecute,
220
- targetDir,
221
- (event) => {
222
- let shouldUpdate = false;
223
- switch (event.type) {
224
- case "data":
225
- if (isBinaryStream) break;
226
- if (config.getShouldUseNodePtyShell()) {
227
- cumulativeStdout = event.chunk;
228
- shouldUpdate = true;
229
- } else if (typeof event.chunk === "string" && typeof cumulativeStdout === "string") {
230
- cumulativeStdout += event.chunk;
231
- }
232
- break;
233
- case "binary_detected":
234
- isBinaryStream = true;
235
- shouldUpdate = true;
236
- break;
237
- case "binary_progress":
238
- isBinaryStream = true;
239
- binaryBytesReceived = event.bytesReceived;
240
- break;
241
- default: {
242
- throw new Error("An unhandled ShellOutputEvent was found.");
243
- }
244
- }
245
- let currentDisplayOutput;
246
- if (isBinaryStream) {
247
- if (binaryBytesReceived > 0) {
248
- currentDisplayOutput = `[Receiving binary output... ${formatMemoryUsage(
249
- binaryBytesReceived
250
- )} received]`;
251
- } else {
252
- currentDisplayOutput = "[Binary output detected. Halting stream...]";
253
- }
254
- } else {
255
- currentDisplayOutput = cumulativeStdout;
256
- }
257
- if (shouldUpdate || Date.now() - lastUpdateTime > OUTPUT_UPDATE_INTERVAL_MS) {
258
- setPendingHistoryItem((prevItem) => {
259
- if (prevItem?.type === "tool_group") {
260
- return {
261
- ...prevItem,
262
- tools: prevItem.tools.map(
263
- (tool) => tool.callId === callId ? {
264
- ...tool,
265
- resultDisplay: typeof currentDisplayOutput === "string" ? compactToolResultDisplayForHistory(
266
- currentDisplayOutput
267
- ) : compactToolResultDisplayForHistory({
268
- ansiOutput: currentDisplayOutput
269
- })
270
- } : tool
271
- )
272
- };
273
- }
274
- return prevItem;
275
- });
276
- lastUpdateTime = Date.now();
277
- }
278
- },
279
- abortSignal,
280
- config.getShouldUseNodePtyShell(),
281
- shellExecutionConfig
282
- );
283
- debugLogger.debug(terminalHeight, terminalWidth);
284
- executionPid = pid;
285
- if (pid) {
286
- setActiveShellPtyId(pid);
287
- setPendingHistoryItem((prevItem) => {
288
- if (prevItem?.type === "tool_group") {
289
- return {
290
- ...prevItem,
291
- tools: prevItem.tools.map(
292
- (tool) => tool.callId === callId ? { ...tool, ptyId: pid } : tool
293
- )
294
- };
295
- }
296
- return prevItem;
297
- });
298
- }
299
- result.then((result2) => {
300
- setPendingHistoryItem(null);
301
- let mainContent;
302
- if (isBinary(result2.rawOutput)) {
303
- mainContent = "[Command produced binary output, which is not shown.]";
304
- } else {
305
- mainContent = result2.output.trim() || "(Command produced no output)";
306
- }
307
- let finalOutput = mainContent;
308
- let finalStatus = "Success" /* Success */;
309
- if (result2.error) {
310
- finalStatus = "Error" /* Error */;
311
- finalOutput = `${result2.error.message}
312
- ${finalOutput}`;
313
- } else if (result2.aborted) {
314
- finalStatus = "Canceled" /* Canceled */;
315
- finalOutput = `Command was cancelled.
316
- ${finalOutput}`;
317
- } else if (result2.signal) {
318
- finalStatus = "Error" /* Error */;
319
- finalOutput = `Command terminated by signal: ${result2.signal}.
320
- ${finalOutput}`;
321
- } else if (result2.exitCode !== 0) {
322
- finalStatus = "Error" /* Error */;
323
- finalOutput = `Command exited with code ${result2.exitCode}.
324
- ${finalOutput}`;
325
- }
326
- if (pwdFilePath && fs.existsSync(pwdFilePath)) {
327
- const finalPwd = fs.readFileSync(pwdFilePath, "utf8").trim();
328
- if (finalPwd && finalPwd !== targetDir) {
329
- const warning = `WARNING: shell mode is stateless; the directory change to '${finalPwd}' will not persist.`;
330
- finalOutput = `${warning}
331
-
332
- ${finalOutput}`;
333
- }
334
- }
335
- const finalToolDisplay = {
336
- ...initialToolDisplay,
337
- status: finalStatus,
338
- resultDisplay: compactToolResultDisplayForHistory(finalOutput)
339
- };
340
- addItemToHistory(
341
- {
342
- type: "tool_group",
343
- tools: [finalToolDisplay],
344
- isUserInitiated: true
345
- },
346
- userMessageTimestamp
347
- );
348
- addShellCommandToGeminiHistory(
349
- geminiClient,
350
- rawQuery,
351
- finalOutput
352
- );
353
- }).catch((err) => {
354
- setPendingHistoryItem(null);
355
- const errorMessage = err instanceof Error ? err.message : String(err);
356
- addItemToHistory(
357
- {
358
- type: "error",
359
- text: `An unexpected error occurred: ${errorMessage}`
360
- },
361
- userMessageTimestamp
362
- );
363
- }).finally(() => {
364
- abortSignal.removeEventListener("abort", abortHandler);
365
- if (pwdFilePath && fs.existsSync(pwdFilePath)) {
366
- fs.unlinkSync(pwdFilePath);
367
- }
368
- setActiveShellPtyId(null);
369
- setShellInputFocused(false);
370
- resolve2();
371
- });
372
- } catch (err) {
373
- setPendingHistoryItem(null);
374
- const errorMessage = err instanceof Error ? err.message : String(err);
375
- addItemToHistory(
376
- {
377
- type: "error",
378
- text: `An unexpected error occurred: ${errorMessage}`
379
- },
380
- userMessageTimestamp
381
- );
382
- if (pwdFilePath && fs.existsSync(pwdFilePath)) {
383
- fs.unlinkSync(pwdFilePath);
384
- }
385
- setActiveShellPtyId(null);
386
- setShellInputFocused(false);
387
- resolve2();
388
- }
389
- }, "executeCommand");
390
- const execPromise = new Promise((resolve2) => {
391
- executeCommand(resolve2);
392
- });
393
- onExec(execPromise);
394
- return true;
395
- },
396
- [
397
- config,
398
- onDebugMessage,
399
- addItemToHistory,
400
- setPendingHistoryItem,
401
- onExec,
402
- geminiClient,
403
- setShellInputFocused,
404
- terminalHeight,
405
- terminalWidth
406
- ]
407
- );
408
- return { handleShellCommand, activeShellPtyId };
409
- }, "useShellCommandProcessor");
410
-
411
- // packages/cli/src/ui/hooks/useStateAndRef.ts
412
- init_esbuild_shims();
413
- var import_react3 = __toESM(require_react(), 1);
414
- var useStateAndRef = /* @__PURE__ */ __name((initialValue) => {
415
- const [state, setState] = import_react3.default.useState(initialValue);
416
- const ref = import_react3.default.useRef(initialValue);
417
- const setStateInternal = import_react3.default.useCallback(
418
- (newStateOrCallback) => {
419
- let newValue;
420
- if (typeof newStateOrCallback === "function") {
421
- newValue = newStateOrCallback(ref.current);
422
- } else {
423
- newValue = newStateOrCallback;
424
- }
425
- setState(newValue);
426
- ref.current = newValue;
427
- },
428
- []
429
- );
430
- return [state, ref, setStateInternal];
431
- }, "useStateAndRef");
432
-
433
- // packages/cli/src/ui/hooks/useReactToolScheduler.ts
434
- init_esbuild_shims();
435
- var import_react4 = __toESM(require_react(), 1);
436
- import * as path2 from "node:path";
437
- var debugLogger2 = createDebugLogger("REACT_TOOL_SCHEDULER");
438
- function useReactToolScheduler(onComplete, config, getPreferredEditor, onEditorClose) {
439
- const [toolCallsForDisplay, setToolCallsForDisplay] = (0, import_react4.useState)([]);
440
- const outputUpdateHandler = (0, import_react4.useCallback)(
441
- (toolCallId, outputChunk) => {
442
- if (isShellProgressData(outputChunk)) {
443
- return;
444
- }
445
- const compactOutput = compactToolResultDisplayForHistory(outputChunk);
446
- setToolCallsForDisplay(
447
- (prevCalls) => prevCalls.map((tc) => {
448
- if (tc.request.callId === toolCallId && tc.status === "executing") {
449
- const executingTc = tc;
450
- return { ...executingTc, liveOutput: compactOutput };
451
- }
452
- return tc;
453
- })
454
- );
455
- },
456
- []
457
- );
458
- const allToolCallsCompleteHandler = (0, import_react4.useCallback)(
459
- async (completedToolCalls) => {
460
- await onComplete(completedToolCalls);
461
- },
462
- [onComplete]
463
- );
464
- const toolCallsUpdateHandler = (0, import_react4.useCallback)(
465
- (updatedCoreToolCalls) => {
466
- setToolCallsForDisplay(
467
- (prevTrackedCalls) => updatedCoreToolCalls.map((coreTc) => {
468
- const existingTrackedCall = prevTrackedCalls.find(
469
- (ptc) => ptc.request.callId === coreTc.request.callId
470
- );
471
- const responseSubmittedToGemini = existingTrackedCall?.responseSubmittedToGemini ?? false;
472
- if (coreTc.status === "executing") {
473
- return {
474
- ...coreTc,
475
- responseSubmittedToGemini,
476
- liveOutput: existingTrackedCall?.liveOutput
477
- };
478
- }
479
- return {
480
- ...coreTc,
481
- responseSubmittedToGemini,
482
- liveOutput: void 0,
483
- pid: void 0,
484
- promoteAbortController: void 0
485
- };
486
- })
487
- );
488
- },
489
- [setToolCallsForDisplay]
490
- );
491
- const scheduler = (0, import_react4.useMemo)(
492
- () => new CoreToolScheduler({
493
- config,
494
- chatRecordingService: config.getChatRecordingService(),
495
- outputUpdateHandler,
496
- onAllToolCallsComplete: allToolCallsCompleteHandler,
497
- onToolCallsUpdate: toolCallsUpdateHandler,
498
- getPreferredEditor,
499
- onEditorClose
500
- }),
501
- [
502
- config,
503
- outputUpdateHandler,
504
- allToolCallsCompleteHandler,
505
- toolCallsUpdateHandler,
506
- getPreferredEditor,
507
- onEditorClose
508
- ]
509
- );
510
- const schedule = (0, import_react4.useCallback)(
511
- (request, signal, modelOverride) => {
512
- if (!modelOverride?.endsWith("\0")) {
513
- void scheduler.schedule(request, signal);
514
- return;
515
- }
516
- void (async () => {
517
- try {
518
- const runtimeView = await config.getBaseLlmClient().resolveForModel(modelOverride.slice(0, -1), {
519
- failClosed: true
520
- });
521
- await scheduler.schedule(request, signal, runtimeView);
522
- } catch (error) {
523
- debugLogger2.error(
524
- `Full-turn tool scheduling failed: ${error instanceof Error ? error.message : String(error)}`
525
- );
526
- const message = "Full-turn tool scheduling failed. The tool was not executed.";
527
- const requests = Array.isArray(request) ? request : [request];
528
- const completedCalls = requests.map(
529
- (toolRequest) => {
530
- const toolError = new Error(message);
531
- const responseParts = convertToFunctionErrorResponse(
532
- toolRequest.name,
533
- toolRequest.callId,
534
- message,
535
- message
536
- );
537
- config.getChatRecordingService()?.recordToolResult(responseParts, {
538
- callId: toolRequest.callId,
539
- status: "error",
540
- resultDisplay: message,
541
- error: toolError,
542
- errorType: "unhandled_exception" /* UNHANDLED_EXCEPTION */
543
- });
544
- return {
545
- status: "error",
546
- request: toolRequest,
547
- response: {
548
- callId: toolRequest.callId,
549
- responseParts,
550
- resultDisplay: message,
551
- error: toolError,
552
- errorType: "unhandled_exception" /* UNHANDLED_EXCEPTION */,
553
- contentLength: message.length
554
- }
555
- };
556
- }
557
- );
558
- setToolCallsForDisplay((prev) => [...prev, ...completedCalls]);
559
- await allToolCallsCompleteHandler(completedCalls);
560
- return;
561
- }
562
- })();
563
- },
564
- [allToolCallsCompleteHandler, config, scheduler]
565
- );
566
- const markToolsAsSubmitted = (0, import_react4.useCallback)(
567
- (callIdsToMark) => {
568
- setToolCallsForDisplay(
569
- (prevCalls) => prevCalls.map(
570
- (tc) => callIdsToMark.includes(tc.request.callId) ? { ...tc, responseSubmittedToGemini: true } : tc
571
- )
572
- );
573
- },
574
- []
575
- );
576
- return [toolCallsForDisplay, schedule, markToolsAsSubmitted];
577
- }
578
- __name(useReactToolScheduler, "useReactToolScheduler");
579
- function mapCoreStatusToDisplayStatus(coreStatus) {
580
- switch (coreStatus) {
581
- case "validating":
582
- return "Executing" /* Executing */;
583
- case "awaiting_approval":
584
- return "Confirming" /* Confirming */;
585
- case "executing":
586
- return "Executing" /* Executing */;
587
- case "success":
588
- return "Success" /* Success */;
589
- case "cancelled":
590
- return "Canceled" /* Canceled */;
591
- case "error":
592
- return "Error" /* Error */;
593
- case "scheduled":
594
- return "Pending" /* Pending */;
595
- default: {
596
- const exhaustiveCheck = coreStatus;
597
- debugLogger2.warn(`Unknown core status encountered: ${exhaustiveCheck}`);
598
- return "Error" /* Error */;
599
- }
600
- }
601
- }
602
- __name(mapCoreStatusToDisplayStatus, "mapCoreStatusToDisplayStatus");
603
- function detectMemoryOp(toolName, args, projectRoot) {
604
- const WRITE_TOOLS = /* @__PURE__ */ new Set(["write_file", "edit"]);
605
- const READ_TOOLS = /* @__PURE__ */ new Set(["read_file"]);
606
- const filePath = args?.["file_path"];
607
- if (!filePath) return void 0;
608
- const resolved = path2.resolve(filePath);
609
- if (!isAnyAutoMemPath(resolved, projectRoot)) return void 0;
610
- if (WRITE_TOOLS.has(toolName)) return "write";
611
- if (READ_TOOLS.has(toolName)) return "read";
612
- return void 0;
613
- }
614
- __name(detectMemoryOp, "detectMemoryOp");
615
- function mapToDisplay(toolOrTools, projectRoot) {
616
- const toolCalls = Array.isArray(toolOrTools) ? toolOrTools : [toolOrTools];
617
- const toolDisplays = toolCalls.map(
618
- (trackedCall) => {
619
- let displayName;
620
- let description;
621
- let renderOutputAsMarkdown = false;
622
- if (trackedCall.status === "error") {
623
- displayName = trackedCall.tool === void 0 ? trackedCall.request.name : trackedCall.tool.displayName;
624
- description = JSON.stringify(trackedCall.request.args);
625
- } else {
626
- displayName = trackedCall.tool.displayName;
627
- description = trackedCall.invocation.getDescription();
628
- renderOutputAsMarkdown = trackedCall.tool.isOutputMarkdown;
629
- }
630
- const baseDisplayProperties = {
631
- callId: trackedCall.request.callId,
632
- name: displayName,
633
- description,
634
- renderOutputAsMarkdown,
635
- isMemoryOp: projectRoot && trackedCall.status !== "error" ? detectMemoryOp(
636
- trackedCall.request.name,
637
- trackedCall.request.args,
638
- projectRoot
639
- ) : void 0
640
- };
641
- switch (trackedCall.status) {
642
- case "success":
643
- return {
644
- ...baseDisplayProperties,
645
- status: mapCoreStatusToDisplayStatus(trackedCall.status),
646
- resultDisplay: compactToolResultDisplayForHistory(
647
- trackedCall.response.resultDisplay
648
- ),
649
- // Full detail for the Ctrl+O transcript (§4.9): derived from the
650
- // already-persisted functionResponse parts; NOT char-capped (the
651
- // bound is whatever core already applied). Consumed ONLY by the
652
- // transcript's fullDetail render for collapsible (read/search/list)
653
- // tools whose summary resultDisplay is just a count — so gate the
654
- // extraction on `isCollapsibleTool(displayName)` to avoid storing a
655
- // large (~25K char) string on every edit/write/command/agent call
656
- // that the renderer would never use. Mirrors ToolMessage's
657
- // `usingDetailedDisplay` gate, which also keys off the display name.
658
- detailedDisplay: isCollapsibleTool(displayName) ? getToolResponseDisplayText(trackedCall.response.responseParts) : void 0,
659
- confirmationDetails: void 0
660
- };
661
- case "error":
662
- return {
663
- ...baseDisplayProperties,
664
- status: mapCoreStatusToDisplayStatus(trackedCall.status),
665
- resultDisplay: compactToolResultDisplayForHistory(
666
- trackedCall.response.resultDisplay
667
- ),
668
- confirmationDetails: void 0
669
- };
670
- case "cancelled":
671
- return {
672
- ...baseDisplayProperties,
673
- status: mapCoreStatusToDisplayStatus(trackedCall.status),
674
- resultDisplay: compactToolResultDisplayForHistory(
675
- trackedCall.response.resultDisplay
676
- ),
677
- confirmationDetails: void 0
678
- };
679
- case "awaiting_approval":
680
- return {
681
- ...baseDisplayProperties,
682
- status: mapCoreStatusToDisplayStatus(trackedCall.status),
683
- resultDisplay: void 0,
684
- confirmationDetails: trackedCall.confirmationDetails
685
- };
686
- case "executing":
687
- return {
688
- ...baseDisplayProperties,
689
- status: mapCoreStatusToDisplayStatus(trackedCall.status),
690
- resultDisplay: trackedCall.liveOutput ?? void 0,
691
- confirmationDetails: void 0,
692
- ptyId: trackedCall.pid,
693
- executionStartTime: trackedCall.executionStartTime
694
- };
695
- case "validating":
696
- // Fallthrough
697
- case "scheduled":
698
- return {
699
- ...baseDisplayProperties,
700
- status: mapCoreStatusToDisplayStatus(trackedCall.status),
701
- resultDisplay: void 0,
702
- confirmationDetails: void 0
703
- };
704
- default: {
705
- const exhaustiveCheck = trackedCall;
706
- return {
707
- callId: exhaustiveCheck.request.callId,
708
- name: "Unknown Tool",
709
- description: "Encountered an unknown tool call state.",
710
- status: "Error" /* Error */,
711
- resultDisplay: "Unknown tool call state",
712
- confirmationDetails: void 0,
713
- renderOutputAsMarkdown: false
714
- };
715
- }
716
- }
717
- }
718
- );
719
- return {
720
- type: "tool_group",
721
- tools: toolDisplays,
722
- memoryWriteCount: toolDisplays.filter((t2) => t2.isMemoryOp === "write").length || void 0,
723
- memoryReadCount: toolDisplays.filter((t2) => t2.isMemoryOp === "read").length || void 0
724
- };
725
- }
726
- __name(mapToDisplay, "mapToDisplay");
727
-
728
- // packages/cli/src/ui/hooks/useGeminiStream.ts
729
- import { promises as fs2 } from "node:fs";
730
- import path3 from "node:path";
731
- import process from "node:process";
732
- var debugLogger3 = createDebugLogger("GEMINI_STREAM");
733
- function applyModelOverride(modelOverrideRef, inlineActiveRef, value, isInline) {
734
- modelOverrideRef.current = value;
735
- inlineActiveRef.current = isInline;
736
- debugLogger3.debug(
737
- `model override ${value === void 0 ? "cleared" : `set to ${value}`} (inline=${isInline})`
738
- );
739
- }
740
- __name(applyModelOverride, "applyModelOverride");
741
- function clearModelOverride(modelOverrideRef, inlineActiveRef) {
742
- applyModelOverride(modelOverrideRef, inlineActiveRef, void 0, false);
743
- }
744
- __name(clearModelOverride, "clearModelOverride");
745
- var MID_TURN_AT_COMMAND_RESOLVE_TIMEOUT_MS = 1e4;
746
- var MID_TURN_AT_COMMAND_RESOLVE_TIMEOUT_MESSAGE = "Mid-turn @ command resolution timed out";
747
- function extractLastAssistantText(history) {
748
- for (let i = history.length - 1; i >= 0; i--) {
749
- const item = history[i];
750
- if ((item.type === "gemini" || item.type === "gemini_content") && typeof item.text === "string" && item.text.trim().length > 0) {
751
- return item.text;
752
- }
753
- }
754
- return void 0;
755
- }
756
- __name(extractLastAssistantText, "extractLastAssistantText");
757
- function stripLeadingBlankLines(text) {
758
- return text.replace(/^(?:[ \t]*\r?\n)+/, "");
759
- }
760
- __name(stripLeadingBlankLines, "stripLeadingBlankLines");
761
- async function resolveWithAbort(signal, run) {
762
- let onAbort;
763
- const abortPromise = new Promise((_, reject) => {
764
- onAbort = /* @__PURE__ */ __name(() => {
765
- reject(
766
- signal.reason instanceof Error ? signal.reason : new Error("Mid-turn @ command resolution aborted")
767
- );
768
- }, "onAbort");
769
- if (signal.aborted) {
770
- onAbort();
771
- return;
772
- }
773
- signal.addEventListener("abort", onAbort, { once: true });
774
- });
775
- try {
776
- return await Promise.race([run(), abortPromise]);
777
- } finally {
778
- if (onAbort) {
779
- signal.removeEventListener("abort", onAbort);
780
- }
781
- }
782
- }
783
- __name(resolveWithAbort, "resolveWithAbort");
784
- function extractToolResultText(parts) {
785
- if (!parts) return "";
786
- const list = Array.isArray(parts) ? parts : [parts];
787
- const chunks = [];
788
- for (const part of list) {
789
- if ("functionResponse" in part && part.functionResponse) {
790
- const response = part.functionResponse.response;
791
- if (response !== void 0) chunks.push(response);
792
- } else if ("text" in part && typeof part.text === "string") {
793
- chunks.push(part.text);
794
- }
795
- }
796
- if (chunks.length === 0) return "";
797
- if (chunks.length === 1) return chunks[0];
798
- return chunks;
799
- }
800
- __name(extractToolResultText, "extractToolResultText");
801
- function classifyApiError(error) {
802
- const status = error.status;
803
- const message = error.message?.toLowerCase() ?? "";
804
- if (status === 429 || message.includes("rate limit")) {
805
- return "rate_limit";
806
- }
807
- if (status === 401 || message.includes("unauthorized")) {
808
- return "authentication_failed";
809
- }
810
- if (status === 402 || status === 403 || message.includes("billing") || message.includes("quota")) {
811
- return "billing_error";
812
- }
813
- if (status === 400 || message.includes("invalid")) {
814
- return "invalid_request";
815
- }
816
- if (status !== void 0 && status >= 500) {
817
- return "server_error";
818
- }
819
- if (message.includes("max_tokens") || message.includes("token limit")) {
820
- return "max_output_tokens";
821
- }
822
- return "unknown";
823
- }
824
- __name(classifyApiError, "classifyApiError");
825
- function checkImageFormatsSupport(parts) {
826
- const unsupportedMimeTypes = [];
827
- let hasImages = false;
828
- if (typeof parts === "string") {
829
- return {
830
- hasImages: false,
831
- hasUnsupportedFormats: false,
832
- unsupportedMimeTypes: []
833
- };
834
- }
835
- const partsArray = Array.isArray(parts) ? parts : [parts];
836
- for (const part of partsArray) {
837
- if (typeof part === "string") continue;
838
- let mimeType;
839
- if ("inlineData" in part && part.inlineData?.mimeType?.startsWith("image/")) {
840
- hasImages = true;
841
- mimeType = part.inlineData.mimeType;
842
- }
843
- if ("fileData" in part && part.fileData?.mimeType?.startsWith("image/")) {
844
- hasImages = true;
845
- mimeType = part.fileData.mimeType;
846
- }
847
- if (mimeType && !isSupportedImageMimeType(mimeType)) {
848
- unsupportedMimeTypes.push(mimeType);
849
- }
850
- }
851
- return {
852
- hasImages,
853
- hasUnsupportedFormats: unsupportedMimeTypes.length > 0,
854
- unsupportedMimeTypes
855
- };
856
- }
857
- __name(checkImageFormatsSupport, "checkImageFormatsSupport");
858
- var EDIT_TOOL_NAMES = /* @__PURE__ */ new Set([
859
- ToolNames.EDIT,
860
- "replace",
861
- // legacy alias, may still arrive from older providers
862
- ToolNames.WRITE_FILE,
863
- ToolNames.NOTEBOOK_EDIT
864
- ]);
865
- var STREAM_UPDATE_THROTTLE_MS = 60;
866
- var STREAM_PENDING_ITEM_MAX_CHARS = 16384;
867
- var STREAM_PENDING_COMMIT_RESERVE_ROWS = 5;
868
- var STREAM_PENDING_COMPOSER_RESERVE_ROWS = 12;
869
- var LOADING_THOUGHT_DESCRIPTION_MAX_CHARS = 4096;
870
- function showCitations(settings) {
871
- const enabled = settings?.merged?.ui?.showCitations;
872
- if (enabled !== void 0) {
873
- return enabled;
874
- }
875
- return true;
876
- }
877
- __name(showCitations, "showCitations");
878
- function clampLoadingThoughtDescription(description) {
879
- if (description.length <= LOADING_THOUGHT_DESCRIPTION_MAX_CHARS) {
880
- return description;
881
- }
882
- return description.slice(0, LOADING_THOUGHT_DESCRIPTION_MAX_CHARS);
883
- }
884
- __name(clampLoadingThoughtDescription, "clampLoadingThoughtDescription");
885
- function charIndexAfterLine(text, keptLines) {
886
- if (keptLines <= 0) return -1;
887
- let count = 0;
888
- for (let i = 0; i < text.length; i++) {
889
- if (text[i] === "\n") {
890
- count++;
891
- if (count === keptLines) return i + 1;
892
- }
893
- }
894
- return -1;
895
- }
896
- __name(charIndexAfterLine, "charIndexAfterLine");
897
- var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, config, isConfigInitialized, settings, onDebugMessage, handleSlashCommand, shellModeActive, getPreferredEditor, onAuthError, performMemoryRefresh, modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError, onEditorClose, onCancelSubmit, setShellInputFocused, terminalWidth, terminalHeight, midTurnDrainRef, logger, availableTerminalHeightRef, terminalWidthRef, midTurnRestoreRef) => {
898
- const [initError, setInitError] = (0, import_react5.useState)(null);
899
- const abortControllerRef = (0, import_react5.useRef)(null);
900
- const flushBufferedStreamEventsRef = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
901
- const turnCancelledRef = (0, import_react5.useRef)(false);
902
- const isSubmittingQueryRef = (0, import_react5.useRef)(false);
903
- const lastPromptRef = (0, import_react5.useRef)(null);
904
- const lastTurnUserItemRef = (0, import_react5.useRef)(null);
905
- const turnSawContentEventRef = (0, import_react5.useRef)(false);
906
- const lastPromptErroredRef = (0, import_react5.useRef)(false);
907
- const commitItem = (0, import_react5.useCallback)(
908
- (item, userMessageTimestamp) => {
909
- if (item.type === "gemini" && !item.timestamp) {
910
- item.timestamp = Date.now();
911
- }
912
- return addItem(item, userMessageTimestamp);
913
- },
914
- [addItem]
915
- );
916
- const dualOutput = useDualOutput();
917
- const [isResponding, setIsResponding] = (0, import_react5.useState)(false);
918
- const activeModelStreamsRef = (0, import_react5.useRef)(0);
919
- const [thought, setThought] = (0, import_react5.useState)(null);
920
- const historyRef = (0, import_react5.useRef)(history);
921
- (0, import_react5.useLayoutEffect)(() => {
922
- historyRef.current = history;
923
- }, [history]);
924
- const auxiliaryAbortRefsRef = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
925
- const [pendingHistoryItem, pendingHistoryItemRef, setPendingHistoryItem] = useStateAndRef(null);
926
- const [pendingThoughtItem, pendingThoughtItemRef, setPendingThoughtItem] = useStateAndRef(null);
927
- const thoughtStartTimeRef = (0, import_react5.useRef)(null);
928
- const [
929
- pendingRetryErrorItem,
930
- pendingRetryErrorItemRef,
931
- setPendingRetryErrorItem
932
- ] = useStateAndRef(null);
933
- const [
934
- pendingRetryCountdownItem,
935
- pendingRetryCountdownItemRef,
936
- setPendingRetryCountdownItem
937
- ] = useStateAndRef(null);
938
- const retryCountdownTimerRef = (0, import_react5.useRef)(
939
- null
940
- );
941
- const processedMemoryToolsRef = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
942
- const submitPromptOnCompleteRef = (0, import_react5.useRef)(null);
943
- const modelOverrideRef = (0, import_react5.useRef)(void 0);
944
- const inlineModelOverrideActiveRef = (0, import_react5.useRef)(false);
945
- const handledProviderToolCallIdsRef = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
946
- const duplicateProviderToolCallResponseIdsRef = (0, import_react5.useRef)(
947
- /* @__PURE__ */ new Set()
948
- );
949
- const pendingDuplicateToolResponsesRef = (0, import_react5.useRef)([]);
950
- const immediateDuplicateToolResponsesRef = (0, import_react5.useRef)(null);
951
- const streamingResponseLengthRef = (0, import_react5.useRef)(0);
952
- const [isReceivingContent, setIsReceivingContent] = (0, import_react5.useState)(false);
953
- const {
954
- startNewPrompt,
955
- getPromptCount,
956
- stats: sessionStates
957
- } = useSessionStats();
958
- const storage = config.storage;
959
- const [toolCalls, scheduleToolCalls, markToolsAsSubmitted] = useReactToolScheduler(
960
- async (completedToolCallsFromScheduler) => {
961
- if (completedToolCallsFromScheduler.length > 0) {
962
- const projectRoot = config.getProjectRoot();
963
- const toolGroupDisplay = mapToDisplay(
964
- completedToolCallsFromScheduler,
965
- projectRoot
966
- );
967
- addItem(toolGroupDisplay, Date.now());
968
- await handleCompletedTools(
969
- completedToolCallsFromScheduler
970
- );
971
- }
972
- },
973
- config,
974
- getPreferredEditor,
975
- onEditorClose
976
- );
977
- const pendingToolCallGroupDisplay = (0, import_react5.useMemo)(
978
- () => toolCalls.length ? mapToDisplay(toolCalls, config.getProjectRoot()) : void 0,
979
- [toolCalls, config]
980
- );
981
- const activeToolPtyId = (0, import_react5.useMemo)(() => {
982
- const executingShellTool = toolCalls?.find(
983
- (tc) => tc.status === "executing" && tc.request.name === "run_shell_command"
984
- );
985
- if (executingShellTool) {
986
- return executingShellTool.pid;
987
- }
988
- return void 0;
989
- }, [toolCalls]);
990
- const loopDetectedRef = (0, import_react5.useRef)(false);
991
- const [
992
- loopDetectionConfirmationRequest,
993
- setLoopDetectionConfirmationRequest
994
- ] = (0, import_react5.useState)(null);
995
- const stopRetryCountdownTimer = (0, import_react5.useCallback)(() => {
996
- if (retryCountdownTimerRef.current) {
997
- clearInterval(retryCountdownTimerRef.current);
998
- retryCountdownTimerRef.current = null;
999
- }
1000
- }, []);
1001
- const clearRetryCountdown = (0, import_react5.useCallback)(() => {
1002
- stopRetryCountdownTimer();
1003
- skipRetryDelayRef.current = null;
1004
- setPendingRetryErrorItem(null);
1005
- setPendingRetryCountdownItem(null);
1006
- }, [
1007
- setPendingRetryErrorItem,
1008
- setPendingRetryCountdownItem,
1009
- stopRetryCountdownTimer
1010
- ]);
1011
- const skipRetryDelayRef = (0, import_react5.useRef)(null);
1012
- const startRetryCountdown = (0, import_react5.useCallback)(
1013
- (retryInfo) => {
1014
- stopRetryCountdownTimer();
1015
- skipRetryDelayRef.current = retryInfo.skipDelay;
1016
- const startTime = Date.now();
1017
- const { message, attempt, maxRetries, delayMs } = retryInfo;
1018
- const retryReasonText = message ?? t("Rate limit exceeded. Please wait and try again.");
1019
- const updateCountdown = /* @__PURE__ */ __name(() => {
1020
- const elapsedMs = Date.now() - startTime;
1021
- const remainingMs = Math.max(0, delayMs - elapsedMs);
1022
- const remainingSec = Math.ceil(remainingMs / 1e3);
1023
- const hintText = `Retrying in ${remainingSec}s\u2026 (attempt ${attempt}/${maxRetries})`;
1024
- setPendingRetryErrorItem({
1025
- type: "error" /* ERROR */,
1026
- text: retryReasonText,
1027
- hint: hintText
1028
- });
1029
- setPendingRetryCountdownItem({
1030
- type: "retry_countdown",
1031
- text: t(
1032
- "Retrying in {{seconds}} seconds\u2026 (attempt {{attempt}}/{{maxRetries}})",
1033
- {
1034
- seconds: String(remainingSec),
1035
- attempt: String(attempt),
1036
- maxRetries: String(maxRetries)
1037
- }
1038
- )
1039
- });
1040
- if (remainingMs <= 0) {
1041
- stopRetryCountdownTimer();
1042
- }
1043
- }, "updateCountdown");
1044
- updateCountdown();
1045
- retryCountdownTimerRef.current = setInterval(updateCountdown, 1e3);
1046
- },
1047
- [
1048
- setPendingRetryErrorItem,
1049
- setPendingRetryCountdownItem,
1050
- stopRetryCountdownTimer
1051
- ]
1052
- );
1053
- (0, import_react5.useEffect)(() => () => stopRetryCountdownTimer(), [stopRetryCountdownTimer]);
1054
- const onExec = (0, import_react5.useCallback)(async (done) => {
1055
- setIsResponding(true);
1056
- await done;
1057
- setIsResponding(false);
1058
- }, []);
1059
- const { handleShellCommand, activeShellPtyId } = useShellCommandProcessor(
1060
- addItem,
1061
- setPendingHistoryItem,
1062
- onExec,
1063
- onDebugMessage,
1064
- config,
1065
- geminiClient,
1066
- setShellInputFocused,
1067
- terminalWidth,
1068
- terminalHeight
1069
- );
1070
- const activePtyId = activeShellPtyId || activeToolPtyId;
1071
- (0, import_react5.useEffect)(() => {
1072
- if (!activePtyId) {
1073
- setShellInputFocused(false);
1074
- }
1075
- }, [activePtyId, setShellInputFocused]);
1076
- const streamingState = (0, import_react5.useMemo)(() => {
1077
- if (toolCalls.some((tc) => tc.status === "awaiting_approval")) {
1078
- return "waiting_for_confirmation" /* WaitingForConfirmation */;
1079
- }
1080
- if (toolCalls.some((tc) => {
1081
- if (tc.status !== "executing") return false;
1082
- const liveOutput = tc.liveOutput;
1083
- return typeof liveOutput === "object" && liveOutput !== null && "type" in liveOutput && liveOutput.type === "task_execution" && "pendingConfirmation" in liveOutput && liveOutput.pendingConfirmation != null;
1084
- })) {
1085
- return "waiting_for_confirmation" /* WaitingForConfirmation */;
1086
- }
1087
- if (isResponding || toolCalls.some(
1088
- (tc) => tc.status === "executing" || tc.status === "scheduled" || tc.status === "validating" || (tc.status === "success" || tc.status === "error" || tc.status === "cancelled") && !tc.responseSubmittedToGemini
1089
- )) {
1090
- return "responding" /* Responding */;
1091
- }
1092
- return "idle" /* Idle */;
1093
- }, [isResponding, toolCalls]);
1094
- (0, import_react5.useEffect)(() => {
1095
- if (config.getApprovalMode() === "yolo" /* YOLO */ && streamingState === "idle" /* Idle */) {
1096
- const lastUserMessageIndex = history.findLastIndex(
1097
- (item) => item.type === "user" /* USER */
1098
- );
1099
- const turnCount = lastUserMessageIndex === -1 ? 0 : history.length - lastUserMessageIndex;
1100
- if (turnCount > 0) {
1101
- logConversationFinishedEvent(
1102
- config,
1103
- new ConversationFinishedEvent(config.getApprovalMode(), turnCount)
1104
- );
1105
- }
1106
- }
1107
- }, [streamingState, config, history]);
1108
- const cancelOngoingRequest = (0, import_react5.useCallback)(() => {
1109
- if (streamingState !== "responding" /* Responding */) {
1110
- return;
1111
- }
1112
- if (turnCancelledRef.current) {
1113
- return;
1114
- }
1115
- for (const flushBufferedStreamEvents of flushBufferedStreamEventsRef.current) {
1116
- flushBufferedStreamEvents();
1117
- }
1118
- const pendingItemAtCancel = pendingHistoryItemRef.current;
1119
- turnCancelledRef.current = true;
1120
- isSubmittingQueryRef.current = false;
1121
- abortControllerRef.current?.abort();
1122
- const loopWakeupsCancelled = config.getCronScheduler()?.cancelAllWakeups() ?? 0;
1123
- for (const ac of auxiliaryAbortRefsRef.current) {
1124
- ac.abort();
1125
- }
1126
- auxiliaryAbortRefsRef.current.clear();
1127
- config.getArenaAgentClient()?.reportCancelled();
1128
- const prompt_id = config.getSessionId() + "########" + getPromptCount();
1129
- const cancellationEvent = new ApiCancelEvent(
1130
- modelOverrideRef.current ?? config.getModel(),
1131
- prompt_id,
1132
- config.getContentGeneratorConfig()?.authType,
1133
- loopWakeupsCancelled > 0 ? loopWakeupsCancelled : void 0
1134
- );
1135
- logApiCancel(config, cancellationEvent);
1136
- if (pendingHistoryItemRef.current) {
1137
- commitItem(pendingHistoryItemRef.current, Date.now());
1138
- }
1139
- addItem(
1140
- {
1141
- type: "info" /* INFO */,
1142
- text: "Request cancelled."
1143
- },
1144
- Date.now()
1145
- );
1146
- if (loopWakeupsCancelled > 0) {
1147
- addItem(
1148
- {
1149
- type: "info" /* INFO */,
1150
- text: `Stopped the self-paced loop: cancelled ${loopWakeupsCancelled} pending wakeup${loopWakeupsCancelled === 1 ? "" : "s"}.`
1151
- },
1152
- Date.now()
1153
- );
1154
- }
1155
- setPendingHistoryItem(null);
1156
- clearRetryCountdown();
1157
- try {
1158
- onCancelSubmit({
1159
- pendingItem: pendingItemAtCancel,
1160
- lastTurnUserItem: lastTurnUserItemRef.current,
1161
- turnProducedMeaningfulContent: turnSawContentEventRef.current
1162
- });
1163
- } finally {
1164
- setIsResponding(false);
1165
- setShellInputFocused(false);
1166
- }
1167
- }, [
1168
- streamingState,
1169
- addItem,
1170
- commitItem,
1171
- setPendingHistoryItem,
1172
- onCancelSubmit,
1173
- pendingHistoryItemRef,
1174
- setShellInputFocused,
1175
- clearRetryCountdown,
1176
- config,
1177
- getPromptCount
1178
- ]);
1179
- const applyVisionBridgeIfNeeded = (0, import_react5.useCallback)(
1180
- async (parts, timestamp, signal) => {
1181
- if (parts === null || !hasImageParts(parts)) {
1182
- return { parts, shouldProceed: true };
1183
- }
1184
- if (modelOverrideRef.current?.endsWith("\0")) {
1185
- return { parts, shouldProceed: true };
1186
- }
1187
- if (inlineModelOverrideActiveRef.current) {
1188
- return { parts, shouldProceed: true };
1189
- }
1190
- if (!shouldRunVisionBridge(config)) {
1191
- return { parts, shouldProceed: true };
1192
- }
1193
- if (signal.aborted) {
1194
- return { parts: null, shouldProceed: false };
1195
- }
1196
- debugLogger3.debug("vision bridge: gate matched, running conversion");
1197
- const fullTurnModel = config.getDefaultVisionBridgeModel();
1198
- if (fullTurnModel?.agentCapable) {
1199
- const fullTurnParts = (Array.isArray(parts) ? parts : [parts]).map(
1200
- (part) => typeof part === "string" ? { text: part } : clampInlineMediaPart(part)
1201
- );
1202
- if (!hasImageParts(fullTurnParts)) {
1203
- return { parts: fullTurnParts, shouldProceed: true };
1204
- }
1205
- applyModelOverride(
1206
- modelOverrideRef,
1207
- inlineModelOverrideActiveRef,
1208
- getFullTurnVisionModelSelector(fullTurnModel),
1209
- false
1210
- );
1211
- addItem(
1212
- {
1213
- type: "vision_notice" /* VISION_NOTICE */,
1214
- text: formatFullTurnVisionNotice(fullTurnModel)
1215
- },
1216
- timestamp
1217
- );
1218
- return { parts: fullTurnParts, shouldProceed: true };
1219
- }
1220
- const bridgeResult = await runVisionBridge({ config, parts, signal });
1221
- debugLogger3.debug(
1222
- `vision bridge: status=${bridgeResult.status} applied=${bridgeResult.applied} model=${bridgeResult.modelId ?? "(none)"}`
1223
- );
1224
- if (bridgeResult.status !== "skipped" || bridgeResult.egressOccurred) {
1225
- addItem(
1226
- {
1227
- type: bridgeResult.status === "failed" ? "error" /* ERROR */ : "vision_notice" /* VISION_NOTICE */,
1228
- text: formatVisionBridgeNotice(bridgeResult)
1229
- },
1230
- timestamp
1231
- );
1232
- }
1233
- if (signal.aborted) {
1234
- return { parts: null, shouldProceed: false };
1235
- }
1236
- if (bridgeResult.applied && bridgeResult.parts != null) {
1237
- return { parts: bridgeResult.parts, shouldProceed: true };
1238
- }
1239
- const textOnly = splitImageParts(parts).nonImageParts;
1240
- return textOnly.length > 0 ? { parts: textOnly, shouldProceed: true } : { parts: null, shouldProceed: false };
1241
- },
1242
- [addItem, config]
1243
- );
1244
- const prepareQueryForGemini = (0, import_react5.useCallback)(
1245
- async (query, userMessageTimestamp, abortSignal, prompt_id, submitType) => {
1246
- if (turnCancelledRef.current) {
1247
- return { queryToSend: null, shouldProceed: false };
1248
- }
1249
- if (typeof query === "string" && query.trim().length === 0) {
1250
- return { queryToSend: null, shouldProceed: false };
1251
- }
1252
- lastTurnUserItemRef.current = null;
1253
- let localQueryToSendToGemini = null;
1254
- if (typeof query === "string") {
1255
- const trimmedQuery = query.trim();
1256
- if (submitType === "notification" /* Notification */) {
1257
- onDebugMessage(
1258
- `Received notification (${trimmedQuery.length} chars)`
1259
- );
1260
- return { queryToSend: trimmedQuery, shouldProceed: true };
1261
- }
1262
- if (submitType === "teammate" /* Teammate */) {
1263
- onDebugMessage(
1264
- `Received teammate message (${trimmedQuery.length} chars)`
1265
- );
1266
- return { queryToSend: trimmedQuery, shouldProceed: true };
1267
- }
1268
- onDebugMessage(`Received user query (${trimmedQuery.length} chars)`);
1269
- await logger?.logMessage("user" /* USER */, trimmedQuery);
1270
- const slashCommandResult = isSlashCommand(trimmedQuery) ? await handleSlashCommand(trimmedQuery) : false;
1271
- if (slashCommandResult) {
1272
- switch (slashCommandResult.type) {
1273
- case "schedule_tool": {
1274
- const { toolName, toolArgs } = slashCommandResult;
1275
- const toolCallRequest = {
1276
- callId: `${toolName}-${Date.now()}-${Math.random().toString(16).slice(2)}`,
1277
- name: toolName,
1278
- args: toolArgs,
1279
- isClientInitiated: true,
1280
- prompt_id
1281
- };
1282
- scheduleToolCalls([toolCallRequest], abortSignal);
1283
- return { queryToSend: null, shouldProceed: false };
1284
- }
1285
- case "submit_prompt": {
1286
- localQueryToSendToGemini = slashCommandResult.content;
1287
- submitPromptOnCompleteRef.current = slashCommandResult.onComplete ?? null;
1288
- if (slashCommandResult.modelOverride) {
1289
- if (isInlineModelOverrideAllowed(
1290
- config,
1291
- slashCommandResult.modelOverride
1292
- )) {
1293
- applyModelOverride(
1294
- modelOverrideRef,
1295
- inlineModelOverrideActiveRef,
1296
- slashCommandResult.modelOverride,
1297
- true
1298
- );
1299
- } else {
1300
- debugLogger3.warn(
1301
- `ignoring model override '${slashCommandResult.modelOverride}': not a model on the active provider`
1302
- );
1303
- }
1304
- }
1305
- const bridgeResult2 = await applyVisionBridgeIfNeeded(
1306
- localQueryToSendToGemini,
1307
- userMessageTimestamp,
1308
- abortSignal
1309
- );
1310
- if (!bridgeResult2.shouldProceed) {
1311
- return { queryToSend: null, shouldProceed: false };
1312
- }
1313
- localQueryToSendToGemini = bridgeResult2.parts;
1314
- return {
1315
- queryToSend: localQueryToSendToGemini,
1316
- shouldProceed: true
1317
- };
1318
- }
1319
- case "handled": {
1320
- return { queryToSend: null, shouldProceed: false };
1321
- }
1322
- default: {
1323
- const unreachable = slashCommandResult;
1324
- throw new Error(
1325
- `Unhandled slash command result type: ${unreachable}`
1326
- );
1327
- }
1328
- }
1329
- }
1330
- if (shellModeActive && handleShellCommand(trimmedQuery, abortSignal)) {
1331
- return { queryToSend: null, shouldProceed: false };
1332
- }
1333
- localQueryToSendToGemini = trimmedQuery;
1334
- if (submitType !== "cron" /* Cron */) {
1335
- const insertedId = addItem(
1336
- {
1337
- type: "user" /* USER */,
1338
- text: trimmedQuery,
1339
- promptId: prompt_id
1340
- },
1341
- userMessageTimestamp
1342
- );
1343
- lastTurnUserItemRef.current = {
1344
- id: insertedId,
1345
- text: trimmedQuery
1346
- };
1347
- await new Promise((r) => setImmediate(r));
1348
- }
1349
- if (isAtCommand(trimmedQuery)) {
1350
- const atCommandResult = await handleAtCommand({
1351
- query: trimmedQuery,
1352
- config,
1353
- onDebugMessage,
1354
- messageId: userMessageTimestamp,
1355
- signal: abortSignal,
1356
- addItem
1357
- });
1358
- if (!atCommandResult.shouldProceed) {
1359
- return { queryToSend: null, shouldProceed: false };
1360
- }
1361
- localQueryToSendToGemini = atCommandResult.processedQuery;
1362
- }
1363
- const bridgeResult = await applyVisionBridgeIfNeeded(
1364
- localQueryToSendToGemini,
1365
- userMessageTimestamp,
1366
- abortSignal
1367
- );
1368
- if (!bridgeResult.shouldProceed) {
1369
- return { queryToSend: null, shouldProceed: false };
1370
- }
1371
- localQueryToSendToGemini = bridgeResult.parts;
1372
- } else {
1373
- localQueryToSendToGemini = query;
1374
- }
1375
- if (localQueryToSendToGemini === null) {
1376
- onDebugMessage(
1377
- "Query processing resulted in null, not sending to Gemini."
1378
- );
1379
- return { queryToSend: null, shouldProceed: false };
1380
- }
1381
- return { queryToSend: localQueryToSendToGemini, shouldProceed: true };
1382
- },
1383
- [
1384
- config,
1385
- addItem,
1386
- onDebugMessage,
1387
- handleShellCommand,
1388
- handleSlashCommand,
1389
- logger,
1390
- shellModeActive,
1391
- scheduleToolCalls,
1392
- applyVisionBridgeIfNeeded
1393
- ]
1394
- );
1395
- const handleContentEvent = (0, import_react5.useCallback)(
1396
- (eventValue, currentGeminiMessageBuffer, userMessageTimestamp) => {
1397
- if (turnCancelledRef.current) {
1398
- return "";
1399
- }
1400
- streamingResponseLengthRef.current += eventValue.length;
1401
- setIsReceivingContent(true);
1402
- turnSawContentEventRef.current = true;
1403
- let newGeminiMessageBuffer = currentGeminiMessageBuffer + eventValue;
1404
- if (pendingHistoryItemRef.current?.type !== "gemini" && pendingHistoryItemRef.current?.type !== "gemini_content") {
1405
- if (newGeminiMessageBuffer.trim().length === 0) {
1406
- return newGeminiMessageBuffer;
1407
- }
1408
- if (pendingHistoryItemRef.current) {
1409
- commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
1410
- }
1411
- setPendingHistoryItem({
1412
- type: "gemini",
1413
- text: "",
1414
- timestamp: Date.now()
1415
- });
1416
- newGeminiMessageBuffer = stripLeadingBlankLines(newGeminiMessageBuffer);
1417
- }
1418
- let nextPendingType = pendingHistoryItemRef.current?.type;
1419
- while (newGeminiMessageBuffer.length > STREAM_PENDING_ITEM_MAX_CHARS) {
1420
- const splitPoint = findLastSafeSplitPoint(
1421
- newGeminiMessageBuffer,
1422
- STREAM_PENDING_ITEM_MAX_CHARS
1423
- );
1424
- const safeSplitPoint = splitPoint > 0 && splitPoint < newGeminiMessageBuffer.length ? splitPoint : STREAM_PENDING_ITEM_MAX_CHARS;
1425
- const { before: beforeText, after: afterText } = splitFencedMarkdown(
1426
- newGeminiMessageBuffer,
1427
- safeSplitPoint
1428
- );
1429
- commitItem(
1430
- {
1431
- type: nextPendingType,
1432
- text: beforeText
1433
- },
1434
- userMessageTimestamp
1435
- );
1436
- nextPendingType = "gemini_content";
1437
- newGeminiMessageBuffer = afterText;
1438
- }
1439
- const viewportRows = (availableTerminalHeightRef?.current ?? 0) > 0 ? availableTerminalHeightRef.current : Math.max(4, terminalHeight - STREAM_PENDING_COMPOSER_RESERVE_ROWS);
1440
- const commitWidth = (terminalWidthRef?.current ?? 0) > 0 ? terminalWidthRef.current : terminalWidth;
1441
- const commitRowBudget = Math.max(
1442
- 4,
1443
- viewportRows - STREAM_PENDING_COMMIT_RESERVE_ROWS
1444
- );
1445
- const tableClampRows = Math.max(2, viewportRows - 3);
1446
- while (true) {
1447
- const bufferLines = newGeminiMessageBuffer.split("\n");
1448
- const { keptLines, clipped } = fitPendingSlice(
1449
- bufferLines,
1450
- commitWidth,
1451
- commitRowBudget,
1452
- tableClampRows
1453
- );
1454
- if (!clipped) break;
1455
- let boundaryLine = -1;
1456
- for (let k = Math.min(keptLines, bufferLines.length - 1); k >= 0; k--) {
1457
- if (bufferLines[k].trim() === "") {
1458
- boundaryLine = k;
1459
- break;
1460
- }
1461
- }
1462
- let target;
1463
- if (boundaryLine < 0) {
1464
- const capIndex = charIndexAfterLine(
1465
- newGeminiMessageBuffer,
1466
- keptLines
1467
- );
1468
- const fenceInfo = capIndex > 0 ? getEnclosingFenceInfo(newGeminiMessageBuffer, capIndex) : null;
1469
- if (!fenceInfo || fenceInfo.lang?.toLowerCase() === "mermaid") {
1470
- break;
1471
- }
1472
- target = capIndex;
1473
- } else {
1474
- target = charIndexAfterLine(newGeminiMessageBuffer, boundaryLine + 1);
1475
- if (target <= 0) break;
1476
- }
1477
- const splitPoint = findLastSafeSplitPoint(
1478
- newGeminiMessageBuffer,
1479
- target
1480
- );
1481
- if (splitPoint <= 0 || splitPoint >= newGeminiMessageBuffer.length) {
1482
- break;
1483
- }
1484
- const { before: beforeText, after: afterText } = splitFencedMarkdown(
1485
- newGeminiMessageBuffer,
1486
- splitPoint
1487
- );
1488
- commitItem(
1489
- {
1490
- type: nextPendingType,
1491
- text: beforeText
1492
- },
1493
- userMessageTimestamp
1494
- );
1495
- nextPendingType = "gemini_content";
1496
- newGeminiMessageBuffer = afterText;
1497
- }
1498
- setPendingHistoryItem((item) => {
1499
- const base = {
1500
- type: nextPendingType,
1501
- text: newGeminiMessageBuffer
1502
- };
1503
- if (item && "timestamp" in item) {
1504
- base.timestamp = item.timestamp;
1505
- }
1506
- return base;
1507
- });
1508
- return newGeminiMessageBuffer;
1509
- },
1510
- [
1511
- commitItem,
1512
- pendingHistoryItemRef,
1513
- setPendingHistoryItem,
1514
- terminalWidth,
1515
- terminalHeight,
1516
- availableTerminalHeightRef,
1517
- terminalWidthRef
1518
- ]
1519
- );
1520
- const mergeThought = (0, import_react5.useCallback)(
1521
- (incoming) => {
1522
- setThought((prev) => {
1523
- const incomingDescription = incoming.description ? clampLoadingThoughtDescription(incoming.description) : incoming.description;
1524
- if (!prev) {
1525
- if (debugLogger3.isEnabled()) {
1526
- debugLogger3.debug(
1527
- `[THOUGHT_MERGE] New thought: subjectLength=${incoming.subject?.length ?? 0}, description length=${incomingDescription?.length ?? 0}`
1528
- );
1529
- }
1530
- return {
1531
- ...incoming,
1532
- description: incomingDescription
1533
- };
1534
- }
1535
- const subject = incoming.subject || prev.subject;
1536
- const description = clampLoadingThoughtDescription(
1537
- `${prev.description ?? ""}${incomingDescription ?? ""}`
1538
- );
1539
- if (debugLogger3.isEnabled()) {
1540
- debugLogger3.debug(
1541
- `[THOUGHT_MERGE] Accumulating thought: prev length=${prev.description?.length ?? 0}, incoming length=${incomingDescription?.length ?? 0}, total length=${description.length}`
1542
- );
1543
- }
1544
- return { subject, description };
1545
- });
1546
- },
1547
- [setThought]
1548
- );
1549
- const handleThoughtEvent = (0, import_react5.useCallback)(
1550
- (eventValue, currentThoughtBuffer, userMessageTimestamp) => {
1551
- if (turnCancelledRef.current) {
1552
- return "";
1553
- }
1554
- const thoughtText = eventValue.description ?? "";
1555
- if (!thoughtText) {
1556
- return currentThoughtBuffer;
1557
- }
1558
- let newThoughtBuffer = currentThoughtBuffer + thoughtText;
1559
- if (newThoughtBuffer.trim().length === 0) {
1560
- return newThoughtBuffer;
1561
- }
1562
- streamingResponseLengthRef.current += thoughtText.length;
1563
- const startingNewThought = currentThoughtBuffer.trim().length === 0;
1564
- const description = startingNewThought ? stripLeadingBlankLines(newThoughtBuffer) : thoughtText;
1565
- if (startingNewThought) {
1566
- thoughtStartTimeRef.current = Date.now();
1567
- newThoughtBuffer = description;
1568
- }
1569
- mergeThought({
1570
- ...eventValue,
1571
- description
1572
- });
1573
- let pendingThoughtType = startingNewThought ? "gemini_thought" : pendingThoughtItemRef.current?.type === "gemini_thought_content" ? "gemini_thought_content" : "gemini_thought";
1574
- const getThoughtDurationMs = /* @__PURE__ */ __name(() => thoughtStartTimeRef.current ? Date.now() - thoughtStartTimeRef.current : 0, "getThoughtDurationMs");
1575
- const buildThoughtItem = /* @__PURE__ */ __name((type, text) => type === "gemini_thought" ? {
1576
- type,
1577
- text,
1578
- durationMs: getThoughtDurationMs()
1579
- } : {
1580
- type,
1581
- text
1582
- }, "buildThoughtItem");
1583
- let splitPoint = findLastSafeSplitPoint(
1584
- newThoughtBuffer,
1585
- STREAM_PENDING_ITEM_MAX_CHARS
1586
- );
1587
- while (newThoughtBuffer.length > STREAM_PENDING_ITEM_MAX_CHARS) {
1588
- const safeSplitPoint = splitPoint > 0 && splitPoint < newThoughtBuffer.length ? splitPoint : STREAM_PENDING_ITEM_MAX_CHARS;
1589
- const { before: beforeText, after: afterText } = splitFencedMarkdown(
1590
- newThoughtBuffer,
1591
- safeSplitPoint
1592
- );
1593
- addItem(
1594
- buildThoughtItem(pendingThoughtType, beforeText),
1595
- userMessageTimestamp
1596
- );
1597
- pendingThoughtType = "gemini_thought_content";
1598
- newThoughtBuffer = afterText;
1599
- splitPoint = findLastSafeSplitPoint(
1600
- newThoughtBuffer,
1601
- STREAM_PENDING_ITEM_MAX_CHARS
1602
- );
1603
- }
1604
- setPendingThoughtItem(
1605
- buildThoughtItem(pendingThoughtType, newThoughtBuffer)
1606
- );
1607
- return newThoughtBuffer;
1608
- },
1609
- [addItem, mergeThought, pendingThoughtItemRef, setPendingThoughtItem]
1610
- );
1611
- const commitPendingThought = (0, import_react5.useCallback)(
1612
- (userMessageTimestamp) => {
1613
- if (pendingThoughtItemRef.current) {
1614
- const item = { ...pendingThoughtItemRef.current };
1615
- if (item.type === "gemini_thought" && thoughtStartTimeRef.current) {
1616
- item.durationMs = Date.now() - thoughtStartTimeRef.current;
1617
- }
1618
- addItem(item, userMessageTimestamp);
1619
- }
1620
- setPendingThoughtItem(null);
1621
- thoughtStartTimeRef.current = null;
1622
- },
1623
- [addItem, pendingThoughtItemRef, setPendingThoughtItem]
1624
- );
1625
- const handleUserCancelledEvent = (0, import_react5.useCallback)(
1626
- (userMessageTimestamp) => {
1627
- if (turnCancelledRef.current) {
1628
- return;
1629
- }
1630
- lastPromptErroredRef.current = false;
1631
- commitPendingThought(userMessageTimestamp);
1632
- if (pendingHistoryItemRef.current) {
1633
- if (pendingHistoryItemRef.current.type === "tool_group") {
1634
- const updatedTools = pendingHistoryItemRef.current.tools.map(
1635
- (tool) => tool.status === "Pending" /* Pending */ || tool.status === "Confirming" /* Confirming */ || tool.status === "Executing" /* Executing */ ? { ...tool, status: "Canceled" /* Canceled */ } : tool
1636
- );
1637
- const pendingItem = {
1638
- ...pendingHistoryItemRef.current,
1639
- tools: updatedTools
1640
- };
1641
- addItem(pendingItem, userMessageTimestamp);
1642
- } else {
1643
- commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
1644
- }
1645
- setPendingHistoryItem(null);
1646
- }
1647
- addItem(
1648
- { type: "info" /* INFO */, text: "User cancelled the request." },
1649
- userMessageTimestamp
1650
- );
1651
- clearRetryCountdown();
1652
- setIsResponding(false);
1653
- setThought(null);
1654
- },
1655
- [
1656
- addItem,
1657
- commitPendingThought,
1658
- commitItem,
1659
- pendingHistoryItemRef,
1660
- setPendingHistoryItem,
1661
- setThought,
1662
- clearRetryCountdown
1663
- ]
1664
- );
1665
- const handleErrorEvent = (0, import_react5.useCallback)(
1666
- (eventValue, userMessageTimestamp) => {
1667
- lastPromptErroredRef.current = true;
1668
- commitPendingThought(userMessageTimestamp);
1669
- if (pendingHistoryItemRef.current) {
1670
- commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
1671
- setPendingHistoryItem(null);
1672
- }
1673
- const isShowingAutoRetry = retryCountdownTimerRef.current !== null;
1674
- clearRetryCountdown();
1675
- const formattedErrorText = parseAndFormatApiError(
1676
- eventValue.error,
1677
- config.getContentGeneratorConfig()?.authType
1678
- );
1679
- if (!isShowingAutoRetry) {
1680
- const retryHint = t("Press Ctrl+Y to retry");
1681
- setPendingRetryErrorItem({
1682
- type: "error",
1683
- text: formattedErrorText,
1684
- hint: retryHint
1685
- });
1686
- }
1687
- setThought(null);
1688
- const errorType = classifyApiError(eventValue.error);
1689
- config.getHookSystem()?.fireStopFailureEvent(
1690
- errorType,
1691
- eventValue.error.message,
1692
- formattedErrorText
1693
- ).catch((err) => {
1694
- debugLogger3.warn(`StopFailure hook failed: ${err}`);
1695
- });
1696
- },
1697
- [
1698
- commitPendingThought,
1699
- commitItem,
1700
- pendingHistoryItemRef,
1701
- setPendingHistoryItem,
1702
- setPendingRetryErrorItem,
1703
- config,
1704
- setThought,
1705
- clearRetryCountdown
1706
- ]
1707
- );
1708
- const handleCitationEvent = (0, import_react5.useCallback)(
1709
- (text, userMessageTimestamp) => {
1710
- if (!showCitations(settings)) {
1711
- return;
1712
- }
1713
- if (pendingHistoryItemRef.current) {
1714
- commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
1715
- setPendingHistoryItem(null);
1716
- }
1717
- addItem({ type: "info" /* INFO */, text }, userMessageTimestamp);
1718
- },
1719
- [
1720
- addItem,
1721
- commitItem,
1722
- pendingHistoryItemRef,
1723
- setPendingHistoryItem,
1724
- settings
1725
- ]
1726
- );
1727
- const handleFinishedEvent = (0, import_react5.useCallback)(
1728
- (event, userMessageTimestamp) => {
1729
- const finishReason = event.value.reason;
1730
- if (!finishReason) {
1731
- return;
1732
- }
1733
- const finishReasonMessages = {
1734
- [FinishReason.FINISH_REASON_UNSPECIFIED]: void 0,
1735
- [FinishReason.STOP]: void 0,
1736
- [FinishReason.MAX_TOKENS]: "Response truncated due to token limits.",
1737
- [FinishReason.SAFETY]: "Response stopped due to safety reasons.",
1738
- [FinishReason.RECITATION]: "Response stopped due to recitation policy.",
1739
- [FinishReason.LANGUAGE]: "Response stopped due to unsupported language.",
1740
- [FinishReason.BLOCKLIST]: "Response stopped due to forbidden terms.",
1741
- [FinishReason.PROHIBITED_CONTENT]: "Response stopped due to prohibited content.",
1742
- [FinishReason.SPII]: "Response stopped due to sensitive personally identifiable information.",
1743
- [FinishReason.OTHER]: "Response stopped for other reasons.",
1744
- [FinishReason.MALFORMED_FUNCTION_CALL]: "Response stopped due to malformed function call.",
1745
- [FinishReason.IMAGE_SAFETY]: "Response stopped due to image safety violations.",
1746
- [FinishReason.IMAGE_PROHIBITED_CONTENT]: "Response stopped due to image prohibited content.",
1747
- [FinishReason.IMAGE_RECITATION]: "Response stopped due to image recitation policy.",
1748
- [FinishReason.IMAGE_OTHER]: "Response stopped due to other image-related reasons.",
1749
- [FinishReason.NO_IMAGE]: "Response stopped due to no image.",
1750
- [FinishReason.UNEXPECTED_TOOL_CALL]: "Response stopped due to unexpected tool call."
1751
- };
1752
- const message = finishReasonMessages[finishReason];
1753
- if (message) {
1754
- addItem(
1755
- {
1756
- type: "info",
1757
- text: `\u26A0 ${message}`
1758
- },
1759
- userMessageTimestamp
1760
- );
1761
- }
1762
- if (retryCountdownTimerRef.current) {
1763
- clearRetryCountdown();
1764
- }
1765
- },
1766
- [addItem, clearRetryCountdown]
1767
- );
1768
- const autonomousLoopTickResolverRef = (0, import_react5.useRef)(null);
1769
- const handleChatCompressionEvent = (0, import_react5.useCallback)(
1770
- (eventValue, userMessageTimestamp) => {
1771
- autonomousLoopTickResolverRef.current?.resetCache();
1772
- if (pendingHistoryItemRef.current) {
1773
- commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
1774
- setPendingHistoryItem(null);
1775
- }
1776
- const activeModel = modelOverrideRef.current ?? config.getModel();
1777
- const reasonClause = eventValue?.triggerReason === "image_overflow" ? `accumulated enough tool screenshots to trigger compaction for ${activeModel}` : `approached the input token limit for ${activeModel}`;
1778
- return addItem(
1779
- {
1780
- type: "info",
1781
- text: `IMPORTANT: This conversation ${reasonClause}. A compressed context will be sent for future messages (compressed from: ${eventValue?.originalTokenCount ?? "unknown"} to ${eventValue?.newTokenCount ?? "unknown"} tokens).`
1782
- },
1783
- Date.now()
1784
- );
1785
- },
1786
- [addItem, commitItem, config, pendingHistoryItemRef, setPendingHistoryItem]
1787
- );
1788
- const handleMaxSessionTurnsEvent = (0, import_react5.useCallback)(
1789
- () => addItem(
1790
- {
1791
- type: "info",
1792
- text: `The session has reached the maximum number of turns: ${config.getMaxSessionTurns()}. Please update this limit in your setting.json file.`
1793
- },
1794
- Date.now()
1795
- ),
1796
- [addItem, config]
1797
- );
1798
- const handleSessionTokenLimitExceededEvent = (0, import_react5.useCallback)(
1799
- (value) => addItem(
1800
- {
1801
- type: "error",
1802
- text: `\u2717 Session token limit exceeded: ${value.currentTokens.toLocaleString()} tokens > ${value.limit.toLocaleString()} limit.
1803
-
1804
- \u2605 Solutions:
1805
- \u2022 Start a new session: Use /clear command
1806
- \u2022 Increase limit: Add "sessionTokenLimit": (e.g., 128000) to your settings.json
1807
- \u2022 Compress history: Use /compress command to compress history`
1808
- },
1809
- Date.now()
1810
- ),
1811
- [addItem]
1812
- );
1813
- const handleLoopDetectionConfirmation = (0, import_react5.useCallback)(
1814
- (result) => {
1815
- setLoopDetectionConfirmationRequest(null);
1816
- if (result.userSelection === "disable") {
1817
- config.getGeminiClient().getLoopDetectionService().disableForSession();
1818
- addItem(
1819
- {
1820
- type: "info",
1821
- text: `Loop detection has been disabled for this session. Please try your request again.`
1822
- },
1823
- Date.now()
1824
- );
1825
- } else {
1826
- addItem(
1827
- {
1828
- type: "info",
1829
- text: `A potential loop was detected. This can happen due to repetitive tool calls or other model behavior. The request has been halted.`
1830
- },
1831
- Date.now()
1832
- );
1833
- }
1834
- },
1835
- [config, addItem]
1836
- );
1837
- const handleLoopDetectedEvent = (0, import_react5.useCallback)(() => {
1838
- setLoopDetectionConfirmationRequest({
1839
- onComplete: handleLoopDetectionConfirmation
1840
- });
1841
- }, [handleLoopDetectionConfirmation]);
1842
- const handleUserPromptSubmitBlockedEvent = (0, import_react5.useCallback)(
1843
- (value, userMessageTimestamp) => {
1844
- if (pendingHistoryItemRef.current) {
1845
- commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
1846
- setPendingHistoryItem(null);
1847
- }
1848
- addItem(
1849
- {
1850
- type: "user_prompt_submit_blocked",
1851
- reason: value.reason,
1852
- originalPrompt: value.originalPrompt
1853
- },
1854
- userMessageTimestamp
1855
- );
1856
- },
1857
- [addItem, commitItem, pendingHistoryItemRef, setPendingHistoryItem]
1858
- );
1859
- const handleStopHookLoopEvent = (0, import_react5.useCallback)(
1860
- (value, userMessageTimestamp) => {
1861
- if (pendingHistoryItemRef.current) {
1862
- commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
1863
- setPendingHistoryItem(null);
1864
- }
1865
- const activeGoal = getActiveGoal(config.getSessionId());
1866
- if (activeGoal && activeGoal.condition) {
1867
- const item = {
1868
- type: "goal_status" /* GOAL_STATUS */,
1869
- kind: "checking",
1870
- condition: activeGoal.condition,
1871
- iterations: activeGoal.iterations,
1872
- // Carried so a transcript truncated past its `set` card can still
1873
- // restore the goal's original start time.
1874
- setAt: activeGoal.setAt,
1875
- lastReason: activeGoal.lastReason ?? value.reasons[value.reasons.length - 1]
1876
- };
1877
- addItem(item, userMessageTimestamp);
1878
- recordGoalStatusItem(config, item);
1879
- return;
1880
- }
1881
- addItem(
1882
- {
1883
- type: "stop_hook_loop",
1884
- iterationCount: value.iterationCount,
1885
- reasons: value.reasons,
1886
- stopHookCount: value.stopHookCount
1887
- },
1888
- userMessageTimestamp
1889
- );
1890
- },
1891
- [addItem, commitItem, config, pendingHistoryItemRef, setPendingHistoryItem]
1892
- );
1893
- const handleActiveGoalEvent = (0, import_react5.useCallback)(
1894
- (activeGoal) => {
1895
- const sessionId = config.getSessionId();
1896
- const currentActiveGoal = getActiveGoal(sessionId);
1897
- if (activeGoal) {
1898
- if (activeGoalEquals(currentActiveGoal, activeGoal)) {
1899
- return;
1900
- }
1901
- setActiveGoal(sessionId, activeGoal);
1902
- return;
1903
- }
1904
- if (!currentActiveGoal) {
1905
- return;
1906
- }
1907
- clearActiveGoal(sessionId);
1908
- },
1909
- [config]
1910
- );
1911
- const processGeminiStreamEvents = (0, import_react5.useCallback)(
1912
- async (stream, userMessageTimestamp, signal) => {
1913
- let geminiMessageBuffer = "";
1914
- let thoughtBuffer = "";
1915
- const toolCallRequests = [];
1916
- const bufferedEvents = [];
1917
- let flushTimer = null;
1918
- const discardBufferedStreamEvents = /* @__PURE__ */ __name(() => {
1919
- if (flushTimer) {
1920
- clearTimeout(flushTimer);
1921
- flushTimer = null;
1922
- }
1923
- bufferedEvents.length = 0;
1924
- }, "discardBufferedStreamEvents");
1925
- const flushBufferedStreamEvents = /* @__PURE__ */ __name(() => {
1926
- if (flushTimer) {
1927
- clearTimeout(flushTimer);
1928
- flushTimer = null;
1929
- }
1930
- if (bufferedEvents.length === 0) {
1931
- return;
1932
- }
1933
- while (bufferedEvents.length > 0) {
1934
- const nextEvent = bufferedEvents.shift();
1935
- if (nextEvent.kind === "content") {
1936
- const contentParts = [nextEvent.value];
1937
- while (bufferedEvents[0]?.kind === "content") {
1938
- const queuedContent = bufferedEvents.shift();
1939
- if (queuedContent?.kind !== "content") {
1940
- break;
1941
- }
1942
- contentParts.push(queuedContent.value);
1943
- }
1944
- geminiMessageBuffer = handleContentEvent(
1945
- contentParts.join(""),
1946
- geminiMessageBuffer,
1947
- userMessageTimestamp
1948
- );
1949
- continue;
1950
- }
1951
- let subject = nextEvent.value.subject;
1952
- const thoughtDescriptions = [];
1953
- if (nextEvent.value.description) {
1954
- thoughtDescriptions.push(nextEvent.value.description);
1955
- }
1956
- while (bufferedEvents[0]?.kind === "thought") {
1957
- const queuedThought = bufferedEvents.shift();
1958
- if (queuedThought?.kind !== "thought") {
1959
- break;
1960
- }
1961
- subject = queuedThought.value.subject || subject;
1962
- if (queuedThought.value.description) {
1963
- thoughtDescriptions.push(queuedThought.value.description);
1964
- }
1965
- }
1966
- thoughtBuffer = handleThoughtEvent(
1967
- {
1968
- subject,
1969
- description: thoughtDescriptions.join("")
1970
- },
1971
- thoughtBuffer,
1972
- userMessageTimestamp
1973
- );
1974
- }
1975
- }, "flushBufferedStreamEvents");
1976
- const scheduleBufferedStreamFlush = /* @__PURE__ */ __name(() => {
1977
- if (flushTimer) {
1978
- return;
1979
- }
1980
- flushTimer = setTimeout(() => {
1981
- flushBufferedStreamEvents();
1982
- }, STREAM_UPDATE_THROTTLE_MS);
1983
- }, "scheduleBufferedStreamFlush");
1984
- flushBufferedStreamEventsRef.current.add(flushBufferedStreamEvents);
1985
- dualOutput?.startAssistantMessage();
1986
- try {
1987
- for await (const event of stream) {
1988
- dualOutput?.processEvent(event);
1989
- switch (event.type) {
1990
- case "thought" /* Thought */:
1991
- if (event.value.subject && !event.value.description) {
1992
- flushBufferedStreamEvents();
1993
- setThought(event.value);
1994
- } else {
1995
- bufferedEvents.push({ kind: "thought", value: event.value });
1996
- scheduleBufferedStreamFlush();
1997
- }
1998
- break;
1999
- case "content" /* Content */:
2000
- if (pendingThoughtItemRef.current || bufferedEvents.some((e) => e.kind === "thought")) {
2001
- flushBufferedStreamEvents();
2002
- commitPendingThought(userMessageTimestamp);
2003
- thoughtBuffer = "";
2004
- }
2005
- setThought((prev) => prev ? null : prev);
2006
- bufferedEvents.push({ kind: "content", value: event.value });
2007
- scheduleBufferedStreamFlush();
2008
- break;
2009
- case "tool_call_request" /* ToolCallRequest */:
2010
- flushBufferedStreamEvents();
2011
- commitPendingThought(userMessageTimestamp);
2012
- thoughtBuffer = "";
2013
- setThought((prev) => prev ? null : prev);
2014
- toolCallRequests.push(event.value);
2015
- try {
2016
- const argsJson = JSON.stringify(event.value.args);
2017
- streamingResponseLengthRef.current += argsJson.length;
2018
- } catch {
2019
- }
2020
- break;
2021
- case "user_cancelled" /* UserCancelled */:
2022
- flushBufferedStreamEvents();
2023
- toolCallRequests.length = 0;
2024
- handleUserCancelledEvent(userMessageTimestamp);
2025
- break;
2026
- case "error" /* Error */:
2027
- flushBufferedStreamEvents();
2028
- handleErrorEvent(event.value, userMessageTimestamp);
2029
- break;
2030
- case "chat_compressed" /* ChatCompressed */:
2031
- flushBufferedStreamEvents();
2032
- handleChatCompressionEvent(event.value, userMessageTimestamp);
2033
- break;
2034
- case "tool_call_confirmation" /* ToolCallConfirmation */:
2035
- case "tool_call_response" /* ToolCallResponse */:
2036
- flushBufferedStreamEvents();
2037
- break;
2038
- case "max_session_turns" /* MaxSessionTurns */:
2039
- flushBufferedStreamEvents();
2040
- handleMaxSessionTurnsEvent();
2041
- break;
2042
- case "session_token_limit_exceeded" /* SessionTokenLimitExceeded */:
2043
- flushBufferedStreamEvents();
2044
- handleSessionTokenLimitExceededEvent(event.value);
2045
- break;
2046
- case "finished" /* Finished */:
2047
- flushBufferedStreamEvents();
2048
- commitPendingThought(userMessageTimestamp);
2049
- handleFinishedEvent(
2050
- event,
2051
- userMessageTimestamp
2052
- );
2053
- if (pendingHistoryItemRef.current) {
2054
- commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
2055
- setPendingHistoryItem(null);
2056
- }
2057
- geminiMessageBuffer = "";
2058
- thoughtBuffer = "";
2059
- setThought(null);
2060
- break;
2061
- case "citation" /* Citation */:
2062
- flushBufferedStreamEvents();
2063
- handleCitationEvent(event.value, userMessageTimestamp);
2064
- break;
2065
- case "loop_detected" /* LoopDetected */:
2066
- flushBufferedStreamEvents();
2067
- loopDetectedRef.current = true;
2068
- break;
2069
- case "retry" /* Retry */:
2070
- if (!event.isContinuation) {
2071
- discardBufferedStreamEvents();
2072
- if (pendingHistoryItemRef.current) {
2073
- setPendingHistoryItem(null);
2074
- }
2075
- commitPendingThought(userMessageTimestamp);
2076
- thoughtBuffer = "";
2077
- setThought(null);
2078
- geminiMessageBuffer = "";
2079
- } else {
2080
- flushBufferedStreamEvents();
2081
- }
2082
- toolCallRequests.length = 0;
2083
- if (event.retryInfo) {
2084
- startRetryCountdown(event.retryInfo);
2085
- } else {
2086
- clearRetryCountdown();
2087
- }
2088
- break;
2089
- case "model_fallback" /* ModelFallback */: {
2090
- discardBufferedStreamEvents();
2091
- if (pendingHistoryItemRef.current) {
2092
- setPendingHistoryItem(null);
2093
- }
2094
- commitPendingThought(userMessageTimestamp);
2095
- thoughtBuffer = "";
2096
- setThought(null);
2097
- geminiMessageBuffer = "";
2098
- toolCallRequests.length = 0;
2099
- clearRetryCountdown();
2100
- const fromModel = sanitizeDisplayText(event.fromModel) ?? "(unknown)";
2101
- const toModel = sanitizeDisplayText(event.toModel) ?? "(unknown)";
2102
- addItem(
2103
- {
2104
- type: "notification",
2105
- text: `Model ${fromModel} unavailable, falling back to ${toModel}`
2106
- },
2107
- userMessageTimestamp
2108
- );
2109
- break;
2110
- }
2111
- case "hook_system_message" /* HookSystemMessage */:
2112
- flushBufferedStreamEvents();
2113
- if (pendingHistoryItemRef.current) {
2114
- commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
2115
- setPendingHistoryItem(null);
2116
- }
2117
- addItem(
2118
- {
2119
- type: "stop_hook_system_message",
2120
- message: event.value
2121
- },
2122
- userMessageTimestamp
2123
- );
2124
- break;
2125
- case "user_prompt_submit_blocked" /* UserPromptSubmitBlocked */:
2126
- flushBufferedStreamEvents();
2127
- handleUserPromptSubmitBlockedEvent(
2128
- event.value,
2129
- userMessageTimestamp
2130
- );
2131
- break;
2132
- case "stop_hook_loop" /* StopHookLoop */:
2133
- flushBufferedStreamEvents();
2134
- handleStopHookLoopEvent(event.value, userMessageTimestamp);
2135
- break;
2136
- case "active_goal" /* ActiveGoal */:
2137
- handleActiveGoalEvent(event.value);
2138
- break;
2139
- default: {
2140
- const unreachable = event;
2141
- return unreachable;
2142
- }
2143
- }
2144
- }
2145
- } finally {
2146
- flushBufferedStreamEvents();
2147
- commitPendingThought(userMessageTimestamp);
2148
- discardBufferedStreamEvents();
2149
- flushBufferedStreamEventsRef.current.delete(flushBufferedStreamEvents);
2150
- }
2151
- dualOutput?.finalizeAssistantMessage();
2152
- if (toolCallRequests.length > 0 && !signal.aborted && !loopDetectedRef.current) {
2153
- const executableToolCallRequests = [];
2154
- const duplicateResponseParts = [];
2155
- let duplicatePromptId;
2156
- const historyCallIdsWithResponse = geminiClient ? geminiClient.getHistoryFunctionResponseIds() : /* @__PURE__ */ new Set();
2157
- const handledProviderIds = /* @__PURE__ */ new Set([
2158
- ...handledProviderToolCallIdsRef.current,
2159
- ...historyCallIdsWithResponse
2160
- ]);
2161
- const repeatedDuplicateRequest = findRepeatedDuplicateProviderToolCall(
2162
- toolCallRequests,
2163
- (request) => request.providerCallId,
2164
- handledProviderIds,
2165
- duplicateProviderToolCallResponseIdsRef.current
2166
- );
2167
- if (repeatedDuplicateRequest?.providerCallId) {
2168
- debugLogger3.debug(
2169
- `[processGeminiStreamEvents] Dropping batch after repeated duplicate provider tool-call id: ${repeatedDuplicateRequest.providerCallId} (tool: ${repeatedDuplicateRequest.name})`
2170
- );
2171
- loopDetectedRef.current = true;
2172
- return 0 /* Completed */;
2173
- }
2174
- for (const request of toolCallRequests) {
2175
- const providerCallId = request.providerCallId;
2176
- if (!providerCallId) {
2177
- executableToolCallRequests.push(request);
2178
- continue;
2179
- }
2180
- if (handledProviderToolCallIdsRef.current.has(providerCallId) || historyCallIdsWithResponse.has(providerCallId)) {
2181
- markDuplicateProviderToolCallResponseSent(
2182
- providerCallId,
2183
- duplicateProviderToolCallResponseIdsRef.current
2184
- );
2185
- const response = createDuplicateProviderToolCallResponse(request);
2186
- debugLogger3.debug(
2187
- `[processGeminiStreamEvents] Suppressing duplicate provider tool-call id: ${providerCallId} (tool: ${request.name})`
2188
- );
2189
- dualOutput?.emitToolResult(request, response);
2190
- duplicateResponseParts.push(...response.responseParts);
2191
- duplicatePromptId ??= request.prompt_id;
2192
- continue;
2193
- }
2194
- handledProviderToolCallIdsRef.current.add(providerCallId);
2195
- executableToolCallRequests.push(request);
2196
- }
2197
- if (duplicateResponseParts.length > 0) {
2198
- if (executableToolCallRequests.length > 0) {
2199
- pendingDuplicateToolResponsesRef.current.push({
2200
- executableCallIds: new Set(
2201
- executableToolCallRequests.map((request) => request.callId)
2202
- ),
2203
- promptId: duplicatePromptId ?? executableToolCallRequests[0]?.prompt_id,
2204
- responseParts: duplicateResponseParts
2205
- });
2206
- } else {
2207
- immediateDuplicateToolResponsesRef.current = {
2208
- promptId: duplicatePromptId,
2209
- responseParts: duplicateResponseParts
2210
- };
2211
- }
2212
- }
2213
- if (executableToolCallRequests.length > 0) {
2214
- scheduleToolCalls(
2215
- executableToolCallRequests,
2216
- signal,
2217
- modelOverrideRef.current
2218
- );
2219
- }
2220
- }
2221
- return 0 /* Completed */;
2222
- },
2223
- [
2224
- handleContentEvent,
2225
- handleThoughtEvent,
2226
- handleUserCancelledEvent,
2227
- handleErrorEvent,
2228
- scheduleToolCalls,
2229
- geminiClient,
2230
- handleChatCompressionEvent,
2231
- handleFinishedEvent,
2232
- handleMaxSessionTurnsEvent,
2233
- handleSessionTokenLimitExceededEvent,
2234
- handleCitationEvent,
2235
- startRetryCountdown,
2236
- clearRetryCountdown,
2237
- setThought,
2238
- commitPendingThought,
2239
- pendingHistoryItemRef,
2240
- pendingThoughtItemRef,
2241
- setPendingHistoryItem,
2242
- handleUserPromptSubmitBlockedEvent,
2243
- handleStopHookLoopEvent,
2244
- handleActiveGoalEvent,
2245
- addItem,
2246
- commitItem,
2247
- dualOutput
2248
- ]
2249
- );
2250
- const resolveSteeredMessages = (0, import_react5.useCallback)(
2251
- async (messages, signal) => {
2252
- const resolvedMessages = [];
2253
- const resolvedForRecording = [];
2254
- const timestamp = Date.now();
2255
- for (let index = 0; index < messages.length; index += 1) {
2256
- if (signal.aborted) break;
2257
- const message = messages[index];
2258
- const sideEffects = [];
2259
- let resolvedQuery = [{ text: message }];
2260
- if (isAtCommand(message)) {
2261
- const timeout = new AbortController();
2262
- const atCommandSignal = AbortSignal.any([signal, timeout.signal]);
2263
- const timeoutId = setTimeout(() => {
2264
- timeout.abort(
2265
- new Error(MID_TURN_AT_COMMAND_RESOLVE_TIMEOUT_MESSAGE)
2266
- );
2267
- }, MID_TURN_AT_COMMAND_RESOLVE_TIMEOUT_MS);
2268
- try {
2269
- const atCommandResult = await resolveWithAbort(
2270
- atCommandSignal,
2271
- () => resolveAtCommandQuery({
2272
- query: message,
2273
- config,
2274
- onDebugMessage,
2275
- messageId: timestamp + index,
2276
- signal: atCommandSignal
2277
- })
2278
- );
2279
- const shouldSkipMessage = !atCommandResult.shouldProceed && (atCommandResult.toolDisplays?.length ?? 0) > 0;
2280
- if (atCommandResult.shouldProceed && atCommandResult.processedQuery !== null) {
2281
- resolvedQuery = atCommandResult.processedQuery;
2282
- } else if (atCommandResult.toolDisplays?.length) {
2283
- const toolDisplays = atCommandResult.toolDisplays;
2284
- const showToolDisplays = /* @__PURE__ */ __name(() => addItem(
2285
- { type: "tool_group", tools: toolDisplays },
2286
- timestamp + index
2287
- ), "showToolDisplays");
2288
- if (shouldSkipMessage) showToolDisplays();
2289
- else sideEffects.push(showToolDisplays);
2290
- }
2291
- if (atCommandResult.recording) {
2292
- const recordAtCommand = /* @__PURE__ */ __name(() => config.getChatRecordingService?.()?.recordAtCommand?.({
2293
- filesRead: atCommandResult.recording.filesRead,
2294
- status: atCommandResult.recording.status,
2295
- ...atCommandResult.recording.message ? { message: atCommandResult.recording.message } : {},
2296
- userText: message
2297
- }), "recordAtCommand");
2298
- if (shouldSkipMessage) recordAtCommand();
2299
- else sideEffects.push(recordAtCommand);
2300
- }
2301
- if (shouldSkipMessage) continue;
2302
- } catch (error) {
2303
- const errorMessage = getErrorMessage(error);
2304
- onDebugMessage(
2305
- `Failed to resolve mid-turn @ command: ${errorMessage}`
2306
- );
2307
- if (!signal.aborted) {
2308
- addItem(
2309
- {
2310
- type: "warning" /* WARNING */,
2311
- text: `Could not attach file: ${errorMessage}`
2312
- },
2313
- Date.now()
2314
- );
2315
- }
2316
- continue;
2317
- } finally {
2318
- clearTimeout(timeoutId);
2319
- }
2320
- if (signal.aborted) break;
2321
- }
2322
- const bridgeResult = await applyVisionBridgeIfNeeded(
2323
- resolvedQuery,
2324
- timestamp + index,
2325
- signal
2326
- );
2327
- if (!bridgeResult.shouldProceed) {
2328
- if (signal.aborted) break;
2329
- continue;
2330
- }
2331
- const messageParts = normalizePartList(
2332
- bridgeResult.parts ?? resolvedQuery
2333
- );
2334
- const formatCheck = checkImageFormatsSupport(messageParts);
2335
- if (formatCheck.hasUnsupportedFormats) {
2336
- sideEffects.push(
2337
- () => addItem(
2338
- {
2339
- type: "info" /* INFO */,
2340
- text: getUnsupportedImageFormatWarning()
2341
- },
2342
- Date.now()
2343
- )
2344
- );
2345
- }
2346
- if (resolvedMessages.length > 0 && messageParts.length > 0) {
2347
- resolvedMessages.push({ text: "\n\n" });
2348
- }
2349
- resolvedMessages.push(...messageParts);
2350
- resolvedForRecording.push({
2351
- message,
2352
- parts: messageParts,
2353
- sideEffects
2354
- });
2355
- }
2356
- if (signal.aborted) return void 0;
2357
- return {
2358
- parts: resolvedMessages,
2359
- accept: /* @__PURE__ */ __name(() => {
2360
- for (const { message, parts, sideEffects } of resolvedForRecording) {
2361
- for (const sideEffect of sideEffects) sideEffect();
2362
- config.getChatRecordingService?.()?.recordMidTurnUserMessage(parts, message);
2363
- addItem(
2364
- { type: "notification" /* NOTIFICATION */, text: message },
2365
- Date.now()
2366
- );
2367
- }
2368
- }, "accept")
2369
- };
2370
- },
2371
- [addItem, applyVisionBridgeIfNeeded, config, onDebugMessage]
2372
- );
2373
- const resolveDrainedSteerMessages = (0, import_react5.useCallback)(
2374
- async (messages, signal) => {
2375
- try {
2376
- const resolved = await resolveSteeredMessages(messages, signal);
2377
- if (signal.aborted) {
2378
- midTurnRestoreRef?.current?.(messages);
2379
- return void 0;
2380
- }
2381
- if (!resolved || resolved.parts.length === 0) return void 0;
2382
- let settled = false;
2383
- return {
2384
- parts: resolved.parts,
2385
- accept: /* @__PURE__ */ __name(() => {
2386
- if (settled) return;
2387
- settled = true;
2388
- resolved.accept();
2389
- }, "accept"),
2390
- restore: /* @__PURE__ */ __name(() => {
2391
- if (settled) return;
2392
- settled = true;
2393
- midTurnRestoreRef?.current?.(messages);
2394
- }, "restore")
2395
- };
2396
- } catch (error) {
2397
- midTurnRestoreRef?.current?.(messages);
2398
- onDebugMessage(
2399
- `Failed to prepare steer input: ${getErrorMessage(error)}`
2400
- );
2401
- return void 0;
2402
- }
2403
- },
2404
- [midTurnRestoreRef, onDebugMessage, resolveSteeredMessages]
2405
- );
2406
- const drainSteerAtBoundary = (0, import_react5.useCallback)(
2407
- async (signal) => {
2408
- const messages = midTurnDrainRef?.current?.() ?? [];
2409
- if (messages.length === 0) return void 0;
2410
- return resolveDrainedSteerMessages(messages, signal);
2411
- },
2412
- [midTurnDrainRef, resolveDrainedSteerMessages]
2413
- );
2414
- const submitQuery = (0, import_react5.useCallback)(
2415
- async (query, submitType = "userQuery" /* UserQuery */, prompt_id, metadata) => {
2416
- const allowConcurrentBtwDuringResponse = submitType === "userQuery" /* UserQuery */ && streamingState === "responding" /* Responding */ && typeof query === "string" && isBtwCommand(query);
2417
- const isTurnContinuation = submitType === "toolResult" /* ToolResult */ || submitType === "steer" /* Steer */;
2418
- if (isSubmittingQueryRef.current && !isTurnContinuation && !allowConcurrentBtwDuringResponse) {
2419
- metadata?.onDeliveryFailed?.();
2420
- return;
2421
- }
2422
- if ((streamingState === "responding" /* Responding */ || streamingState === "waiting_for_confirmation" /* WaitingForConfirmation */) && !isTurnContinuation && !allowConcurrentBtwDuringResponse) {
2423
- metadata?.onDeliveryFailed?.();
2424
- return;
2425
- }
2426
- isSubmittingQueryRef.current = true;
2427
- loopDetectedRef.current = false;
2428
- if (!isTurnContinuation && !allowConcurrentBtwDuringResponse) {
2429
- lastTurnUserItemRef.current = null;
2430
- turnSawContentEventRef.current = false;
2431
- handledProviderToolCallIdsRef.current.clear();
2432
- duplicateProviderToolCallResponseIdsRef.current.clear();
2433
- pendingDuplicateToolResponsesRef.current = [];
2434
- immediateDuplicateToolResponsesRef.current = null;
2435
- }
2436
- const userMessageTimestamp = Date.now();
2437
- if (!isTurnContinuation && submitType !== "notification" /* Notification */ && !allowConcurrentBtwDuringResponse) {
2438
- setModelSwitchedFromQuotaError(false);
2439
- const droppingInlineOverrideOnRetry = submitType === "retry" /* Retry */ && inlineModelOverrideActiveRef.current;
2440
- if (submitType !== "retry" /* Retry */ || inlineModelOverrideActiveRef.current) {
2441
- if (droppingInlineOverrideOnRetry) {
2442
- addItem(
2443
- {
2444
- type: "info",
2445
- text: `Inline model override cleared on retry \u2014 retrying on the session model (${config.getModel()}).`
2446
- },
2447
- userMessageTimestamp
2448
- );
2449
- }
2450
- clearModelOverride(modelOverrideRef, inlineModelOverrideActiveRef);
2451
- }
2452
- if (pendingRetryCountdownItemRef.current || pendingRetryErrorItemRef.current) {
2453
- const pendingError = pendingRetryErrorItemRef.current;
2454
- if (pendingError && pendingError.type === "error") {
2455
- const { hint: _hint, ...errorWithoutHint } = pendingError;
2456
- addItem(errorWithoutHint, userMessageTimestamp);
2457
- }
2458
- clearRetryCountdown();
2459
- }
2460
- }
2461
- const abortController = new AbortController();
2462
- const abortSignal = abortController.signal;
2463
- if (!allowConcurrentBtwDuringResponse) {
2464
- abortControllerRef.current = abortController;
2465
- turnCancelledRef.current = false;
2466
- }
2467
- if (!prompt_id) {
2468
- prompt_id = config.getSessionId() + "########" + getPromptCount();
2469
- }
2470
- return promptIdContext.run(prompt_id, async () => {
2471
- const { queryToSend, shouldProceed } = submitType === "retry" /* Retry */ ? { queryToSend: query, shouldProceed: true } : await prepareQueryForGemini(
2472
- query,
2473
- userMessageTimestamp,
2474
- abortSignal,
2475
- prompt_id,
2476
- submitType
2477
- );
2478
- if (!shouldProceed || queryToSend === null) {
2479
- isSubmittingQueryRef.current = false;
2480
- metadata?.onDeliveryFailed?.();
2481
- return;
2482
- }
2483
- if (submitType === "userQuery" /* UserQuery */ || submitType === "cron" /* Cron */ || submitType === "teammate" /* Teammate */) {
2484
- const formatCheck = checkImageFormatsSupport(queryToSend);
2485
- if (formatCheck.hasUnsupportedFormats) {
2486
- addItem(
2487
- {
2488
- type: "info" /* INFO */,
2489
- text: getUnsupportedImageFormatWarning()
2490
- },
2491
- userMessageTimestamp
2492
- );
2493
- }
2494
- }
2495
- const finalQueryToSend = queryToSend;
2496
- lastPromptRef.current = finalQueryToSend;
2497
- lastPromptErroredRef.current = false;
2498
- if (submitType === "userQuery" /* UserQuery */ || submitType === "cron" /* Cron */ || submitType === "teammate" /* Teammate */) {
2499
- startNewPrompt();
2500
- if (typeof queryToSend === "string") {
2501
- logUserPrompt(
2502
- config,
2503
- new UserPromptEvent(
2504
- queryToSend.length,
2505
- prompt_id,
2506
- config.getContentGeneratorConfig()?.authType,
2507
- queryToSend,
2508
- modelOverrideRef.current ?? config.getModel()
2509
- )
2510
- );
2511
- }
2512
- setThought(null);
2513
- setPendingThoughtItem(null);
2514
- }
2515
- if (submitType === "retry" /* Retry */) {
2516
- logUserRetry(config, new UserRetryEvent(prompt_id));
2517
- }
2518
- activeModelStreamsRef.current += 1;
2519
- setIsResponding(true);
2520
- setInitError(null);
2521
- setIsReceivingContent(false);
2522
- if (!isTurnContinuation) {
2523
- streamingResponseLengthRef.current = 0;
2524
- }
2525
- try {
2526
- if (dualOutput && submitType !== "toolResult" /* ToolResult */) {
2527
- const rawParts = typeof finalQueryToSend === "string" ? [finalQueryToSend] : Array.isArray(finalQueryToSend) ? finalQueryToSend : [finalQueryToSend];
2528
- const userParts = rawParts.map(
2529
- (p) => typeof p === "string" ? { text: p } : p
2530
- );
2531
- dualOutput.emitUserMessage(userParts);
2532
- }
2533
- const stream = geminiClient.sendMessageStream(
2534
- finalQueryToSend,
2535
- abortSignal,
2536
- prompt_id,
2537
- {
2538
- type: submitType,
2539
- notificationDisplayText: metadata?.notificationDisplayText,
2540
- modelOverride: modelOverrideRef.current,
2541
- steerInput: metadata?.steerInput,
2542
- ...!allowConcurrentBtwDuringResponse && midTurnDrainRef ? { getSteerInput: drainSteerAtBoundary } : {}
2543
- }
2544
- );
2545
- const processingStatus = await processGeminiStreamEvents(
2546
- stream,
2547
- userMessageTimestamp,
2548
- abortSignal
2549
- );
2550
- if (processingStatus === 1 /* UserCancelled */) {
2551
- submitPromptOnCompleteRef.current = null;
2552
- isSubmittingQueryRef.current = false;
2553
- metadata?.onDeliveryFailed?.();
2554
- return;
2555
- }
2556
- if (pendingHistoryItemRef.current) {
2557
- commitItem(pendingHistoryItemRef.current, userMessageTimestamp);
2558
- setPendingHistoryItem(null);
2559
- }
2560
- const immediateDuplicateToolResponses = immediateDuplicateToolResponsesRef.current;
2561
- if (immediateDuplicateToolResponses) {
2562
- immediateDuplicateToolResponsesRef.current = null;
2563
- await submitQuery(
2564
- immediateDuplicateToolResponses.responseParts,
2565
- "toolResult" /* ToolResult */,
2566
- immediateDuplicateToolResponses.promptId
2567
- );
2568
- }
2569
- if (retryCountdownTimerRef.current) {
2570
- clearRetryCountdown();
2571
- }
2572
- const loopDetected = loopDetectedRef.current;
2573
- if (loopDetected) {
2574
- loopDetectedRef.current = false;
2575
- handleLoopDetectedEvent();
2576
- }
2577
- if (lastPromptErroredRef.current) {
2578
- metadata?.onDeliveryFailed?.();
2579
- } else {
2580
- metadata?.onDelivered?.();
2581
- }
2582
- const onComplete = submitPromptOnCompleteRef.current;
2583
- if (onComplete) {
2584
- submitPromptOnCompleteRef.current = null;
2585
- void onComplete().catch((err) => {
2586
- debugLogger3.error("onComplete callback failed:", err);
2587
- });
2588
- }
2589
- if (geminiClient) {
2590
- const memoryTaskPromises = geminiClient.consumePendingMemoryTaskPromises();
2591
- for (const p of memoryTaskPromises) {
2592
- void p.then((count) => {
2593
- if (count > 0) {
2594
- addItem(
2595
- {
2596
- type: "memory_saved",
2597
- writtenCount: count,
2598
- verb: "Updated"
2599
- },
2600
- Date.now()
2601
- );
2602
- }
2603
- });
2604
- }
2605
- }
2606
- } catch (error) {
2607
- metadata?.onDeliveryFailed?.();
2608
- if (error instanceof UnauthorizedError) {
2609
- onAuthError("Session expired or is unauthorized.");
2610
- } else if (!isNodeError(error) || error.name !== "AbortError") {
2611
- lastPromptErroredRef.current = true;
2612
- const retryHint = t("Press Ctrl+Y to retry");
2613
- setPendingRetryErrorItem({
2614
- type: "error",
2615
- text: parseAndFormatApiError(
2616
- getErrorMessage(error) || "Unknown error",
2617
- config.getContentGeneratorConfig()?.authType
2618
- ),
2619
- hint: retryHint
2620
- });
2621
- }
2622
- } finally {
2623
- submitPromptOnCompleteRef.current = null;
2624
- activeModelStreamsRef.current = Math.max(
2625
- 0,
2626
- activeModelStreamsRef.current - 1
2627
- );
2628
- if (activeModelStreamsRef.current === 0) {
2629
- setIsResponding(false);
2630
- }
2631
- isSubmittingQueryRef.current = false;
2632
- }
2633
- });
2634
- },
2635
- [
2636
- streamingState,
2637
- setModelSwitchedFromQuotaError,
2638
- prepareQueryForGemini,
2639
- processGeminiStreamEvents,
2640
- pendingHistoryItemRef,
2641
- addItem,
2642
- commitItem,
2643
- setPendingHistoryItem,
2644
- setInitError,
2645
- geminiClient,
2646
- onAuthError,
2647
- config,
2648
- startNewPrompt,
2649
- getPromptCount,
2650
- handleLoopDetectedEvent,
2651
- clearRetryCountdown,
2652
- pendingRetryCountdownItemRef,
2653
- pendingRetryErrorItemRef,
2654
- setPendingRetryErrorItem,
2655
- setPendingThoughtItem,
2656
- dualOutput,
2657
- drainSteerAtBoundary,
2658
- midTurnDrainRef
2659
- ]
2660
- );
2661
- const retryLastPrompt = (0, import_react5.useCallback)(async () => {
2662
- if (skipRetryDelayRef.current) {
2663
- skipRetryDelayRef.current();
2664
- skipRetryDelayRef.current = null;
2665
- clearRetryCountdown();
2666
- return;
2667
- }
2668
- if (streamingState === "responding" /* Responding */ || streamingState === "waiting_for_confirmation" /* WaitingForConfirmation */) {
2669
- return;
2670
- }
2671
- const lastPrompt = lastPromptRef.current;
2672
- if (!lastPrompt || !lastPromptErroredRef.current) {
2673
- addItem(
2674
- {
2675
- type: "info" /* INFO */,
2676
- text: t("No failed request to retry.")
2677
- },
2678
- Date.now()
2679
- );
2680
- return;
2681
- }
2682
- clearRetryCountdown();
2683
- await submitQuery(lastPrompt, "retry" /* Retry */);
2684
- }, [streamingState, addItem, clearRetryCountdown, submitQuery]);
2685
- const handleApprovalModeChange = (0, import_react5.useCallback)(
2686
- async (newApprovalMode) => {
2687
- if (newApprovalMode === "yolo" /* YOLO */ || newApprovalMode === "auto-edit" /* AUTO_EDIT */) {
2688
- let awaitingApprovalCalls = toolCalls.filter(
2689
- (call) => {
2690
- if (call.status !== "awaiting_approval") {
2691
- return false;
2692
- }
2693
- const { confirmationDetails } = call;
2694
- return !(confirmationDetails && "hideAlwaysAllow" in confirmationDetails && confirmationDetails.hideAlwaysAllow === true);
2695
- }
2696
- );
2697
- if (newApprovalMode === "auto-edit" /* AUTO_EDIT */) {
2698
- awaitingApprovalCalls = awaitingApprovalCalls.filter(
2699
- (call) => EDIT_TOOL_NAMES.has(call.request.name)
2700
- );
2701
- }
2702
- for (const call of awaitingApprovalCalls) {
2703
- if (call.confirmationDetails?.onConfirm) {
2704
- try {
2705
- await call.confirmationDetails.onConfirm(
2706
- "proceed_once" /* ProceedOnce */
2707
- );
2708
- } catch (error) {
2709
- debugLogger3.error(
2710
- `Failed to auto-approve tool call ${call.request.callId}:`,
2711
- error
2712
- );
2713
- }
2714
- }
2715
- }
2716
- }
2717
- },
2718
- [toolCalls]
2719
- );
2720
- const handleCompletedTools = (0, import_react5.useCallback)(
2721
- async (completedToolCallsFromScheduler) => {
2722
- const completedAndReadyToSubmitTools = completedToolCallsFromScheduler.filter(
2723
- (tc) => {
2724
- const isTerminalState = tc.status === "success" || tc.status === "error" || tc.status === "cancelled";
2725
- if (isTerminalState) {
2726
- const completedOrCancelledCall = tc;
2727
- return completedOrCancelledCall.response?.responseParts !== void 0;
2728
- }
2729
- return false;
2730
- }
2731
- );
2732
- const historyCallIdsWithResponse = geminiClient ? geminiClient.getHistoryFunctionResponseIds() : /* @__PURE__ */ new Set();
2733
- const dedupedTools = completedAndReadyToSubmitTools.filter(
2734
- (tc) => historyCallIdsWithResponse.has(tc.request.callId)
2735
- );
2736
- const dedupedCallIds = dedupedTools.map((tc) => tc.request.callId);
2737
- if (dedupedCallIds.length > 0) {
2738
- debugLogger3.warn(
2739
- `[REPAIR] Dropping ${dedupedCallIds.length} late tool result(s) whose callId already has a functionResponse in history: ${dedupedCallIds.join(", ")}`
2740
- );
2741
- for (const tc of dedupedTools) {
2742
- if (tc.request.isClientInitiated) continue;
2743
- if (tc.status === "cancelled") continue;
2744
- geminiClient?.recordCompletedToolCall(
2745
- tc.request.name,
2746
- tc.request.args
2747
- );
2748
- }
2749
- markToolsAsSubmitted(dedupedCallIds);
2750
- }
2751
- if (activeModelStreamsRef.current > 0) {
2752
- return;
2753
- }
2754
- const clientTools = completedAndReadyToSubmitTools.filter(
2755
- (t2) => t2.request.isClientInitiated && !historyCallIdsWithResponse.has(t2.request.callId)
2756
- );
2757
- if (clientTools.length > 0) {
2758
- markToolsAsSubmitted(clientTools.map((t2) => t2.request.callId));
2759
- }
2760
- const newSuccessfulMemorySaves = completedAndReadyToSubmitTools.filter(
2761
- (t2) => t2.request.name === "save_memory" && t2.status === "success" && !processedMemoryToolsRef.current.has(t2.request.callId)
2762
- );
2763
- const geminiTools = completedAndReadyToSubmitTools.filter(
2764
- (t2) => !t2.request.isClientInitiated && !historyCallIdsWithResponse.has(t2.request.callId)
2765
- );
2766
- const didRefreshManagedMemory = await refreshMemoryAfterManagedWrite(
2767
- config,
2768
- completedAndReadyToSubmitTools.map((toolCall) => ({
2769
- toolName: toolCall.request.name,
2770
- args: toolCall.request.args,
2771
- status: toolCall.status
2772
- })),
2773
- { logContext: "interactive memory tool batch" }
2774
- );
2775
- if (newSuccessfulMemorySaves.length > 0) {
2776
- if (!didRefreshManagedMemory) {
2777
- void performMemoryRefresh().catch((err) => {
2778
- debugLogger3.warn(`save_memory refresh failed: ${err}`);
2779
- });
2780
- }
2781
- newSuccessfulMemorySaves.forEach(
2782
- (t2) => processedMemoryToolsRef.current.add(t2.request.callId)
2783
- );
2784
- }
2785
- const completedCallIds = new Set(
2786
- completedAndReadyToSubmitTools.map(
2787
- (toolCall) => toolCall.request.callId
2788
- )
2789
- );
2790
- const readyDuplicateBatches = [];
2791
- pendingDuplicateToolResponsesRef.current = pendingDuplicateToolResponsesRef.current.filter((batch) => {
2792
- const isReady = [...batch.executableCallIds].some(
2793
- (callId) => completedCallIds.has(callId)
2794
- );
2795
- if (isReady) {
2796
- readyDuplicateBatches.push(batch);
2797
- }
2798
- return !isReady;
2799
- });
2800
- const pendingDuplicateResponseParts = readyDuplicateBatches.flatMap(
2801
- (batch) => batch.responseParts
2802
- );
2803
- const pendingDuplicatePromptId = readyDuplicateBatches[0]?.promptId;
2804
- for (const toolCall of geminiTools) {
2805
- geminiClient?.recordCompletedToolCall(
2806
- toolCall.request.name,
2807
- toolCall.request.args
2808
- );
2809
- }
2810
- if (geminiTools.length === 0 && pendingDuplicateResponseParts.length === 0) {
2811
- return;
2812
- }
2813
- if (turnCancelledRef.current || abortControllerRef.current?.signal.aborted) {
2814
- markToolsAsSubmitted(
2815
- geminiTools.map((toolCall) => toolCall.request.callId)
2816
- );
2817
- return;
2818
- }
2819
- const allToolsCancelled = geminiTools.every(
2820
- (tc) => tc.status === "cancelled"
2821
- );
2822
- if (allToolsCancelled && pendingDuplicateResponseParts.length === 0) {
2823
- if (geminiClient) {
2824
- const combinedParts = geminiTools.flatMap(
2825
- (toolCall) => toolCall.response.responseParts
2826
- );
2827
- geminiClient.addHistory({
2828
- role: "user",
2829
- parts: combinedParts
2830
- });
2831
- config.getArenaAgentClient()?.reportCancelled();
2832
- }
2833
- const callIdsToMarkAsSubmitted2 = geminiTools.map(
2834
- (toolCall) => toolCall.request.callId
2835
- );
2836
- markToolsAsSubmitted(callIdsToMarkAsSubmitted2);
2837
- return;
2838
- }
2839
- const responsesToSend = geminiTools.flatMap(
2840
- (toolCall) => toolCall.response.responseParts
2841
- );
2842
- responsesToSend.push(...pendingDuplicateResponseParts);
2843
- const callIdsToMarkAsSubmitted = geminiTools.map(
2844
- (toolCall) => toolCall.request.callId
2845
- );
2846
- const prompt_ids = geminiTools.map(
2847
- (toolCall) => toolCall.request.prompt_id
2848
- );
2849
- const promptId = prompt_ids[0] ?? pendingDuplicatePromptId;
2850
- for (const toolCall of geminiTools) {
2851
- if ("modelOverride" in toolCall.response) {
2852
- if (inlineModelOverrideActiveRef.current || modelOverrideRef.current?.endsWith("\0")) {
2853
- debugLogger3.debug(
2854
- `skill-tool model override (${String(
2855
- toolCall.response.modelOverride
2856
- )}) blocked: ${inlineModelOverrideActiveRef.current ? "inline override active" : "full-turn override active"}`
2857
- );
2858
- } else {
2859
- applyModelOverride(
2860
- modelOverrideRef,
2861
- inlineModelOverrideActiveRef,
2862
- toolCall.response.modelOverride,
2863
- false
2864
- );
2865
- }
2866
- }
2867
- }
2868
- if (dualOutput) {
2869
- for (const toolCall of geminiTools) {
2870
- dualOutput.emitToolResult(toolCall.request, toolCall.response);
2871
- }
2872
- }
2873
- markToolsAsSubmitted(callIdsToMarkAsSubmitted);
2874
- if (config.getEmitToolUseSummaries()) {
2875
- const successfulTools = geminiTools.filter(
2876
- (tc) => tc.status === "success"
2877
- );
2878
- if (successfulTools.length > 0) {
2879
- const toolInfoForSummary = successfulTools.map((tc) => ({
2880
- name: tc.request.name,
2881
- input: tc.request.args,
2882
- output: extractToolResultText(tc.response.responseParts)
2883
- }));
2884
- const toolUseIds = successfulTools.map((tc) => tc.request.callId);
2885
- const lastAssistantText = extractLastAssistantText(
2886
- historyRef.current
2887
- );
2888
- const summaryAbort = new AbortController();
2889
- auxiliaryAbortRefsRef.current.add(summaryAbort);
2890
- const anchorCallId = toolUseIds[0];
2891
- void generateToolUseSummary({
2892
- config,
2893
- tools: toolInfoForSummary,
2894
- signal: summaryAbort.signal,
2895
- lastAssistantText
2896
- }).then((summary) => {
2897
- auxiliaryAbortRefsRef.current.delete(summaryAbort);
2898
- const cancelled = turnCancelledRef.current || abortControllerRef.current?.signal.aborted || summaryAbort.signal.aborted;
2899
- if (!summary || cancelled) return;
2900
- const currentHistory = historyRef.current;
2901
- const ourIdx = currentHistory.findIndex(
2902
- (h) => h.type === "tool_group" && h.tools.some((t2) => t2.callId === anchorCallId)
2903
- );
2904
- if (ourIdx < 0) return;
2905
- const laterToolGroupExists = currentHistory.slice(ourIdx + 1).some((h) => h.type === "tool_group");
2906
- if (laterToolGroupExists) return;
2907
- if (summary && !cancelled) {
2908
- addItem(
2909
- {
2910
- type: "tool_use_summary",
2911
- summary,
2912
- precedingToolUseIds: toolUseIds
2913
- },
2914
- Date.now()
2915
- );
2916
- }
2917
- }).catch(() => {
2918
- auxiliaryAbortRefsRef.current.delete(summaryAbort);
2919
- });
2920
- }
2921
- }
2922
- if (modelSwitchedFromQuotaError) {
2923
- return;
2924
- }
2925
- const drained = turnCancelledRef.current || abortControllerRef.current?.signal.aborted ? [] : midTurnDrainRef?.current?.() ?? [];
2926
- let drainedSteer;
2927
- if (drained.length > 0) {
2928
- const midTurnAbort = abortControllerRef.current ?? new AbortController();
2929
- const shouldTrackMidTurnAbort = !abortControllerRef.current;
2930
- if (shouldTrackMidTurnAbort) {
2931
- auxiliaryAbortRefsRef.current.add(midTurnAbort);
2932
- }
2933
- try {
2934
- drainedSteer = await resolveDrainedSteerMessages(
2935
- drained,
2936
- midTurnAbort.signal
2937
- );
2938
- if (drainedSteer) {
2939
- responsesToSend.push(...drainedSteer.parts);
2940
- }
2941
- } finally {
2942
- if (shouldTrackMidTurnAbort) {
2943
- auxiliaryAbortRefsRef.current.delete(midTurnAbort);
2944
- midTurnAbort.abort();
2945
- }
2946
- }
2947
- }
2948
- if (turnCancelledRef.current || abortControllerRef.current?.signal.aborted) {
2949
- drainedSteer?.restore();
2950
- return;
2951
- }
2952
- void submitQuery(responsesToSend, "toolResult" /* ToolResult */, promptId, {
2953
- steerInput: drainedSteer,
2954
- onDelivered: drainedSteer?.accept,
2955
- onDeliveryFailed: drainedSteer?.restore
2956
- });
2957
- },
2958
- [
2959
- submitQuery,
2960
- markToolsAsSubmitted,
2961
- geminiClient,
2962
- performMemoryRefresh,
2963
- modelSwitchedFromQuotaError,
2964
- config,
2965
- midTurnDrainRef,
2966
- addItem,
2967
- dualOutput,
2968
- resolveDrainedSteerMessages
2969
- ]
2970
- );
2971
- const pendingHistoryItems = (0, import_react5.useMemo)(
2972
- () => [
2973
- // Reasoning renders above the streaming answer.
2974
- pendingThoughtItem,
2975
- pendingHistoryItem,
2976
- pendingRetryErrorItem,
2977
- pendingRetryCountdownItem,
2978
- pendingToolCallGroupDisplay
2979
- ].filter((i) => i !== void 0 && i !== null),
2980
- [
2981
- pendingThoughtItem,
2982
- pendingHistoryItem,
2983
- pendingRetryErrorItem,
2984
- pendingRetryCountdownItem,
2985
- pendingToolCallGroupDisplay
2986
- ]
2987
- );
2988
- (0, import_react5.useEffect)(() => {
2989
- const saveRestorableToolCalls = /* @__PURE__ */ __name(async () => {
2990
- if (!config.getFileCheckpointingEnabled()) {
2991
- return;
2992
- }
2993
- const restorableToolCalls = toolCalls.filter(
2994
- (toolCall) => EDIT_TOOL_NAMES.has(toolCall.request.name) && toolCall.status === "awaiting_approval" && !toolCall.request.isClientInitiated
2995
- );
2996
- if (restorableToolCalls.length > 0) {
2997
- const checkpointDir = storage.getProjectTempCheckpointsDir();
2998
- if (!checkpointDir) {
2999
- return;
3000
- }
3001
- try {
3002
- await fs2.mkdir(checkpointDir, { recursive: true });
3003
- } catch (error) {
3004
- if (!isNodeError(error) || error.code !== "EEXIST") {
3005
- onDebugMessage(
3006
- `Failed to create checkpoint directory: ${getErrorMessage(error)}`
3007
- );
3008
- return;
3009
- }
3010
- }
3011
- for (const toolCall of restorableToolCalls) {
3012
- const filePath = toolCall.request.args["file_path"] ?? toolCall.request.args["notebook_path"];
3013
- if (!filePath) {
3014
- onDebugMessage(
3015
- `Skipping restorable tool call due to missing file_path: ${toolCall.request.name}`
3016
- );
3017
- continue;
3018
- }
3019
- try {
3020
- const promptId = toolCall.request.prompt_id;
3021
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-").replace(/\./g, "_");
3022
- const toolName = toolCall.request.name;
3023
- const fileName = path3.basename(filePath);
3024
- const toolCallWithSnapshotFileName = `${timestamp}-${fileName}-${toolName}.json`;
3025
- const clientHistory = geminiClient?.getHistoryShallow();
3026
- const toolCallWithSnapshotFilePath = path3.join(
3027
- checkpointDir,
3028
- toolCallWithSnapshotFileName
3029
- );
3030
- await fs2.writeFile(
3031
- toolCallWithSnapshotFilePath,
3032
- JSON.stringify(
3033
- {
3034
- history,
3035
- clientHistory,
3036
- toolCall: {
3037
- name: toolCall.request.name,
3038
- args: toolCall.request.args
3039
- },
3040
- promptId,
3041
- filePath
3042
- },
3043
- null,
3044
- 2
3045
- )
3046
- );
3047
- } catch (error) {
3048
- onDebugMessage(
3049
- `Failed to create checkpoint for ${filePath}: ${getErrorMessage(
3050
- error
3051
- )}. This may indicate a problem with file system permissions.`
3052
- );
3053
- }
3054
- }
3055
- }
3056
- }, "saveRestorableToolCalls");
3057
- saveRestorableToolCalls();
3058
- }, [toolCalls, config, onDebugMessage, history, geminiClient, storage]);
3059
- const notificationQueueRef = (0, import_react5.useRef)([]);
3060
- const [notificationTrigger, setNotificationTrigger] = (0, import_react5.useState)(0);
3061
- const getAutonomousLoopTickResolver = (0, import_react5.useCallback)(() => {
3062
- autonomousLoopTickResolverRef.current ??= new AutonomousLoopTickResolver();
3063
- return autonomousLoopTickResolverRef.current;
3064
- }, []);
3065
- const notificationQueueSessionIdRef = (0, import_react5.useRef)(sessionStates.sessionId);
3066
- (0, import_react5.useEffect)(() => {
3067
- if (notificationQueueSessionIdRef.current === sessionStates.sessionId) {
3068
- return;
3069
- }
3070
- notificationQueueSessionIdRef.current = sessionStates.sessionId;
3071
- notificationQueueRef.current = [];
3072
- autonomousLoopTickResolverRef.current?.resetCache();
3073
- }, [sessionStates.sessionId]);
3074
- const cronSessionIdRef = (0, import_react5.useRef)(sessionStates.sessionId);
3075
- cronSessionIdRef.current = sessionStates.sessionId;
3076
- (0, import_react5.useEffect)(() => {
3077
- if (!isConfigInitialized) return;
3078
- if (!config.isCronEnabled()) return;
3079
- const scheduler = config.getCronScheduler();
3080
- let stopped = false;
3081
- void (async () => {
3082
- try {
3083
- await scheduler.enableDurable(cronSessionIdRef.current);
3084
- } catch (err) {
3085
- debugLogger3.warn(
3086
- `Durable cron init failed \u2014 persistent tasks will not fire in this session: ${err}`
3087
- );
3088
- }
3089
- if (stopped) return;
3090
- scheduler.start(
3091
- (job) => {
3092
- const source = job.cronExpr === "@wakeup" ? "Loop" : "Cron";
3093
- const autonomousMode = detectAutonomousSentinel(job.prompt);
3094
- let label = job.prompt.slice(0, 40);
3095
- let modelText = job.prompt;
3096
- if (autonomousMode) {
3097
- if (job.missed) return;
3098
- const resolver = getAutonomousLoopTickResolver();
3099
- const tick = resolver.resolveAutonomous(autonomousMode);
3100
- label = "Autonomous loop tick";
3101
- modelText = tick.modelText;
3102
- notificationQueueRef.current.push({
3103
- displayText: `${job.missed ? "Missed" : source}: ${label}`,
3104
- modelText,
3105
- sendMessageType: "cron" /* Cron */,
3106
- onDelivered: /* @__PURE__ */ __name(() => resolver.markDelivered(), "onDelivered")
3107
- });
3108
- setNotificationTrigger((n) => n + 1);
3109
- return;
3110
- }
3111
- notificationQueueRef.current.push({
3112
- displayText: `${job.missed ? "Missed" : source}: ${label}`,
3113
- modelText,
3114
- sendMessageType: "cron" /* Cron */
3115
- });
3116
- setNotificationTrigger((n) => n + 1);
3117
- }
3118
- );
3119
- })();
3120
- return () => {
3121
- stopped = true;
3122
- const summary = scheduler.getExitSummary();
3123
- scheduler.stop();
3124
- if (summary) {
3125
- process.stderr.write(summary + "\n");
3126
- }
3127
- };
3128
- }, [config, getAutonomousLoopTickResolver, isConfigInitialized]);
3129
- (0, import_react5.useEffect)(() => {
3130
- const registry = config.getBackgroundTaskRegistry();
3131
- registry.setNotificationCallback((displayText, modelText) => {
3132
- notificationQueueRef.current.push({
3133
- displayText,
3134
- modelText,
3135
- sendMessageType: "notification" /* Notification */
3136
- });
3137
- setNotificationTrigger((n) => n + 1);
3138
- });
3139
- return () => {
3140
- registry.setNotificationCallback(void 0);
3141
- };
3142
- }, [config]);
3143
- (0, import_react5.useEffect)(() => {
3144
- const registry = config.getBackgroundShellRegistry();
3145
- registry.setNotificationCallback((displayText, modelText) => {
3146
- notificationQueueRef.current.push({
3147
- displayText,
3148
- modelText,
3149
- sendMessageType: "notification" /* Notification */
3150
- });
3151
- setNotificationTrigger((n) => n + 1);
3152
- });
3153
- return () => {
3154
- registry.setNotificationCallback(void 0);
3155
- };
3156
- }, [config]);
3157
- (0, import_react5.useEffect)(() => {
3158
- const registry = config.getMonitorRegistry();
3159
- registry.setNotificationCallback((displayText, modelText, meta) => {
3160
- if (meta.status === "running" && typeof registry.get === "function") {
3161
- const entry = registry.get(meta.monitorId);
3162
- if (!entry || entry.status !== "running") return;
3163
- }
3164
- notificationQueueRef.current.push({
3165
- displayText,
3166
- modelText,
3167
- sendMessageType: "notification" /* Notification */
3168
- });
3169
- setNotificationTrigger((n) => n + 1);
3170
- });
3171
- return () => {
3172
- registry.setNotificationCallback(void 0);
3173
- };
3174
- }, [config]);
3175
- (0, import_react5.useEffect)(() => {
3176
- if (streamingState === "idle" /* Idle */ && !isSubmittingQueryRef.current && notificationQueueRef.current.length > 0) {
3177
- const queue = notificationQueueRef.current;
3178
- const targetType = queue[0].sendMessageType;
3179
- if (targetType === "cron" /* Cron */) {
3180
- const item = queue.shift();
3181
- addItem(
3182
- { type: "notification", text: item.displayText },
3183
- Date.now()
3184
- );
3185
- submitQuery(item.modelText, item.sendMessageType, void 0, {
3186
- notificationDisplayText: item.displayText,
3187
- onDelivered: item.onDelivered,
3188
- onDeliveryFailed: item.onDeliveryFailed
3189
- });
3190
- return;
3191
- }
3192
- let splitIdx = 0;
3193
- while (splitIdx < queue.length && queue[splitIdx].sendMessageType === targetType) {
3194
- splitIdx++;
3195
- }
3196
- const batch = queue.splice(0, splitIdx);
3197
- const now = Date.now();
3198
- for (const item of batch) {
3199
- addItem({ type: "notification", text: item.displayText }, now);
3200
- }
3201
- const combinedModelText = batch.map((e) => e.modelText).join("\n\n");
3202
- const combinedDisplayText = batch.map((e) => e.displayText).join("; ");
3203
- submitQuery(combinedModelText, targetType, void 0, {
3204
- notificationDisplayText: combinedDisplayText
3205
- });
3206
- }
3207
- }, [streamingState, submitQuery, notificationTrigger, addItem]);
3208
- const teammateQueueRef = (0, import_react5.useRef)([]);
3209
- const [teammateTrigger, setTeammateTrigger] = (0, import_react5.useState)(0);
3210
- (0, import_react5.useEffect)(() => {
3211
- let boundManager = null;
3212
- const handleManagerChange = /* @__PURE__ */ __name((manager) => {
3213
- if (boundManager && boundManager !== manager) {
3214
- boundManager.setLeaderMessageCallback(null);
3215
- teammateQueueRef.current.length = 0;
3216
- }
3217
- boundManager = manager;
3218
- if (manager) {
3219
- manager.setLeaderMessageCallback(
3220
- (modelText, display) => {
3221
- teammateQueueRef.current.push({ modelText, display });
3222
- setTeammateTrigger((n) => n + 1);
3223
- }
3224
- );
3225
- }
3226
- }, "handleManagerChange");
3227
- config.onTeamManagerChange(handleManagerChange);
3228
- const current = config.getTeamManager();
3229
- if (current) {
3230
- handleManagerChange(current);
3231
- }
3232
- return () => {
3233
- config.onTeamManagerChange(null, handleManagerChange);
3234
- if (boundManager) {
3235
- boundManager.setLeaderMessageCallback(null);
3236
- boundManager = null;
3237
- }
3238
- };
3239
- }, [config]);
3240
- (0, import_react5.useEffect)(() => {
3241
- if (streamingState === "idle" /* Idle */ && !isSubmittingQueryRef.current && teammateQueueRef.current.length > 0) {
3242
- const batch = teammateQueueRef.current.splice(0);
3243
- for (const entry of batch) {
3244
- addItem(
3245
- { type: "notification", text: entry.display },
3246
- Date.now()
3247
- );
3248
- }
3249
- const modelText = batch.map((e) => e.modelText).join("\n\n");
3250
- const display = batch.map((e) => e.display).join("; ");
3251
- submitQuery(modelText, "teammate" /* Teammate */, void 0, {
3252
- notificationDisplayText: display
3253
- });
3254
- }
3255
- }, [streamingState, submitQuery, teammateTrigger, addItem]);
3256
- return {
3257
- streamingState,
3258
- submitQuery,
3259
- initError,
3260
- pendingHistoryItems,
3261
- thought,
3262
- cancelOngoingRequest,
3263
- retryLastPrompt,
3264
- pendingToolCalls: toolCalls,
3265
- handleApprovalModeChange,
3266
- activePtyId,
3267
- loopDetectionConfirmationRequest,
3268
- streamingResponseLengthRef,
3269
- isReceivingContent
3270
- };
3271
- }, "useGeminiStream");
3272
-
3273
- export {
3274
- DualOutputContext,
3275
- useDualOutput,
3276
- classifyApiError,
3277
- useGeminiStream
3278
- };
3279
- /**
3280
- * @license
3281
- * Copyright 2025 Qwen Team
3282
- * SPDX-License-Identifier: Apache-2.0
3283
- */
3284
- /**
3285
- * @license
3286
- * Copyright 2025 Google LLC
3287
- * SPDX-License-Identifier: Apache-2.0
3288
- */