@qwen-code/qwen-code 0.19.11 → 0.19.12-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/batch/SKILL.md +6 -0
- package/bundled/qc-helper/docs/configuration/model-providers.md +11 -0
- package/bundled/qc-helper/docs/configuration/settings.md +11 -10
- package/bundled/qc-helper/docs/features/channels/overview.md +66 -11
- package/bundled/qc-helper/docs/features/sub-agents.md +8 -8
- package/bundled/qc-helper/docs/features/worktree.md +2 -2
- package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +42 -7
- package/bundled/qc-helper/docs/qwen-serve.md +102 -40
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +1 -1
- package/bundled/review/SKILL.md +60 -49
- package/bundled/simplify/SKILL.md +1 -1
- package/chunks/{MaxSizedBox-L6TGYDM3.js → MaxSizedBox-3KIWAU6Z.js} +31 -32
- package/chunks/{StandaloneSessionPicker-AKEQHU5P.js → StandaloneSessionPicker-TF626NO7.js} +45 -46
- package/chunks/acp-startup-profiler-N3RHHXJ3.js +25 -0
- package/chunks/{acpAgent-PTNBGJDN.js → acpAgent-JDVJXVBO.js} +1863 -507
- package/chunks/{agent-AJOMOZPJ.js → agent-BONWC4VY.js} +26 -27
- package/chunks/{agent-headless-CYKOMAXS.js → agent-headless-H7HKMGLZ.js} +26 -27
- package/chunks/{anthropicContentGenerator-HBRXJSP4.js → anthropicContentGenerator-ZZRGFEES.js} +35 -12
- package/chunks/{artifact-tool-MIZLXBLF.js → artifact-tool-PHO5XEGZ.js} +5 -5
- package/chunks/{askUserQuestion-XMJVPNWM.js → askUserQuestion-CEPBT47X.js} +2 -47
- package/chunks/{bridge-QKISWPCI.js → bridge-ATN2TLWJ.js} +31 -32
- package/chunks/{ca-CODEN7TD.js → ca-2SL2BXTK.js} +3 -2
- package/chunks/{channel-worker-group-SOUWTFHC.js → channel-worker-group-S3H5QHTI.js} +4 -4
- package/chunks/{channel-worker-manager-LOVSV3WW.js → channel-worker-manager-ZJ4HTMO2.js} +4 -4
- package/chunks/{channel-worker-supervisor-XW6MHJBQ.js → channel-worker-supervisor-JA6VZ5V5.js} +3 -3
- package/chunks/{chunk-ZIXOTAPZ.js → chunk-2DZ7E27L.js} +92 -3
- package/chunks/{chunk-L5U3ELZX.js → chunk-335ECZTA.js} +1 -1
- package/chunks/{chunk-2FO5GFKZ.js → chunk-3DJY4IFO.js} +1 -1
- package/chunks/{chunk-4AGTGMCQ.js → chunk-3PE7OY2G.js} +12 -12
- package/chunks/{chunk-QOTQH4CB.js → chunk-4AGBO6RB.js} +27 -10
- package/chunks/{chunk-Y66VOBRP.js → chunk-4CA4WUMS.js} +2 -2
- package/chunks/{chunk-LQIDP6K5.js → chunk-4CHDYDG3.js} +1 -1
- package/chunks/{chunk-574PTLMU.js → chunk-4OVECYBM.js} +407 -92
- package/chunks/{chunk-TV6K2FB4.js → chunk-4RPARQ5D.js} +2 -2
- package/chunks/{chunk-TL4R5TRK.js → chunk-4W55BHOC.js} +2 -2
- package/chunks/{chunk-RCEEXIOO.js → chunk-4XCVGEEX.js} +3 -3
- package/chunks/{chunk-3DWIFU7L.js → chunk-53UMEONK.js} +1 -1
- package/chunks/{chunk-AU3MFJPL.js → chunk-54KPEDM2.js} +8 -8
- package/chunks/{chunk-T76DGHGG.js → chunk-66F4IJ4L.js} +5 -5
- package/chunks/{chunk-YLSSEUAM.js → chunk-675SVDMD.js} +354 -278
- package/chunks/{chunk-NVTQZXR7.js → chunk-6QGZVKOO.js} +91 -52
- package/chunks/{chunk-NJOFRXTM.js → chunk-6TDA4EVC.js} +4200 -3450
- package/chunks/{chunk-BYH2JRK3.js → chunk-6WZZHJSZ.js} +5 -5
- package/chunks/{chunk-7X7TEQNX.js → chunk-76BFY7AF.js} +13 -0
- package/chunks/chunk-7KS72E2N.js +883 -0
- package/chunks/{chunk-CF5VJRGC.js → chunk-7LMAKIWE.js} +1 -1
- package/chunks/{chunk-WMNXXRGL.js → chunk-7O7WZH7N.js} +31 -31
- package/chunks/{chunk-7ZYHLN67.js → chunk-7OZGMFHC.js} +26 -75
- package/chunks/{chunk-6WPJRYLZ.js → chunk-7SX6WZNO.js} +3 -3
- package/chunks/{chunk-JGUT3LWZ.js → chunk-ANRANWVE.js} +4 -1
- package/chunks/{chunk-JD44PNGJ.js → chunk-AWOU24F6.js} +10 -5
- package/chunks/{chunk-6WGZDD67.js → chunk-BEFQGC6H.js} +2 -2
- package/chunks/{chunk-KXYJPRT5.js → chunk-BEZPRKD3.js} +28 -6
- package/chunks/{chunk-FYQ22K62.js → chunk-CHVH4DVN.js} +6 -5
- package/chunks/{chunk-LS56TX3M.js → chunk-CMHJEUVB.js} +1 -1
- package/chunks/{chunk-FXKOAEXP.js → chunk-CXWUXRD5.js} +14 -14
- package/chunks/{chunk-CAHY5ABC.js → chunk-DULSE2SH.js} +1 -1
- package/chunks/{chunk-SQ5BK3GO.js → chunk-DYUPBU7H.js} +1 -1
- package/chunks/{chunk-FNX3LGAK.js → chunk-E655RDRL.js} +1 -1
- package/chunks/{chunk-N5VIZTND.js → chunk-EWPLL4OT.js} +1 -1
- package/chunks/{chunk-FSA7ERJ2.js → chunk-F2RR4HO2.js} +1 -1
- package/chunks/{chunk-S63Z5V42.js → chunk-F2YCCUXI.js} +4 -4
- package/chunks/{chunk-3AYLDB6B.js → chunk-FEZXQXW2.js} +1 -1
- package/chunks/{chunk-OWT2CAEQ.js → chunk-GEHSF7MS.js} +105 -12
- package/chunks/{chunk-LXLTBIDP.js → chunk-HCCR43AY.js} +1 -1
- package/chunks/{chunk-7NMU22Q3.js → chunk-HQ7MDVBO.js} +18 -7
- package/chunks/{chunk-KSZKSE23.js → chunk-HVWPSGDY.js} +1 -1
- package/chunks/{chunk-YFVO2HOR.js → chunk-HZXU6YZW.js} +5 -5
- package/chunks/{chunk-HASK4LMI.js → chunk-IKLWU6YS.js} +13 -6
- package/chunks/{chunk-GNBBAQ6J.js → chunk-ILQ42UG6.js} +111 -40
- package/chunks/{chunk-THXDQSTA.js → chunk-IQRQVPGN.js} +49 -154
- package/chunks/{chunk-SPJQO2CE.js → chunk-J2MKYJKZ.js} +2 -2
- package/chunks/{chunk-SUARMD4Q.js → chunk-J6NT5YTN.js} +28 -2
- package/chunks/{chunk-TYLOFD2U.js → chunk-JCJPZMJV.js} +1 -1
- package/chunks/{chunk-BYB3GF2T.js → chunk-JCYMQU5F.js} +133 -6
- package/chunks/{chunk-6EDDYPI3.js → chunk-JUNVFQVY.js} +4 -4
- package/chunks/{chunk-CH2XVB47.js → chunk-K7P34F2J.js} +3 -3
- package/chunks/{chunk-5VWYKIMW.js → chunk-KANTXY7B.js} +2 -2
- package/chunks/{chunk-K7VD4XLT.js → chunk-LHEQDKAR.js} +1 -1
- package/chunks/{chunk-A2HWMJVO.js → chunk-LKR7QQ63.js} +3 -3
- package/chunks/{chunk-4HUDDSO5.js → chunk-LLIGYAQU.js} +4 -4
- package/chunks/{chunk-5Z452MMD.js → chunk-LODZMRXC.js} +154 -83
- package/chunks/{chunk-FBU7WRZI.js → chunk-LPHGXXZX.js} +6 -1
- package/chunks/{chunk-CPFIQVZJ.js → chunk-LYFDJTXE.js} +1 -1
- package/chunks/{chunk-TIOE2OPE.js → chunk-MCYZTKBV.js} +2 -2
- package/chunks/{chunk-ZQIYGQCG.js → chunk-MHEZV3OY.js} +506 -143
- package/chunks/{chunk-JWICTOXS.js → chunk-NGTQA57Y.js} +2 -2
- package/chunks/{chunk-5CNYZ7TN.js → chunk-NJQPQ4IO.js} +7 -7
- package/chunks/chunk-NSZJQACR.js +45 -0
- package/chunks/{chunk-DOPUYNXO.js → chunk-NUHSLBJZ.js} +7 -7
- package/chunks/{chunk-CITWNIXJ.js → chunk-NVUGS23Y.js} +5 -5
- package/chunks/{chunk-2Z5UX4KI.js → chunk-OSSDHJDU.js} +1 -1
- package/chunks/{chunk-YUZI3WAC.js → chunk-OWAK7LMW.js} +7 -0
- package/chunks/{chunk-Y3KFTWVX.js → chunk-OZWJAFFE.js} +6 -6
- package/chunks/{chunk-YGYSMY2R.js → chunk-PSISZNIT.js} +1629 -1142
- package/chunks/{chunk-4ROQY23C.js → chunk-PTXVHS2O.js} +7 -7
- package/chunks/{chunk-OKAIGAYW.js → chunk-QGONRHUS.js} +3 -3
- package/chunks/{chunk-PZL23GTM.js → chunk-QR6U5QPP.js} +8 -0
- package/chunks/chunk-QSG4ZFG4.js +257 -0
- package/chunks/{chunk-BXBDC476.js → chunk-R32BTEZY.js} +5 -5
- package/chunks/{chunk-AVEOWVOM.js → chunk-R3VWUU2E.js} +1 -1
- package/chunks/{chunk-RP5R7MB6.js → chunk-R4RIMOJL.js} +12 -12
- package/chunks/{chunk-ARKANCNX.js → chunk-SGPFJMRP.js} +1 -1
- package/chunks/{chunk-3M75MSVA.js → chunk-SMASS3CY.js} +1 -1
- package/chunks/{chunk-4IJMTYCB.js → chunk-SNONG66P.js} +818 -29
- package/chunks/chunk-TDKQP3M6.js +201 -0
- package/chunks/{chunk-VFX7EZIR.js → chunk-TFV3XVAZ.js} +8 -1
- package/chunks/{chunk-4LD5APFL.js → chunk-TYQMGACW.js} +1 -0
- package/chunks/{chunk-7NFB7LBQ.js → chunk-UE5TZ55T.js} +8 -0
- package/chunks/{chunk-F333XEAU.js → chunk-UOA2IHRI.js} +4 -3
- package/chunks/{chunk-VRR65QYW.js → chunk-V4PCIS25.js} +5 -1
- package/chunks/{chunk-WIEO4CWB.js → chunk-VAJS2E2D.js} +1 -1
- package/chunks/{chunk-GLNHPRZT.js → chunk-W4DFAUAO.js} +1 -1
- package/chunks/{chunk-STZQCNN3.js → chunk-W7H223ZZ.js} +1 -1
- package/chunks/{chunk-6Y6ORE2G.js → chunk-WACI4VES.js} +288 -20
- package/chunks/{chunk-WTNZ6DXB.js → chunk-WEPXQKGP.js} +1 -1
- package/chunks/{chunk-4BJVSIS3.js → chunk-WHQNBBWW.js} +2 -2
- package/chunks/{chunk-QDJ2R4CM.js → chunk-WTHRMVKB.js} +3 -3
- package/chunks/{chunk-L4Y55KIS.js → chunk-X6YQWCIJ.js} +1 -1
- package/chunks/{chunk-Q6TUALBE.js → chunk-XAAEDML2.js} +1 -1
- package/chunks/{chunk-BUAXJVNP.js → chunk-XACBIZJB.js} +3 -3
- package/chunks/{chunk-2OG646IN.js → chunk-XFJU7SVP.js} +4 -4
- package/chunks/{chunk-KKRTYONM.js → chunk-XSPFQQRE.js} +3 -3
- package/chunks/{chunk-V2DXTLUE.js → chunk-Y5UDBQYF.js} +3 -3
- package/chunks/{chunk-MQOVXZAF.js → chunk-YN2I5I42.js} +529 -61
- package/chunks/{chunk-FMNYGWOD.js → chunk-Z4ZCVYJ5.js} +14 -8
- package/chunks/{chunk-SY7NEYX4.js → chunk-ZFHHBRRA.js} +2 -2
- package/chunks/{chunk-QYG4BY6Q.js → chunk-ZPVGEMVC.js} +1 -1
- package/chunks/{computer-use-VZZMJEQ7.js → computer-use-UY4A72X7.js} +26 -27
- package/chunks/{config-utils-IQQT3GCI.js → config-utils-KWTRFP7D.js} +3 -3
- package/chunks/{contextCommand-PORKIZSY.js → contextCommand-3DZ2SVH6.js} +30 -31
- package/chunks/{create-sub-session-EAB2U5XW.js → create-sub-session-DIJOV6HV.js} +2 -2
- package/chunks/{create-sub-session-XVFKHAFW.js → create-sub-session-OT7WXLDO.js} +27 -28
- package/chunks/{cron-create-GMVKSXZT.js → cron-create-X462ERYA.js} +4 -4
- package/chunks/{cron-delete-VDZKUAVK.js → cron-delete-SL5UJUM3.js} +4 -4
- package/chunks/{cron-list-UG7C7RAR.js → cron-list-3MD6SVXI.js} +4 -4
- package/chunks/{daemon-IHR6WSPB.js → daemon-ZW6LHOXT.js} +91 -14
- package/chunks/{daemon-status-provider-ABLBA3UJ.js → daemon-status-provider-GTZOYSBO.js} +35 -36
- package/chunks/{de-NOXPCSYN.js → de-I7ZIYXZC.js} +3 -2
- package/chunks/{dist-PX2ERZ6I.js → dist-HCUUS6IH.js} +2 -2
- package/chunks/{dist-VYWUKURL.js → dist-O2IP3G5D.js} +1 -1
- package/chunks/{dist-GXJVCOS7.js → dist-RZBJT5O2.js} +2 -1
- package/chunks/{dist-V2YVLYOW.js → dist-Y54RURGT.js} +3 -1
- package/chunks/{dist-DOPL5LSQ.js → dist-YTPTCUAD.js} +1 -1
- package/chunks/{dist-4WCQEZIN.js → dist-ZJHKKWUD.js} +1 -1
- package/chunks/{earlyInputCapture-DJCU5SPU.js → earlyInputCapture-GGWVGBZ7.js} +27 -28
- package/chunks/{edit-O4VV5AO6.js → edit-JN467GIR.js} +27 -28
- package/chunks/{en-JFVULHTB.js → en-XE34GKAA.js} +7 -3
- package/chunks/{enter-worktree-XQYDDI2I.js → enter-worktree-MMO4VBQE.js} +26 -27
- package/chunks/{enterPlanMode-CESVMQBV.js → enterPlanMode-BRZOG4DB.js} +27 -30
- package/chunks/{environment-5KXOLZNR.js → environment-LOCDCWMZ.js} +29 -30
- package/chunks/{errors-EBUTCBAQ.js → errors-XXSL5HGG.js} +29 -30
- package/chunks/{exit-worktree-MWGNSPNX.js → exit-worktree-UD7PI5H5.js} +26 -27
- package/chunks/exitPlanMode-EIUETQI6.js +389 -0
- package/chunks/{fast-path-6V73F2T2.js → fast-path-ULGAEUVK.js} +2 -2
- package/chunks/{fr-HVFNU42H.js → fr-X7KDVZIY.js} +3 -2
- package/chunks/{gemini-TEFJZCIZ.js → gemini-KW3APZ4P.js} +133 -80
- package/chunks/{geminiContentGenerator-M56BEXWI.js → geminiContentGenerator-4BQ5QHPR.js} +5 -5
- package/chunks/{glob-DMYFEEAZ.js → glob-FPKAMR6B.js} +32 -28
- package/chunks/{grep-GYE47MD4.js → grep-MOGRCYB4.js} +32 -28
- package/chunks/{handleAutoUpdate-OLUY4L7L.js → handleAutoUpdate-QUMRZZOS.js} +33 -34
- package/chunks/{i18n-462JC7IY.js → i18n-F3W6YUYP.js} +28 -29
- package/chunks/{initializer-Y7WD4D2I.js → initializer-KLU2KAIZ.js} +33 -34
- package/chunks/{installationInfo-I2Z3BKCE.js → installationInfo-P3ZP2SIZ.js} +27 -28
- package/chunks/{ja-PY5AF544.js → ja-2ICT3KXF.js} +3 -2
- package/chunks/{keychain-token-storage-AU22CQI6.js → keychain-token-storage-K23CFKGN.js} +2 -2
- package/chunks/{list-XQ5MSAXP.js → list-4X6D5JD2.js} +35 -36
- package/chunks/{loadedSettingsAdapter-TQOWYE7C.js → loadedSettingsAdapter-446B6WKA.js} +32 -33
- package/chunks/{loop-wakeup-QXWZSCYM.js → loop-wakeup-6H7OENTB.js} +5 -5
- package/chunks/{ls-2OUTG3IZ.js → ls-APTSOOS5.js} +4 -4
- package/chunks/{lsp-4VMNXZW6.js → lsp-HPACPJAN.js} +2 -2
- package/chunks/{mcp-22LLEEVM.js → mcp-JYVOJZOD.js} +32 -33
- package/chunks/{monitor-VKG324X3.js → monitor-KY7YH7TL.js} +26 -27
- package/chunks/nonInteractiveCli-EK35TLVJ.js +129 -0
- package/chunks/{notebook-edit-FJJRBQ3S.js → notebook-edit-IHGW42QK.js} +27 -28
- package/chunks/{openaiContentGenerator-4T2OGTR5.js → openaiContentGenerator-FURUCKQJ.js} +13 -14
- package/chunks/{pidfile-XL3MDCBM.js → pidfile-WKUVXDMR.js} +27 -28
- package/chunks/{processUtils-7UCFN34D.js → processUtils-LHSRN76X.js} +2 -2
- package/chunks/{pt-A3PRQXMU.js → pt-JJ4XPIBP.js} +3 -2
- package/chunks/{qwenContentGenerator-PQUXJDIZ.js → qwenContentGenerator-NRLM7R36.js} +30 -31
- package/chunks/{qwenOAuth2-LEYOU7RU.js → qwenOAuth2-5FNX3AWH.js} +22 -5
- package/chunks/{read-file-3EYQML7E.js → read-file-VLEAEXFP.js} +9 -10
- package/chunks/{read-mcp-resource-JUFHCKSC.js → read-mcp-resource-C6NT52T6.js} +2 -2
- package/chunks/{record-artifact-DWSMBXYY.js → record-artifact-ENCU7QCL.js} +2 -2
- package/chunks/{ripGrep-S6WPGQNA.js → ripGrep-MT23EIDD.js} +26 -27
- package/chunks/{ru-IBCWUTOC.js → ru-STR4KTW7.js} +3 -2
- package/chunks/{run-qwen-serve-NSKBT3HU.js → run-qwen-serve-5HWOQFLI.js} +63 -47
- package/chunks/{runtime-LG5ZZ3VH.js → runtime-6IVKJSLW.js} +38 -37
- package/chunks/{scheduler-PLX3VVTB.js → scheduler-63GJG75U.js} +26 -27
- package/chunks/{send-message-JZ752NWD.js → send-message-5GZ4FX2V.js} +3 -3
- package/chunks/{serve-S2ZLRZZR.js → serve-3LL7RRDP.js} +32 -33
- package/chunks/{server-5ECMV4TM.js → server-AA24QLPA.js} +1672 -615
- package/chunks/{session-ILSONWG4.js → session-LRVCFQQQ.js} +102 -75
- package/chunks/{settings-BOE7WWSA.js → settings-ZX3OKUT4.js} +36 -37
- package/chunks/{shell-VW664JIZ.js → shell-KR3IMYH6.js} +26 -27
- package/chunks/{skill-COHV6625.js → skill-QLM2LSF7.js} +11 -12
- package/chunks/{spawnChannel-5UUR5XOZ.js → spawnChannel-6WFOK3SA.js} +28 -29
- package/chunks/{src-XPKFZ3RN.js → src-ADLNIPHD.js} +101 -72
- package/chunks/{standalone-update-IOOJ2NZQ.js → standalone-update-C54OTJWJ.js} +29 -30
- package/chunks/{startInteractiveUI-3NGJGXXS.js → startInteractiveUI-KFAOS6HC.js} +2342 -1796
- package/chunks/{stdioHelpers-UMY72QRP.js → stdioHelpers-HGIYTWAY.js} +3 -1
- package/chunks/{syntheticOutput-LELY6HAI.js → syntheticOutput-ULOVVLY4.js} +3 -3
- package/chunks/{task-create-QY3BIMNM.js → task-create-DUE2PMNI.js} +7 -7
- package/chunks/{task-list-D2U47WBJ.js → task-list-WVPNX7BZ.js} +5 -5
- package/chunks/{task-stop-N6E5IYLH.js → task-stop-CPEQWOT6.js} +2 -2
- package/chunks/{task-update-HJCQILLB.js → task-update-HY2LNFFB.js} +7 -7
- package/chunks/{team-create-UPLVZQFX.js → team-create-Q5B5M7UD.js} +26 -27
- package/chunks/{team-delete-RCWYDRF4.js → team-delete-JJV6IUOA.js} +5 -5
- package/chunks/{team-plan-approval-F5F432RO.js → team-plan-approval-J55PXNY2.js} +26 -27
- package/chunks/{theme-manager-JJE4BJ67.js → theme-manager-QWTDRPHV.js} +27 -28
- package/chunks/todoWrite-JHHIDOIV.js +358 -0
- package/chunks/{tool-search-LRXI4JLZ.js → tool-search-LSSKWZKH.js} +10 -11
- package/chunks/{total-session-admission-I4DHN6UP.js → total-session-admission-S6ATY5HY.js} +32 -33
- package/chunks/{trustedFolders-SEH7LNX2.js → trustedFolders-CY4TUPDJ.js} +28 -29
- package/chunks/turndown.cjs-FZHGMUTY.js +17670 -0
- package/chunks/{update-relaunch-T6ZKBUA6.js → update-relaunch-IOKOUV3K.js} +6 -6
- package/chunks/{updateCheck-FWLXZPRO.js → updateCheck-YNRFE4V7.js} +30 -31
- package/chunks/{validateNonInterActiveAuth-X6K2VWYT.js → validateNonInterActiveAuth-OXTECS4B.js} +68 -68
- package/chunks/{version-LIFSOGSE.js → version-2CZQQDL5.js} +1 -1
- package/chunks/web-fetch-7QTEGJI5.js +938 -0
- package/chunks/{workflow-NX2DFWGD.js → workflow-G3CZU256.js} +29 -30
- package/chunks/{workspace-providers-status-VYD6M2NE.js → workspace-providers-status-UHQOIPAZ.js} +35 -36
- package/chunks/{workspace-registration-store-2Y6PWOEL.js → workspace-registration-store-5WPCMX4F.js} +1 -1
- package/chunks/{workspace-registry-PKBDBWCA.js → workspace-registry-LAQCRQTH.js} +32 -33
- package/chunks/{workspace-service-HHORUHTS.js → workspace-service-6ZEUJY2Z.js} +38 -39
- package/chunks/{workspace-skills-status-O5Q26LIY.js → workspace-skills-status-YG6OITSM.js} +33 -34
- package/chunks/{write-file-NVAEZ3J2.js → write-file-E7T3PU3B.js} +60 -28
- package/chunks/{zh-PAUNIMHQ.js → zh-6ANG2HTL.js} +7 -3
- package/chunks/{zh-TW-GNEUIUFF.js → zh-TW-4RR3YHNN.js} +7 -3
- package/cli-entry.js +37 -2
- package/cli.js +17 -11
- package/locales/ca.js +3 -2
- package/locales/de.js +3 -2
- package/locales/en.js +10 -5
- package/locales/fr.js +3 -2
- package/locales/ja.js +3 -2
- package/locales/pt.js +3 -2
- package/locales/ru.js +3 -2
- package/locales/zh-TW.js +9 -3
- package/locales/zh.js +9 -3
- package/package.json +3 -3
- package/web-shell/assets/{arc-H74fE8UR.js → arc-_dVIKMdB.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-DN3kEq-I.js → architectureDiagram-3BPJPVTR-MuN3nKpL.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-BrqbsFUF.js → blockDiagram-GPEHLZMM-BtmvJjzx.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-ClFhU1P-.js → c4Diagram-AAUBKEIU-Dvi58_BU.js} +1 -1
- package/web-shell/assets/channel-Bi5TehaT.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-jCIcG0_M.js → chunk-2J33WTMH-YqxOVhS1.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-DSkGe62-.js → chunk-4BX2VUAB-DoBgbC9z.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-BxBHOGTd.js → chunk-55IACEB6-3NEQrBAr.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-v_DS7dH7.js → chunk-727SXJPM-DrCZQxp0.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-1RzEKRPq.js → chunk-AQP2D5EJ-m_g3zjgv.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-DyrSbLOX.js → chunk-FMBD7UC4-D1_crABJ.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-BCmdsZiy.js → chunk-ND2GUHAM-BdhgVtBx.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-CphHGW2D.js → chunk-QZHKN3VN-BlmThhm-.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BKhhRdd1.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BKhhRdd1.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-D5kRC7Fi.js → cose-bilkent-S5V4N54A-Cbjm_00Z.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-DIiyJJ0U.js → dagre-BM42HDAG-C39QNVgC.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-BOcuB8xU.js → diagram-2AECGRRQ-DNXSAixC.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-CMgiZ4d3.js → diagram-5GNKFQAL-BCbGUPEA.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-Ctx8pfN0.js → diagram-KO2AKTUF-1eujKSDC.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-BT5REAWC.js → diagram-LMA3HP47-DUMKXgql.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-CJkUqXcp.js → diagram-OG6HWLK6-BFktU3_u.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-DyvNNX6v.js → erDiagram-TEJ5UH35-BvJC7DLk.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-VBf8_My8.js → flowDiagram-I6XJVG4X-Cgu3PlOt.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-CviJnR7B.js → ganttDiagram-6RSMTGT7-DLNXN5Xh.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-BY66_Oze.js → gitGraphDiagram-PVQCEYII-BQFRDv6R.js} +1 -1
- package/web-shell/assets/index-C_ouplMQ.js +1187 -0
- package/web-shell/assets/{index-DhYuvi3j.js → index-CdC3pjP3.js} +1 -1
- package/web-shell/assets/index-XGDFJE-X.css +5 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-D2jaewWZ.js → infoDiagram-5YYISTIA-DT2mOSvp.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-BpnNTyi5.js → ishikawaDiagram-YF4QCWOH-9fy_K4bd.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-CA55GNZF.js → journeyDiagram-JHISSGLW-CoGSEuhE.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-DyiSl_Ts.js → kanban-definition-UN3LZRKU-BP9hHYIj.js} +1 -1
- package/web-shell/assets/{linear-B-sN3dkV.js → linear-uIroDsmp.js} +1 -1
- package/web-shell/assets/{mermaid.core-xf9SXDdb.js → mermaid.core-BUwoStsA.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-DXhr2kRk.js → mindmap-definition-RKZ34NQL-DZB-FWim.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-DUXpbfGQ.js → pieDiagram-4H26LBE5-YPptloKl.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-NeDQYeWw.js → quadrantDiagram-W4KKPZXB-dgk3DSzm.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-BSbFRL1A.js → requirementDiagram-4Y6WPE33-BH2En2i9.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-gg27cAaN.js → sankeyDiagram-5OEKKPKP-BB98feeI.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-Bi_1TSs4.js → sequenceDiagram-3UESZ5HK-CunAIGh8.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-CboCCRaf.js → stateDiagram-AJRCARHV-DTJs_-I2.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DrfFMYta.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-DrGpF_jn.js → timeline-definition-PNZ67QCA-Cd4AN7O0.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-DCaJU67x.js → vennDiagram-CIIHVFJN-xIG-rUU9.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-p0QcW1aP.js → wardley-L42UT6IY-D1UyjIcG.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-DiEVxj1W.js → wardleyDiagram-YWT4CUSO-BVM0Mb99.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-iQB8nSlA.js → xychartDiagram-2RQKCTM6-BX31JDSz.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-2HRYPZT5.js +0 -25
- package/chunks/chunk-QAW7PIHT.js +0 -168
- package/chunks/chunk-RTV5TUYB.js +0 -143
- package/chunks/chunk-ZPAHLFZU.js +0 -172
- package/chunks/exitPlanMode-HYQL4XMB.js +0 -909
- package/chunks/nonInteractiveCli-UMYUT643.js +0 -129
- package/chunks/todoWrite-FKCGATPJ.js +0 -531
- package/chunks/web-fetch-CFCWTCAP.js +0 -5673
- package/web-shell/assets/channel-NFC5ADAa.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-DHgwjz3X.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-DHgwjz3X.js +0 -1
- package/web-shell/assets/index-8xIBbHV3.js +0 -1143
- package/web-shell/assets/index-DLyhlZZO.css +0 -5
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CXRqms6P.js +0 -1
|
@@ -0,0 +1,938 @@
|
|
|
1
|
+
// Force strict mode and setup for ESM
|
|
2
|
+
"use strict";
|
|
3
|
+
import {
|
|
4
|
+
fetchWithPolicy,
|
|
5
|
+
isConnectionLevelError,
|
|
6
|
+
isPrivateHost
|
|
7
|
+
} from "./chunk-7KS72E2N.js";
|
|
8
|
+
import {
|
|
9
|
+
MAX_SESSION_BYTES,
|
|
10
|
+
extractPDFText,
|
|
11
|
+
import_lru_cache,
|
|
12
|
+
runSideQuery
|
|
13
|
+
} from "./chunk-YN2I5I42.js";
|
|
14
|
+
import "./chunk-4WKAA4KS.js";
|
|
15
|
+
import "./chunk-CR3C7WXL.js";
|
|
16
|
+
import "./chunk-VGC4I5JJ.js";
|
|
17
|
+
import "./chunk-LPHGXXZX.js";
|
|
18
|
+
import "./chunk-4CA4WUMS.js";
|
|
19
|
+
import "./chunk-VAJS2E2D.js";
|
|
20
|
+
import "./chunk-WEPXQKGP.js";
|
|
21
|
+
import {
|
|
22
|
+
BaseDeclarativeTool,
|
|
23
|
+
BaseToolInvocation,
|
|
24
|
+
ToolDisplayNames,
|
|
25
|
+
ToolNames
|
|
26
|
+
} from "./chunk-ANRANWVE.js";
|
|
27
|
+
import "./chunk-4CHDYDG3.js";
|
|
28
|
+
import "./chunk-V4PCIS25.js";
|
|
29
|
+
import "./chunk-A4UCTEB5.js";
|
|
30
|
+
import "./chunk-XWRJCPHC.js";
|
|
31
|
+
import "./chunk-TYQMGACW.js";
|
|
32
|
+
import "./chunk-TYAMGABM.js";
|
|
33
|
+
import "./chunk-FCMNKVXT.js";
|
|
34
|
+
import {
|
|
35
|
+
createDebugLogger
|
|
36
|
+
} from "./chunk-UE5TZ55T.js";
|
|
37
|
+
import "./chunk-75DOP5OR.js";
|
|
38
|
+
import "./chunk-DMTGGOSA.js";
|
|
39
|
+
import "./chunk-YQ3U5MUC.js";
|
|
40
|
+
import "./chunk-TB6UDU4T.js";
|
|
41
|
+
import {
|
|
42
|
+
init_esbuild_shims
|
|
43
|
+
} from "./chunk-5O2XNYP6.js";
|
|
44
|
+
import {
|
|
45
|
+
__name
|
|
46
|
+
} from "./chunk-J2S4EL5Y.js";
|
|
47
|
+
|
|
48
|
+
// packages/core/src/tools/web-fetch.ts
|
|
49
|
+
init_esbuild_shims();
|
|
50
|
+
|
|
51
|
+
// packages/core/src/utils/binary-content.ts
|
|
52
|
+
init_esbuild_shims();
|
|
53
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
54
|
+
import * as path from "node:path";
|
|
55
|
+
var BINARY_APPLICATION_TYPES = /* @__PURE__ */ new Set([
|
|
56
|
+
"application/pdf",
|
|
57
|
+
"application/zip",
|
|
58
|
+
"application/gzip",
|
|
59
|
+
"application/x-gzip",
|
|
60
|
+
"application/octet-stream",
|
|
61
|
+
"application/msword",
|
|
62
|
+
"application/vnd.ms-excel",
|
|
63
|
+
"application/vnd.ms-powerpoint",
|
|
64
|
+
"application/x-tar",
|
|
65
|
+
"application/x-7z-compressed",
|
|
66
|
+
"application/x-rar-compressed",
|
|
67
|
+
"application/vnd.rar",
|
|
68
|
+
"application/wasm",
|
|
69
|
+
"application/java-archive"
|
|
70
|
+
]);
|
|
71
|
+
function isBinaryContentType(contentType) {
|
|
72
|
+
if (!contentType) return false;
|
|
73
|
+
const mt = (contentType.split(";")[0] ?? "").trim().toLowerCase();
|
|
74
|
+
if (mt.startsWith("text/")) return false;
|
|
75
|
+
if (mt.endsWith("+json") || mt.endsWith("+xml")) return false;
|
|
76
|
+
if (mt.startsWith("image/") || mt.startsWith("audio/") || mt.startsWith("video/") || mt.startsWith("font/")) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
if (BINARY_APPLICATION_TYPES.has(mt)) return true;
|
|
80
|
+
if (mt.startsWith("application/vnd.openxmlformats")) return true;
|
|
81
|
+
if (mt.startsWith("application/vnd.oasis.opendocument")) return true;
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
__name(isBinaryContentType, "isBinaryContentType");
|
|
85
|
+
var MIME_EXTENSIONS = /* @__PURE__ */ new Map([
|
|
86
|
+
["application/pdf", "pdf"],
|
|
87
|
+
["application/zip", "zip"],
|
|
88
|
+
[
|
|
89
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
90
|
+
"docx"
|
|
91
|
+
],
|
|
92
|
+
["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx"],
|
|
93
|
+
[
|
|
94
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
95
|
+
"pptx"
|
|
96
|
+
],
|
|
97
|
+
["application/msword", "doc"],
|
|
98
|
+
["application/vnd.ms-excel", "xls"],
|
|
99
|
+
["application/vnd.ms-powerpoint", "ppt"],
|
|
100
|
+
["application/gzip", "gz"],
|
|
101
|
+
["application/x-gzip", "gz"],
|
|
102
|
+
["application/x-tar", "tar"],
|
|
103
|
+
["application/x-7z-compressed", "7z"],
|
|
104
|
+
["application/x-rar-compressed", "rar"],
|
|
105
|
+
["application/vnd.rar", "rar"],
|
|
106
|
+
["application/wasm", "wasm"],
|
|
107
|
+
["application/java-archive", "jar"],
|
|
108
|
+
["audio/mpeg", "mp3"],
|
|
109
|
+
["audio/wav", "wav"],
|
|
110
|
+
["audio/ogg", "ogg"],
|
|
111
|
+
["video/mp4", "mp4"],
|
|
112
|
+
["video/webm", "webm"],
|
|
113
|
+
["image/png", "png"],
|
|
114
|
+
["image/jpeg", "jpg"],
|
|
115
|
+
["image/gif", "gif"],
|
|
116
|
+
["image/webp", "webp"],
|
|
117
|
+
["image/svg+xml", "svg"]
|
|
118
|
+
]);
|
|
119
|
+
function extensionForMimeType(mimeType) {
|
|
120
|
+
if (!mimeType) return "bin";
|
|
121
|
+
const mt = (mimeType.split(";")[0] ?? "").trim().toLowerCase();
|
|
122
|
+
return MIME_EXTENSIONS.get(mt) ?? "bin";
|
|
123
|
+
}
|
|
124
|
+
__name(extensionForMimeType, "extensionForMimeType");
|
|
125
|
+
var KNOWN_EXTENSIONS = /* @__PURE__ */ new Set([...MIME_EXTENSIONS.values(), "jpeg", "bin"]);
|
|
126
|
+
function extensionFromFilename(name) {
|
|
127
|
+
if (!name) return void 0;
|
|
128
|
+
const ext = name.split(".").pop()?.trim().toLowerCase();
|
|
129
|
+
return ext && ext !== name && KNOWN_EXTENSIONS.has(ext) ? ext : void 0;
|
|
130
|
+
}
|
|
131
|
+
__name(extensionFromFilename, "extensionFromFilename");
|
|
132
|
+
function filenameFromContentDisposition(contentDisposition) {
|
|
133
|
+
const star = /filename\*\s*=\s*[^']*'[^']*'([^;]+)/i.exec(contentDisposition);
|
|
134
|
+
if (star?.[1]) {
|
|
135
|
+
try {
|
|
136
|
+
return decodeURIComponent(star[1].trim());
|
|
137
|
+
} catch {
|
|
138
|
+
return star[1].trim();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const plain = /filename\s*=\s*"?([^";]+)"?/i.exec(contentDisposition);
|
|
142
|
+
return plain?.[1]?.trim();
|
|
143
|
+
}
|
|
144
|
+
__name(filenameFromContentDisposition, "filenameFromContentDisposition");
|
|
145
|
+
function sniffFileKind(bytes, contentType, contentDisposition, url) {
|
|
146
|
+
const dispositionExt = extensionFromFilename(
|
|
147
|
+
filenameFromContentDisposition(contentDisposition)
|
|
148
|
+
);
|
|
149
|
+
let urlExt;
|
|
150
|
+
try {
|
|
151
|
+
urlExt = extensionFromFilename(new URL(url).pathname.split("/").pop());
|
|
152
|
+
} catch {
|
|
153
|
+
urlExt = void 0;
|
|
154
|
+
}
|
|
155
|
+
if (bytes.length >= 5 && bytes.subarray(0, 5).toString("latin1") === "%PDF-") {
|
|
156
|
+
return {
|
|
157
|
+
extension: "pdf",
|
|
158
|
+
mimeType: "application/pdf",
|
|
159
|
+
magicMatched: true,
|
|
160
|
+
extensionSource: "magic"
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
if (bytes.length >= 4 && bytes[0] === 80 && bytes[1] === 75 && bytes[2] === 3 && bytes[3] === 4) {
|
|
164
|
+
const zipHint = dispositionExt ?? urlExt ?? extensionForMimeType(contentType);
|
|
165
|
+
const refined = zipHint && ["docx", "xlsx", "pptx", "jar"].includes(zipHint) ? zipHint : "zip";
|
|
166
|
+
return {
|
|
167
|
+
extension: refined,
|
|
168
|
+
mimeType: contentType || "application/zip",
|
|
169
|
+
magicMatched: true,
|
|
170
|
+
extensionSource: "magic"
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
if (bytes.length >= 2 && bytes[0] === 31 && bytes[1] === 139) {
|
|
174
|
+
return {
|
|
175
|
+
extension: "gz",
|
|
176
|
+
mimeType: "application/gzip",
|
|
177
|
+
magicMatched: true,
|
|
178
|
+
extensionSource: "magic"
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
if (bytes.length >= 7 && bytes.subarray(0, 4).toString("latin1") === "Rar!" && bytes[4] === 26 && bytes[5] === 7) {
|
|
182
|
+
return {
|
|
183
|
+
extension: "rar",
|
|
184
|
+
mimeType: "application/vnd.rar",
|
|
185
|
+
magicMatched: true,
|
|
186
|
+
extensionSource: "magic"
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
if (bytes.length >= 8 && bytes[0] === 137 && bytes.subarray(1, 4).toString("latin1") === "PNG") {
|
|
190
|
+
return {
|
|
191
|
+
extension: "png",
|
|
192
|
+
mimeType: "image/png",
|
|
193
|
+
magicMatched: true,
|
|
194
|
+
extensionSource: "magic"
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
|
|
198
|
+
return {
|
|
199
|
+
extension: "jpg",
|
|
200
|
+
mimeType: "image/jpeg",
|
|
201
|
+
magicMatched: true,
|
|
202
|
+
extensionSource: "magic"
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
if (bytes.length >= 4 && bytes.subarray(0, 4).toString("latin1") === "GIF8") {
|
|
206
|
+
return {
|
|
207
|
+
extension: "gif",
|
|
208
|
+
mimeType: "image/gif",
|
|
209
|
+
magicMatched: true,
|
|
210
|
+
extensionSource: "magic"
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
if (bytes.length >= 12 && bytes.subarray(0, 4).toString("latin1") === "RIFF" && bytes.subarray(8, 12).toString("latin1") === "WEBP") {
|
|
214
|
+
return {
|
|
215
|
+
extension: "webp",
|
|
216
|
+
mimeType: "image/webp",
|
|
217
|
+
magicMatched: true,
|
|
218
|
+
extensionSource: "magic"
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
const nameExt = dispositionExt ?? urlExt;
|
|
222
|
+
if (nameExt) {
|
|
223
|
+
return {
|
|
224
|
+
extension: nameExt,
|
|
225
|
+
mimeType: contentType,
|
|
226
|
+
magicMatched: false,
|
|
227
|
+
extensionSource: "name"
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
const mimeExt = extensionForMimeType(contentType);
|
|
231
|
+
return {
|
|
232
|
+
extension: mimeExt,
|
|
233
|
+
mimeType: contentType,
|
|
234
|
+
magicMatched: false,
|
|
235
|
+
extensionSource: mimeExt !== "bin" ? "mime" : "fallback"
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
__name(sniffFileKind, "sniffFileKind");
|
|
239
|
+
function looksLikeText(bytes) {
|
|
240
|
+
const window = bytes.subarray(0, 8192);
|
|
241
|
+
if (window.includes(0)) return false;
|
|
242
|
+
const decoded = new TextDecoder("utf-8").decode(window);
|
|
243
|
+
let bad = 0;
|
|
244
|
+
for (let i = 0; i < decoded.length; i++) {
|
|
245
|
+
if (decoded[i] === "\uFFFD" && ++bad > 2) return false;
|
|
246
|
+
}
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
__name(looksLikeText, "looksLikeText");
|
|
250
|
+
async function persistBinaryContent(bytes, ext, dir, persistId) {
|
|
251
|
+
const filepath = path.join(dir, `${persistId}.${ext}`);
|
|
252
|
+
try {
|
|
253
|
+
await mkdir(dir, { recursive: true, mode: 448 });
|
|
254
|
+
await writeFile(filepath, bytes, { mode: 384 });
|
|
255
|
+
} catch (error) {
|
|
256
|
+
return { error: error instanceof Error ? error.message : String(error) };
|
|
257
|
+
}
|
|
258
|
+
return { filepath, size: bytes.length, ext };
|
|
259
|
+
}
|
|
260
|
+
__name(persistBinaryContent, "persistBinaryContent");
|
|
261
|
+
function formatByteSize(sizeInBytes) {
|
|
262
|
+
const kb = sizeInBytes / 1024;
|
|
263
|
+
if (kb < 1) return `${sizeInBytes} bytes`;
|
|
264
|
+
const fmt = /* @__PURE__ */ __name((n) => n.toFixed(1).replace(/\.0$/, ""), "fmt");
|
|
265
|
+
if (kb < 1024) return `${fmt(kb)}KB`;
|
|
266
|
+
const mb = kb / 1024;
|
|
267
|
+
if (mb < 1024) return `${fmt(mb)}MB`;
|
|
268
|
+
return `${fmt(mb / 1024)}GB`;
|
|
269
|
+
}
|
|
270
|
+
__name(formatByteSize, "formatByteSize");
|
|
271
|
+
|
|
272
|
+
// packages/core/src/tools/web-fetch-preapproved.ts
|
|
273
|
+
init_esbuild_shims();
|
|
274
|
+
var PREAPPROVED_HOSTS = /* @__PURE__ */ new Set([
|
|
275
|
+
// Qwen ecosystem
|
|
276
|
+
"qwenlm.github.io",
|
|
277
|
+
"qwen.readthedocs.io",
|
|
278
|
+
"github.com/QwenLM",
|
|
279
|
+
// Matches QwenLM raw files whether requested directly or via a github.com
|
|
280
|
+
// blob URL (the tool rewrites those to this host before fetching).
|
|
281
|
+
"raw.githubusercontent.com/QwenLM",
|
|
282
|
+
"modelcontextprotocol.io",
|
|
283
|
+
// Top programming languages
|
|
284
|
+
"docs.python.org",
|
|
285
|
+
"en.cppreference.com",
|
|
286
|
+
"docs.oracle.com",
|
|
287
|
+
"learn.microsoft.com",
|
|
288
|
+
"developer.mozilla.org",
|
|
289
|
+
"go.dev",
|
|
290
|
+
"pkg.go.dev",
|
|
291
|
+
"www.php.net",
|
|
292
|
+
"docs.swift.org",
|
|
293
|
+
"kotlinlang.org",
|
|
294
|
+
"ruby-doc.org",
|
|
295
|
+
"doc.rust-lang.org",
|
|
296
|
+
"www.typescriptlang.org",
|
|
297
|
+
// Web & JavaScript frameworks/libraries
|
|
298
|
+
"react.dev",
|
|
299
|
+
"angular.io",
|
|
300
|
+
"vuejs.org",
|
|
301
|
+
"nextjs.org",
|
|
302
|
+
"expressjs.com",
|
|
303
|
+
"nodejs.org",
|
|
304
|
+
"bun.sh",
|
|
305
|
+
"jquery.com",
|
|
306
|
+
"getbootstrap.com",
|
|
307
|
+
"tailwindcss.com",
|
|
308
|
+
"d3js.org",
|
|
309
|
+
"threejs.org",
|
|
310
|
+
"redux.js.org",
|
|
311
|
+
"webpack.js.org",
|
|
312
|
+
"jestjs.io",
|
|
313
|
+
"reactrouter.com",
|
|
314
|
+
// Python frameworks & libraries
|
|
315
|
+
"docs.djangoproject.com",
|
|
316
|
+
"flask.palletsprojects.com",
|
|
317
|
+
"fastapi.tiangolo.com",
|
|
318
|
+
"pandas.pydata.org",
|
|
319
|
+
"numpy.org",
|
|
320
|
+
"www.tensorflow.org",
|
|
321
|
+
"pytorch.org",
|
|
322
|
+
"scikit-learn.org",
|
|
323
|
+
"matplotlib.org",
|
|
324
|
+
"requests.readthedocs.io",
|
|
325
|
+
"jupyter.org",
|
|
326
|
+
// PHP frameworks
|
|
327
|
+
"laravel.com",
|
|
328
|
+
"symfony.com",
|
|
329
|
+
"wordpress.org",
|
|
330
|
+
// Java frameworks & libraries
|
|
331
|
+
"docs.spring.io",
|
|
332
|
+
"hibernate.org",
|
|
333
|
+
"tomcat.apache.org",
|
|
334
|
+
"gradle.org",
|
|
335
|
+
"maven.apache.org",
|
|
336
|
+
// .NET & C# frameworks
|
|
337
|
+
"asp.net",
|
|
338
|
+
"dotnet.microsoft.com",
|
|
339
|
+
"nuget.org",
|
|
340
|
+
"blazor.net",
|
|
341
|
+
// Mobile development
|
|
342
|
+
"reactnative.dev",
|
|
343
|
+
"docs.flutter.dev",
|
|
344
|
+
"developer.apple.com",
|
|
345
|
+
"developer.android.com",
|
|
346
|
+
// Data science & machine learning
|
|
347
|
+
"keras.io",
|
|
348
|
+
"spark.apache.org",
|
|
349
|
+
"huggingface.co",
|
|
350
|
+
"www.kaggle.com",
|
|
351
|
+
// Databases
|
|
352
|
+
"www.mongodb.com",
|
|
353
|
+
"redis.io",
|
|
354
|
+
"www.postgresql.org",
|
|
355
|
+
"dev.mysql.com",
|
|
356
|
+
"www.sqlite.org",
|
|
357
|
+
"graphql.org",
|
|
358
|
+
"prisma.io",
|
|
359
|
+
// Cloud & DevOps
|
|
360
|
+
"docs.aws.amazon.com",
|
|
361
|
+
"cloud.google.com",
|
|
362
|
+
"kubernetes.io",
|
|
363
|
+
"www.docker.com",
|
|
364
|
+
"www.terraform.io",
|
|
365
|
+
"www.ansible.com",
|
|
366
|
+
"vercel.com/docs",
|
|
367
|
+
"docs.netlify.com",
|
|
368
|
+
"devcenter.heroku.com",
|
|
369
|
+
// Testing & monitoring
|
|
370
|
+
"cypress.io",
|
|
371
|
+
"selenium.dev",
|
|
372
|
+
// Game development
|
|
373
|
+
"docs.unity.com",
|
|
374
|
+
"docs.unrealengine.com",
|
|
375
|
+
// Other essential tools
|
|
376
|
+
"git-scm.com",
|
|
377
|
+
"nginx.org",
|
|
378
|
+
"httpd.apache.org"
|
|
379
|
+
]);
|
|
380
|
+
var stripWww = /* @__PURE__ */ __name((hostname) => hostname.replace(/^www\./, ""), "stripWww");
|
|
381
|
+
var { HOSTNAME_ONLY, PATH_PREFIXES } = (() => {
|
|
382
|
+
const hosts = /* @__PURE__ */ new Set();
|
|
383
|
+
const paths = /* @__PURE__ */ new Map();
|
|
384
|
+
for (const entry of PREAPPROVED_HOSTS) {
|
|
385
|
+
const slash = entry.indexOf("/");
|
|
386
|
+
if (slash === -1) {
|
|
387
|
+
hosts.add(stripWww(entry));
|
|
388
|
+
} else {
|
|
389
|
+
const host = stripWww(entry.slice(0, slash));
|
|
390
|
+
const prefix = entry.slice(slash).toLowerCase();
|
|
391
|
+
const prefixes = paths.get(host);
|
|
392
|
+
if (prefixes) {
|
|
393
|
+
prefixes.push(prefix);
|
|
394
|
+
} else {
|
|
395
|
+
paths.set(host, [prefix]);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return { HOSTNAME_ONLY: hosts, PATH_PREFIXES: paths };
|
|
400
|
+
})();
|
|
401
|
+
function isPreapprovedHost(hostname, pathname) {
|
|
402
|
+
const host = stripWww(hostname.toLowerCase());
|
|
403
|
+
if (HOSTNAME_ONLY.has(host)) {
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
const prefixes = PATH_PREFIXES.get(host);
|
|
407
|
+
if (prefixes) {
|
|
408
|
+
const path2 = pathname.toLowerCase();
|
|
409
|
+
for (const prefix of prefixes) {
|
|
410
|
+
if (path2 === prefix || path2.startsWith(prefix + "/")) {
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
__name(isPreapprovedHost, "isPreapprovedHost");
|
|
418
|
+
function isPreapprovedUrl(url) {
|
|
419
|
+
try {
|
|
420
|
+
const parsed = new URL(url);
|
|
421
|
+
return parsed.protocol === "https:" && isPreapprovedHost(parsed.hostname, parsed.pathname);
|
|
422
|
+
} catch {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
__name(isPreapprovedUrl, "isPreapprovedUrl");
|
|
427
|
+
|
|
428
|
+
// packages/core/src/tools/web-fetch.ts
|
|
429
|
+
var FETCH_TIMEOUT_MS = 6e4;
|
|
430
|
+
var MAX_CONTENT_CHARS = 1e5;
|
|
431
|
+
var MAX_RESPONSE_BYTES = 10 * 1024 * 1024;
|
|
432
|
+
var MAX_REDIRECTS = 10;
|
|
433
|
+
var CACHE_TTL_MS = 15 * 60 * 1e3;
|
|
434
|
+
var CACHE_CAPACITY = 32;
|
|
435
|
+
var MAX_CACHEABLE_CHARS = 2 * 1024 * 1024;
|
|
436
|
+
var cachesByStorage = /* @__PURE__ */ new WeakMap();
|
|
437
|
+
function getUrlCacheFor(storage) {
|
|
438
|
+
let cache = cachesByStorage.get(storage);
|
|
439
|
+
if (!cache) {
|
|
440
|
+
cache = new import_lru_cache.default(CACHE_CAPACITY);
|
|
441
|
+
cachesByStorage.set(storage, cache);
|
|
442
|
+
}
|
|
443
|
+
return cache;
|
|
444
|
+
}
|
|
445
|
+
__name(getUrlCacheFor, "getUrlCacheFor");
|
|
446
|
+
function clearWebFetchCache() {
|
|
447
|
+
cachesByStorage = /* @__PURE__ */ new WeakMap();
|
|
448
|
+
}
|
|
449
|
+
__name(clearWebFetchCache, "clearWebFetchCache");
|
|
450
|
+
var turndownPromise;
|
|
451
|
+
function getTurndownService() {
|
|
452
|
+
return turndownPromise ??= import("./turndown.cjs-FZHGMUTY.js").then((m) => {
|
|
453
|
+
const service = new m.default();
|
|
454
|
+
service.remove(["script", "style", "noscript"]);
|
|
455
|
+
service.addRule("drop-images", {
|
|
456
|
+
filter: "img",
|
|
457
|
+
replacement: /* @__PURE__ */ __name(() => "", "replacement")
|
|
458
|
+
});
|
|
459
|
+
return service;
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
__name(getTurndownService, "getTurndownService");
|
|
463
|
+
var USER_AGENT_SUFFIX = `(${process.platform}; ${process.arch})`;
|
|
464
|
+
function rewriteGitHubBlobUrl(url) {
|
|
465
|
+
try {
|
|
466
|
+
const parsed = new URL(url);
|
|
467
|
+
const host = parsed.hostname.toLowerCase();
|
|
468
|
+
if (host !== "github.com" && host !== "www.github.com") {
|
|
469
|
+
return url;
|
|
470
|
+
}
|
|
471
|
+
const rawPath = parsed.pathname.replace(/^(\/[^/]+\/[^/]+)\/blob\//, "$1/");
|
|
472
|
+
if (rawPath === parsed.pathname) {
|
|
473
|
+
return url;
|
|
474
|
+
}
|
|
475
|
+
parsed.hostname = "raw.githubusercontent.com";
|
|
476
|
+
parsed.pathname = rawPath;
|
|
477
|
+
return parsed.toString();
|
|
478
|
+
} catch {
|
|
479
|
+
return url;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
__name(rewriteGitHubBlobUrl, "rewriteGitHubBlobUrl");
|
|
483
|
+
function hostnameOf(url) {
|
|
484
|
+
try {
|
|
485
|
+
return new URL(url).hostname;
|
|
486
|
+
} catch {
|
|
487
|
+
return url;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
__name(hostnameOf, "hostnameOf");
|
|
491
|
+
function readHintForPath(persistedPath) {
|
|
492
|
+
if (persistedPath.endsWith(".pdf")) {
|
|
493
|
+
return ` Use ${ToolNames.READ_FILE} to examine it (reads PDFs natively; pass pages for large files).`;
|
|
494
|
+
}
|
|
495
|
+
if (/\.(png|jpe?g|gif|webp)$/.test(persistedPath)) {
|
|
496
|
+
return ` Use ${ToolNames.READ_FILE} to view it.`;
|
|
497
|
+
}
|
|
498
|
+
return "";
|
|
499
|
+
}
|
|
500
|
+
__name(readHintForPath, "readHintForPath");
|
|
501
|
+
function truncateText(text) {
|
|
502
|
+
if (text.length <= MAX_CONTENT_CHARS) {
|
|
503
|
+
return text;
|
|
504
|
+
}
|
|
505
|
+
return text.slice(0, MAX_CONTENT_CHARS) + `
|
|
506
|
+
|
|
507
|
+
[Content truncated: showing first ${MAX_CONTENT_CHARS.toLocaleString("en-US")} of ${text.length.toLocaleString("en-US")} characters]`;
|
|
508
|
+
}
|
|
509
|
+
__name(truncateText, "truncateText");
|
|
510
|
+
var WebFetchToolInvocation = class extends BaseToolInvocation {
|
|
511
|
+
constructor(config, params) {
|
|
512
|
+
super(params);
|
|
513
|
+
this.config = config;
|
|
514
|
+
this.debugLogger = createDebugLogger("WEB_FETCH");
|
|
515
|
+
}
|
|
516
|
+
static {
|
|
517
|
+
__name(this, "WebFetchToolInvocation");
|
|
518
|
+
}
|
|
519
|
+
debugLogger;
|
|
520
|
+
getAcceptHeader() {
|
|
521
|
+
const format = this.params.format ?? "auto";
|
|
522
|
+
switch (format) {
|
|
523
|
+
case "markdown":
|
|
524
|
+
return "text/markdown, */*;q=0.1";
|
|
525
|
+
case "html":
|
|
526
|
+
return "text/html, */*;q=0.1";
|
|
527
|
+
case "text":
|
|
528
|
+
return "text/plain, */*;q=0.1";
|
|
529
|
+
case "auto":
|
|
530
|
+
default:
|
|
531
|
+
return "text/markdown, text/html;q=0.9, text/plain;q=0.8, */*;q=0.1";
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
getUserAgent() {
|
|
535
|
+
const version = this.config.getCliVersion?.() || "unknown";
|
|
536
|
+
return `QwenCode/${version} ${USER_AGENT_SUFFIX}`;
|
|
537
|
+
}
|
|
538
|
+
fetchPlan;
|
|
539
|
+
/** The URL actually fetched: blob→raw for GitHub, https upgrade for public hosts. */
|
|
540
|
+
getFetchUrl() {
|
|
541
|
+
return this.getFetchPlan().url;
|
|
542
|
+
}
|
|
543
|
+
getFetchPlan() {
|
|
544
|
+
return this.fetchPlan ??= this.computeFetchPlan();
|
|
545
|
+
}
|
|
546
|
+
computeFetchPlan() {
|
|
547
|
+
let url = this.params.url;
|
|
548
|
+
let upgradedFrom;
|
|
549
|
+
if (url.toLowerCase().startsWith("http://") && !isPrivateHost(url)) {
|
|
550
|
+
try {
|
|
551
|
+
const parsed = new URL(url);
|
|
552
|
+
if (parsed.port === "") {
|
|
553
|
+
upgradedFrom = url;
|
|
554
|
+
parsed.protocol = "https:";
|
|
555
|
+
url = parsed.toString();
|
|
556
|
+
this.debugLogger.debug(`[WebFetchTool] Upgraded to https: ${url}`);
|
|
557
|
+
}
|
|
558
|
+
} catch {
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return { url, upgradedFrom };
|
|
562
|
+
}
|
|
563
|
+
buildRedirectResult(redirect) {
|
|
564
|
+
const redirectHost = hostnameOf(redirect.redirectUrl);
|
|
565
|
+
const message = `REDIRECT DETECTED: The URL redirects to a different host (or scheme/port), which was not followed automatically.
|
|
566
|
+
|
|
567
|
+
Original URL: ${redirect.originalUrl}
|
|
568
|
+
Redirect URL: ${redirect.redirectUrl}
|
|
569
|
+
Status: ${redirect.status}
|
|
570
|
+
|
|
571
|
+
To fetch the redirected content, call ${WebFetchTool.Name} again with:
|
|
572
|
+
- url: "${redirect.redirectUrl}"
|
|
573
|
+
- prompt: "${this.params.prompt}"`;
|
|
574
|
+
return {
|
|
575
|
+
llmContent: message,
|
|
576
|
+
returnDisplay: `Redirected to ${redirectHost} (${redirect.status}) \u2014 not followed (different host or scheme/port).`
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
buildMetadataHeader(entry) {
|
|
580
|
+
const urlLine = entry.finalUrl !== this.params.url ? `URL: ${this.params.url} (final: ${entry.finalUrl})` : `URL: ${this.params.url}`;
|
|
581
|
+
return `${urlLine}
|
|
582
|
+
Status: ${entry.status} ${entry.statusText || "OK"} | Content-Type: ${entry.contentType || "unknown"} | Size: ${entry.byteLength.toLocaleString("en-US")} bytes`;
|
|
583
|
+
}
|
|
584
|
+
async fetchAndProcess(signal) {
|
|
585
|
+
const fetchUrl = this.getFetchUrl();
|
|
586
|
+
const acceptHeader = this.getAcceptHeader();
|
|
587
|
+
const urlCache = getUrlCacheFor(this.config.storage);
|
|
588
|
+
const cacheKey = `${this.config.getSessionId?.() ?? ""}|${acceptHeader} ${fetchUrl}`;
|
|
589
|
+
const cached = urlCache.get(cacheKey);
|
|
590
|
+
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
|
|
591
|
+
this.debugLogger.debug(`[WebFetchTool] Cache hit for ${fetchUrl}`);
|
|
592
|
+
return cached;
|
|
593
|
+
}
|
|
594
|
+
this.debugLogger.debug(
|
|
595
|
+
`[WebFetchTool] Fetching ${fetchUrl} (Accept: ${acceptHeader})`
|
|
596
|
+
);
|
|
597
|
+
const policyOptions = {
|
|
598
|
+
timeoutMs: FETCH_TIMEOUT_MS,
|
|
599
|
+
maxBytes: MAX_RESPONSE_BYTES,
|
|
600
|
+
maxRedirects: MAX_REDIRECTS,
|
|
601
|
+
signal,
|
|
602
|
+
headers: {
|
|
603
|
+
Accept: acceptHeader,
|
|
604
|
+
"User-Agent": this.getUserAgent()
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
let result;
|
|
608
|
+
let usedHttpFallback = false;
|
|
609
|
+
try {
|
|
610
|
+
result = await fetchWithPolicy(fetchUrl, policyOptions);
|
|
611
|
+
} catch (error) {
|
|
612
|
+
const { upgradedFrom } = this.getFetchPlan();
|
|
613
|
+
if (upgradedFrom && isConnectionLevelError(error)) {
|
|
614
|
+
this.debugLogger.debug(
|
|
615
|
+
`[WebFetchTool] https upgrade failed (${error.message}); retrying original ${upgradedFrom}`
|
|
616
|
+
);
|
|
617
|
+
result = await fetchWithPolicy(upgradedFrom, policyOptions);
|
|
618
|
+
usedHttpFallback = true;
|
|
619
|
+
} else {
|
|
620
|
+
throw error;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if (result.kind === "cross-host-redirect") {
|
|
624
|
+
return result;
|
|
625
|
+
}
|
|
626
|
+
const response = result;
|
|
627
|
+
if (response.status < 200 || response.status >= 300) {
|
|
628
|
+
throw new Error(
|
|
629
|
+
`Request failed with status code ${response.status} ${response.statusText}`
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
const contentType = response.contentType;
|
|
633
|
+
const sniff = sniffFileKind(
|
|
634
|
+
response.body,
|
|
635
|
+
contentType,
|
|
636
|
+
response.contentDisposition,
|
|
637
|
+
response.finalUrl
|
|
638
|
+
);
|
|
639
|
+
let isBinary = isBinaryContentType(contentType) || sniff.magicMatched || !contentType && sniff.extensionSource === "name" && sniff.extension !== "svg";
|
|
640
|
+
if (isBinary && (contentType.split(";")[0] ?? "").trim().toLowerCase() === "application/octet-stream" && !sniff.magicMatched && sniff.extensionSource === "fallback" && looksLikeText(response.body)) {
|
|
641
|
+
isBinary = false;
|
|
642
|
+
}
|
|
643
|
+
let persistedPath;
|
|
644
|
+
let persistedSize;
|
|
645
|
+
let persistedMime;
|
|
646
|
+
let content;
|
|
647
|
+
if (isBinary) {
|
|
648
|
+
const budgetUsed = this.config.getToolResultBytesWritten();
|
|
649
|
+
if (budgetUsed + response.body.length > MAX_SESSION_BYTES) {
|
|
650
|
+
throw new Error(
|
|
651
|
+
`Fetched ${response.body.length} bytes of binary content (${contentType || "unknown content type"}) but the session's tool-result disk budget is exhausted (${budgetUsed} bytes used of ${MAX_SESSION_BYTES}).`
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
this.config.trackToolResultBytes(response.body.length);
|
|
655
|
+
const persistId = `webfetch-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
656
|
+
const persisted = await persistBinaryContent(
|
|
657
|
+
response.body,
|
|
658
|
+
sniff.extension,
|
|
659
|
+
this.config.storage.getToolResultsDir(),
|
|
660
|
+
persistId
|
|
661
|
+
);
|
|
662
|
+
if ("error" in persisted) {
|
|
663
|
+
this.config.trackToolResultBytes(-response.body.length);
|
|
664
|
+
this.debugLogger.error(
|
|
665
|
+
`[WebFetchTool] Failed to persist binary content: ${persisted.error}`
|
|
666
|
+
);
|
|
667
|
+
throw new Error(
|
|
668
|
+
`Fetched ${response.body.length} bytes of binary content (${contentType || "unknown content type"}) but failed to save it: ${persisted.error}`
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
persistedPath = persisted.filepath;
|
|
672
|
+
persistedSize = persisted.size;
|
|
673
|
+
persistedMime = sniff.mimeType || contentType;
|
|
674
|
+
content = "";
|
|
675
|
+
if (sniff.extension === "pdf" && persistedPath) {
|
|
676
|
+
const pdfText = await extractPDFText(persistedPath, { signal });
|
|
677
|
+
if (pdfText.success && pdfText.text.trim()) {
|
|
678
|
+
content = truncateText(pdfText.text);
|
|
679
|
+
} else if (!pdfText.success) {
|
|
680
|
+
this.debugLogger.debug(
|
|
681
|
+
`[WebFetchTool] PDF text extraction failed: ${pdfText.error}`
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
} else if (contentType.includes("text/html")) {
|
|
686
|
+
this.debugLogger.debug("[WebFetchTool] Converting HTML to markdown");
|
|
687
|
+
const decoded = response.body.toString("utf-8");
|
|
688
|
+
try {
|
|
689
|
+
const turndown = await getTurndownService();
|
|
690
|
+
content = truncateText(turndown.turndown(decoded));
|
|
691
|
+
} catch (error) {
|
|
692
|
+
this.debugLogger.error(
|
|
693
|
+
`[WebFetchTool] HTML conversion failed, using raw text`,
|
|
694
|
+
error
|
|
695
|
+
);
|
|
696
|
+
content = truncateText(decoded);
|
|
697
|
+
}
|
|
698
|
+
} else {
|
|
699
|
+
content = truncateText(response.body.toString("utf-8"));
|
|
700
|
+
}
|
|
701
|
+
const entry = {
|
|
702
|
+
fetchedAt: Date.now(),
|
|
703
|
+
status: response.status,
|
|
704
|
+
statusText: response.statusText,
|
|
705
|
+
contentType,
|
|
706
|
+
byteLength: response.body.length,
|
|
707
|
+
finalUrl: response.finalUrl,
|
|
708
|
+
content,
|
|
709
|
+
persistedPath,
|
|
710
|
+
persistedSize,
|
|
711
|
+
persistedMime
|
|
712
|
+
};
|
|
713
|
+
if (!usedHttpFallback && content.length <= MAX_CACHEABLE_CHARS) {
|
|
714
|
+
urlCache.set(cacheKey, entry);
|
|
715
|
+
}
|
|
716
|
+
return entry;
|
|
717
|
+
}
|
|
718
|
+
async executeDirectFetch(signal) {
|
|
719
|
+
try {
|
|
720
|
+
const entry = await this.fetchAndProcess(signal);
|
|
721
|
+
if ("kind" in entry) {
|
|
722
|
+
return this.buildRedirectResult(entry);
|
|
723
|
+
}
|
|
724
|
+
const header = this.buildMetadataHeader(entry);
|
|
725
|
+
const binaryNote = entry.persistedPath ? `
|
|
726
|
+
|
|
727
|
+
[Binary content (${entry.persistedMime || entry.contentType || "unknown"}, ${formatByteSize(entry.persistedSize ?? entry.byteLength)}) saved to ${entry.persistedPath}.${readHintForPath(entry.persistedPath)}]` : "";
|
|
728
|
+
const displaySummary = `Received ${formatByteSize(entry.byteLength)} (${entry.status} ${entry.statusText || "OK"}) from ${hostnameOf(this.params.url)}${entry.persistedPath ? ` \u2014 binary saved to ${entry.persistedPath}` : ""}`;
|
|
729
|
+
if (entry.persistedPath && !entry.content) {
|
|
730
|
+
return {
|
|
731
|
+
llmContent: `${header}
|
|
732
|
+
|
|
733
|
+
[No text could be extracted from this binary content.]${binaryNote}`,
|
|
734
|
+
returnDisplay: displaySummary,
|
|
735
|
+
resultFilePaths: [entry.persistedPath]
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
const preapproved = isPreapprovedUrl(entry.finalUrl);
|
|
739
|
+
if (preapproved && entry.contentType.includes("text/markdown") && entry.content.length <= MAX_CONTENT_CHARS) {
|
|
740
|
+
return {
|
|
741
|
+
llmContent: `${header}
|
|
742
|
+
|
|
743
|
+
${entry.content}${binaryNote}`,
|
|
744
|
+
returnDisplay: displaySummary,
|
|
745
|
+
...entry.persistedPath ? { resultFilePaths: [entry.persistedPath] } : {}
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
const fallbackPrompt = `The user requested the following: "${this.params.prompt}".
|
|
749
|
+
|
|
750
|
+
I have fetched the content from ${this.params.url}. Fetch metadata:
|
|
751
|
+
${header}
|
|
752
|
+
|
|
753
|
+
Please use the following content to answer the user's request.
|
|
754
|
+
|
|
755
|
+
---
|
|
756
|
+
${entry.content}
|
|
757
|
+
---`;
|
|
758
|
+
const result = await runSideQuery(this.config, {
|
|
759
|
+
purpose: "web-fetch",
|
|
760
|
+
// Pin to the main model — fast model loses too much fidelity on
|
|
761
|
+
// long, rich source material.
|
|
762
|
+
model: this.config.getModel(),
|
|
763
|
+
// Best-effort: the outer catch already converts processing failures
|
|
764
|
+
// into a tool error; retrying 7× just delays that fallback.
|
|
765
|
+
maxAttempts: 1,
|
|
766
|
+
contents: [{ role: "user", parts: [{ text: fallbackPrompt }] }],
|
|
767
|
+
systemInstruction: "Extract and summarize the requested information from the provided web content. Be concise and accurate. Respond only with the requested information.",
|
|
768
|
+
abortSignal: signal
|
|
769
|
+
});
|
|
770
|
+
let resultText = (result.text || "").trim();
|
|
771
|
+
if (!resultText) {
|
|
772
|
+
resultText = "[The processing model returned no content. The fetch itself succeeded \u2014 see the metadata above.]";
|
|
773
|
+
}
|
|
774
|
+
return {
|
|
775
|
+
llmContent: `${header}
|
|
776
|
+
|
|
777
|
+
${resultText}${binaryNote}`,
|
|
778
|
+
returnDisplay: displaySummary,
|
|
779
|
+
...entry.persistedPath ? { resultFilePaths: [entry.persistedPath] } : {}
|
|
780
|
+
};
|
|
781
|
+
} catch (e) {
|
|
782
|
+
const error = e;
|
|
783
|
+
const errorMessage = `Error during fetch for ${this.params.url}: ${error.message}`;
|
|
784
|
+
this.debugLogger.error(`[WebFetchTool] ${errorMessage}`, error);
|
|
785
|
+
return {
|
|
786
|
+
llmContent: `Error: ${errorMessage}`,
|
|
787
|
+
returnDisplay: `Error: ${errorMessage}`,
|
|
788
|
+
error: {
|
|
789
|
+
message: errorMessage,
|
|
790
|
+
type: "web_fetch_fallback_failed" /* WEB_FETCH_FALLBACK_FAILED */
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
getDescription() {
|
|
796
|
+
const displayPrompt = this.params.prompt.length > 100 ? this.params.prompt.substring(0, 97) + "..." : this.params.prompt;
|
|
797
|
+
const format = this.params.format ?? "auto";
|
|
798
|
+
return `Fetching content from ${this.params.url} (format: ${format}) and processing with prompt: "${displayPrompt}"`;
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* WebFetch always requires confirmation: it is an egress operation, not a
|
|
802
|
+
* read. A GET discloses its full path and query to a third party, so a
|
|
803
|
+
* model-produced URL (e.g. under prompt injection) is an exfiltration
|
|
804
|
+
* channel regardless of how "trusted" the host is — there is no curated
|
|
805
|
+
* host list this tool can safely auto-allow on the user's behalf. The
|
|
806
|
+
* permission flow consults this default only when no user rule matches, so
|
|
807
|
+
* a user who wants a no-prompt host can still add their own allow rule.
|
|
808
|
+
* (In AUTO mode, WebFetch is excluded from the safe-tool allowlist and
|
|
809
|
+
* instead judged by the exfiltration-aware classifier.)
|
|
810
|
+
*/
|
|
811
|
+
async getDefaultPermission() {
|
|
812
|
+
return "ask";
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* Constructs the web fetch confirmation details.
|
|
816
|
+
*/
|
|
817
|
+
async getConfirmationDetails(_abortSignal) {
|
|
818
|
+
const permissionRules = [`WebFetch(${hostnameOf(this.params.url)})`];
|
|
819
|
+
const confirmationDetails = {
|
|
820
|
+
type: "info",
|
|
821
|
+
title: `Confirm Web Fetch`,
|
|
822
|
+
prompt: `Fetch content from ${this.params.url} and process with: ${this.params.prompt}`,
|
|
823
|
+
urls: [this.params.url],
|
|
824
|
+
permissionRules,
|
|
825
|
+
onConfirm: /* @__PURE__ */ __name(async (_outcome, _payload) => {
|
|
826
|
+
}, "onConfirm")
|
|
827
|
+
};
|
|
828
|
+
return confirmationDetails;
|
|
829
|
+
}
|
|
830
|
+
async execute(signal) {
|
|
831
|
+
return this.executeDirectFetch(signal);
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
var WebFetchTool = class _WebFetchTool extends BaseDeclarativeTool {
|
|
835
|
+
constructor(config) {
|
|
836
|
+
super(
|
|
837
|
+
_WebFetchTool.Name,
|
|
838
|
+
ToolDisplayNames.WEB_FETCH,
|
|
839
|
+
`Fetches content from a specified URL and processes it using an AI model
|
|
840
|
+
- Takes a URL and a prompt as input
|
|
841
|
+
- Supports content negotiation for markdown (reduces tokens by ~80%)
|
|
842
|
+
- Fetches the URL content and converts HTML to markdown (links preserved)
|
|
843
|
+
- Processes the content with the prompt using an AI model
|
|
844
|
+
- Returns the model's response about the content, prefixed with fetch metadata (HTTP status, content type, size)
|
|
845
|
+
- Use this tool when you need to retrieve and analyze web content
|
|
846
|
+
|
|
847
|
+
Usage notes:
|
|
848
|
+
- IMPORTANT: This tool cannot access authenticated or private URLs (e.g. Google Docs, Confluence, Jira, private GitHub). If an MCP-provided web fetch tool is available, prefer using that tool instead of this one, as it may have fewer restrictions. All MCP-provided tools start with "mcp__".
|
|
849
|
+
- The URL must be a fully-formed valid URL
|
|
850
|
+
- Plain-http URLs to public hosts are upgraded to https automatically; localhost/private hosts are fetched as-is
|
|
851
|
+
- When a URL redirects to a different host, the redirect is NOT followed; the tool returns the redirect URL so you can re-issue web_fetch with it
|
|
852
|
+
- Binary content (PDFs, images, archives) is saved to a local file; the result includes the file path \u2014 use read_file on it (it reads PDFs and images natively)
|
|
853
|
+
- Repeated fetches of the same URL within 15 minutes are served from a local cache
|
|
854
|
+
- The prompt should describe what information you want to extract from the page
|
|
855
|
+
- format parameter (optional): controls only the Accept header sent to the server. All content is normalized to plain text for LLM processing, regardless of format.
|
|
856
|
+
- "auto" (default): Prefers markdown via content negotiation, accepts HTML, text, or other content as fallback. Use when user does NOT specify a format.
|
|
857
|
+
- "markdown": Prefers text/markdown. Use when user explicitly asks for markdown content.
|
|
858
|
+
- "html": Prefers text/html. Content is still converted to markdown for LLM processing.
|
|
859
|
+
- "text": Prefers text/plain. Use when user explicitly asks for plain text.
|
|
860
|
+
- This tool does not modify any files (other than saving fetched binary content)
|
|
861
|
+
- Results may be summarized if the content is very large
|
|
862
|
+
- Supports both public and private/localhost URLs using direct fetch`,
|
|
863
|
+
"fetch" /* Fetch */,
|
|
864
|
+
{
|
|
865
|
+
properties: {
|
|
866
|
+
url: {
|
|
867
|
+
description: "The URL to fetch content from",
|
|
868
|
+
type: "string"
|
|
869
|
+
},
|
|
870
|
+
prompt: {
|
|
871
|
+
description: "The prompt to run on the fetched content",
|
|
872
|
+
type: "string"
|
|
873
|
+
},
|
|
874
|
+
format: {
|
|
875
|
+
description: "Preferred content format (Accept header only): auto (default, prefers markdown), markdown, html, or text. All content is normalized to plain text.",
|
|
876
|
+
type: "string",
|
|
877
|
+
enum: ["auto", "markdown", "html", "text"]
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
required: ["url", "prompt"],
|
|
881
|
+
type: "object"
|
|
882
|
+
},
|
|
883
|
+
true,
|
|
884
|
+
// isOutputMarkdown
|
|
885
|
+
false,
|
|
886
|
+
// canUpdateOutput
|
|
887
|
+
true,
|
|
888
|
+
// shouldDefer — web fetching is infrequent
|
|
889
|
+
false,
|
|
890
|
+
// alwaysLoad
|
|
891
|
+
"web fetch url http download content"
|
|
892
|
+
);
|
|
893
|
+
this.config = config;
|
|
894
|
+
}
|
|
895
|
+
static {
|
|
896
|
+
__name(this, "WebFetchTool");
|
|
897
|
+
}
|
|
898
|
+
static Name = ToolNames.WEB_FETCH;
|
|
899
|
+
validateToolParamValues(params) {
|
|
900
|
+
if (!params.url || params.url.trim() === "") {
|
|
901
|
+
return "The 'url' parameter cannot be empty.";
|
|
902
|
+
}
|
|
903
|
+
if (!/^https?:\/\//i.test(params.url)) {
|
|
904
|
+
return "The 'url' must be a valid URL starting with http:// or https://.";
|
|
905
|
+
}
|
|
906
|
+
try {
|
|
907
|
+
const parsedUrl = new URL(params.url);
|
|
908
|
+
if (parsedUrl.username || parsedUrl.password) {
|
|
909
|
+
return "The 'url' must not include credentials.";
|
|
910
|
+
}
|
|
911
|
+
} catch {
|
|
912
|
+
return "The 'url' is malformed and could not be parsed.";
|
|
913
|
+
}
|
|
914
|
+
if (!params.prompt || params.prompt.trim() === "") {
|
|
915
|
+
return "The 'prompt' parameter cannot be empty.";
|
|
916
|
+
}
|
|
917
|
+
return null;
|
|
918
|
+
}
|
|
919
|
+
createInvocation(params) {
|
|
920
|
+
return new WebFetchToolInvocation(this.config, {
|
|
921
|
+
...params,
|
|
922
|
+
url: rewriteGitHubBlobUrl(params.url)
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
toAutoClassifierInput(params) {
|
|
926
|
+
return { url: params.url };
|
|
927
|
+
}
|
|
928
|
+
};
|
|
929
|
+
export {
|
|
930
|
+
WebFetchTool,
|
|
931
|
+
clearWebFetchCache,
|
|
932
|
+
rewriteGitHubBlobUrl
|
|
933
|
+
};
|
|
934
|
+
/**
|
|
935
|
+
* @license
|
|
936
|
+
* Copyright 2025 Google LLC
|
|
937
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
938
|
+
*/
|