@noxsoft/anima 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1260 -28
- package/dist/accounts-Bth3PpPD.js +260 -0
- package/dist/accounts-D8CPKNkN.js +259 -0
- package/dist/acp-cli-ByK6lS6c.js +1081 -0
- package/dist/acp-cli-CaQCjIw4.js +1084 -0
- package/dist/agent-BgIkqd3F.js +725 -0
- package/dist/agent-N5BDcge4.js +725 -0
- package/dist/agent-events-COH7NDW2.js +182 -0
- package/dist/agent-scope-CPphqq-U.js +452 -0
- package/dist/agent-scope-DZgptr9J.js +452 -0
- package/dist/agent-scope-cj2QCT6R.js +112 -0
- package/dist/agents-NEudYMdg.js +774 -0
- package/dist/agents.config-Bujs-NIy.js +182 -0
- package/dist/agents.config-jp7OLssr.js +182 -0
- package/dist/argv-BMZMiW7v.js +73 -0
- package/dist/audit-C-UJhfdv.js +2401 -0
- package/dist/audit-CeCO7SK5.js +2401 -0
- package/dist/auth-BNZsOHGF.js +648 -0
- package/dist/auth-DMPZWzEa.js +639 -0
- package/dist/auth-choice-5VnaGMD-.js +2681 -0
- package/dist/auth-choice-DA2k4vs8.js +2681 -0
- package/dist/auth-health-B7FqA26_.js +149 -0
- package/dist/auth-health-VO_MPqVX.js +149 -0
- package/dist/auth-profiles-BDrNYX_n.js +1564 -0
- package/dist/auth-profiles-CxSHydjn.js +2689 -0
- package/dist/banner-BtDZPRzi.js +294 -0
- package/dist/browser-cli-8yQMpxb8.js +1679 -0
- package/dist/browser-cli-Czg3JtDH.js +1676 -0
- package/dist/build-info.json +3 -3
- package/dist/bundled/boot-md/handler.js +16 -16
- package/dist/bundled/bootstrap-extra-files/handler.js +4 -4
- package/dist/bundled/command-logger/handler.js +1 -1
- package/dist/bundled/session-memory/handler.js +5 -5
- package/dist/call-BIzCaKZb.js +282 -0
- package/dist/call-BYDpTVCZ.js +282 -0
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/catalog-CqKiUgu6.js +185 -0
- package/dist/catalog-DMfEg-oK.js +185 -0
- package/dist/channel-options-BrtCtyrT.js +32 -0
- package/dist/channel-options-CO21Gl8p.js +33 -0
- package/dist/channel-selection-Bbm1lq3P.js +51 -0
- package/dist/channel-selection-CqcX7Ocw.js +51 -0
- package/dist/channel-web-DrsT6OAE.js +2162 -0
- package/dist/channels-cli-Juyh1S6n.js +1304 -0
- package/dist/channels-cli-zNvi1m5c.js +1306 -0
- package/dist/channels-status-issues-CqzqshW4.js +18 -0
- package/dist/channels-status-issues-DdJdO866.js +18 -0
- package/dist/chrome-C4dOMO8z.js +1601 -0
- package/dist/chrome-DdcDzAtH.js +1629 -0
- package/dist/chrome-U3DRzjJD.js +1601 -0
- package/dist/chunk-D2nLsrEW.js +348 -0
- package/dist/clack-prompter-BI3RDW5w.js +92 -0
- package/dist/clack-prompter-Dwr1m_IZ.js +92 -0
- package/dist/cli/daemon-cli.js +1 -1
- package/dist/cli-C3cpDaz8.js +99 -0
- package/dist/cli-CjWUGdGC.js +101 -0
- package/dist/cli-session-BVjY_XrW.js +5463 -0
- package/dist/cli-session-gtuYN2Iq.js +5408 -0
- package/dist/client-Dswwze5_.js +1692 -0
- package/dist/client-LRKFjo4A.js +1692 -0
- package/dist/clipboard-BZKS9O1u.js +31 -0
- package/dist/clipboard-DES8b1AM.js +31 -0
- package/dist/command-format-CP1YTNCl.js +52 -0
- package/dist/command-format-CVL4K5cj.js +52 -0
- package/dist/command-format-G6N2zghg.js +38 -0
- package/dist/command-registry-BBvNvysr.js +248 -0
- package/dist/commands-AZ3n8Y2c.js +726 -0
- package/dist/commands-BMnD_QRY.js +726 -0
- package/dist/commands-registry-cFqZ6Ib4.js +766 -0
- package/dist/commands-registry-q13H7ng5.js +766 -0
- package/dist/common-CX5458fH.js +287 -0
- package/dist/common-DJbnT8ws.js +287 -0
- package/dist/completion-cli-BADRBcIl.js +432 -0
- package/dist/completion-cli-DMQgiObF.js +431 -0
- package/dist/config-CU-Axg8P.js +5704 -0
- package/dist/config-DaqbUdkI.js +5705 -0
- package/dist/config-cli-BPlbwiuA.js +244 -0
- package/dist/config-cli-DXgZJkPU.js +247 -0
- package/dist/config-guard-Ba49JNds.js +76 -0
- package/dist/config-guard-Cu0qMKZJ.js +93 -0
- package/dist/config-kVVm5EYV.js +6523 -0
- package/dist/config-sync-CzLnLTXt.js +91 -0
- package/dist/config-sync-DuydxPWx.js +91 -0
- package/dist/configure-CHgacLyi.js +960 -0
- package/dist/configure-DfHXDa1L.js +959 -0
- package/dist/context-DzgXOckU.js +60 -0
- package/dist/control-service-8_wKHwBa.js +72 -0
- package/dist/control-service-BtL1Jto_.js +72 -0
- package/dist/cron-cli-BCzSR2c0.js +448 -0
- package/dist/cron-cli-CCWNkykU.js +451 -0
- package/dist/daemon-cli-Bjkbu9Vy.js +565 -0
- package/dist/daemon-cli-CmlHcC1J.js +566 -0
- package/dist/daemon-cli.js +16 -16
- package/dist/daemon-runtime-C0tz7VAC.js +460 -0
- package/dist/daemon-runtime-rUTqCVwJ.js +460 -0
- package/dist/deliver-BBggsviM.js +1097 -0
- package/dist/deliver-CePITOl8.js +1162 -0
- package/dist/deliver-DFnVaetP.js +1097 -0
- package/dist/delivery-queue-BJQK3oh5.js +220 -0
- package/dist/deps-CeEKhrp7.js +42 -0
- package/dist/devices-cli-DQrDMrZH.js +198 -0
- package/dist/devices-cli-Oe-A1Dv0.js +195 -0
- package/dist/diagnostics-DxMFrBLO.js +35 -0
- package/dist/diagnostics-m79ZlMmZ.js +35 -0
- package/dist/directory-cli-BL6h8cGF.js +246 -0
- package/dist/directory-cli-Cjgmi_sj.js +243 -0
- package/dist/dispatcher-DAFbQM-c.js +100 -0
- package/dist/dispatcher-DNd40gUn.js +100 -0
- package/dist/dist-CqDI82ei.js +929 -0
- package/dist/dist-DnHRxR5U.js +929 -0
- package/dist/dns-cli-CFtV3BXK.js +200 -0
- package/dist/dns-cli-NyIHvQ5S.js +197 -0
- package/dist/dock-BdXLb5oY.js +753 -0
- package/dist/dock-jYICmNcI.js +753 -0
- package/dist/docs-cli-CrOaIK_H.js +161 -0
- package/dist/docs-cli-D_cmJDSr.js +159 -0
- package/dist/doctor-BpGxKrBl.js +1815 -0
- package/dist/doctor-D12wNQPU.js +1813 -0
- package/dist/doctor-completion-DeOfofek.js +92 -0
- package/dist/doctor-completion-DwjqdEcK.js +92 -0
- package/dist/doctor-config-flow-BI3mpkbd.js +1232 -0
- package/dist/doctor-config-flow-wMHheFkC.js +1232 -0
- package/dist/engine-BCtL-AMw.js +563 -0
- package/dist/engine-Bk_UT413.js +563 -0
- package/dist/entry.js +5 -5
- package/dist/env-v6411I8h.js +32 -0
- package/dist/exec-B7sUS164.js +1167 -0
- package/dist/exec-approvals-CroGJRUg.js +1221 -0
- package/dist/exec-approvals-cli-BTxF_RsH.js +371 -0
- package/dist/exec-approvals-cli-n1gyGwH2.js +368 -0
- package/dist/exec-mhSykkaa.js +255 -0
- package/dist/extensionAPI.js +3 -3
- package/dist/frontmatter-BmHq0vRD.js +204 -0
- package/dist/gateway-cli-DDBadlrS.js +19971 -0
- package/dist/gateway-cli-IZNkOMBe.js +19972 -0
- package/dist/gateway-rpc-Dtx8HN-n.js +28 -0
- package/dist/gateway-rpc-L2PVSqGj.js +28 -0
- package/dist/github-copilot-auth-DKyqDaGU.js +1418 -0
- package/dist/github-copilot-auth-DXpOMSd3.js +1418 -0
- package/dist/gmail-setup-utils-BKNczIJ9.js +428 -0
- package/dist/gmail-setup-utils-co0ppccC.js +428 -0
- package/dist/health-Bm8ZTvC3.js +1253 -0
- package/dist/health-DUf1gt4E.js +1258 -0
- package/dist/health-format-BksT6F68.js +208 -0
- package/dist/health-format-uzh1xYLD.js +208 -0
- package/dist/heartbeat-visibility-1TJb1Zao.js +98 -0
- package/dist/heartbeat-visibility-CwodtdcX.js +98 -0
- package/dist/help-format-C6cv_aZp.js +17 -0
- package/dist/helpers-N-uSFKOn.js +10 -0
- package/dist/hooks-cli-1POsXqOl.js +993 -0
- package/dist/hooks-cli-BGjILbze.js +991 -0
- package/dist/hooks-status-DE07n5RC.js +356 -0
- package/dist/hooks-status-Du-d1jde.js +356 -0
- package/dist/image-ops-B_AYV3tp.js +541 -0
- package/dist/image-ops-Bp0C6Mvr.js +541 -0
- package/dist/index.js +82 -82
- package/dist/init-9A0s7bWG.js +122 -0
- package/dist/init-DoyCHJDC.js +122 -0
- package/dist/installs-D1C9wHAq.js +383 -0
- package/dist/installs-Dh4dHayM.js +383 -0
- package/dist/ipv4-DCItfaJo.js +1964 -0
- package/dist/ipv4-DSOUVx0i.js +1964 -0
- package/dist/lanes-BvSnHq2h.js +232 -0
- package/dist/lifecycle-core-BY4WIf9g.js +388 -0
- package/dist/lifecycle-core-TQKyXO-6.js +387 -0
- package/dist/links-CNu_8RZl.js +15 -0
- package/dist/links-D2tt2ouh.js +15 -0
- package/dist/llm-slug-generator.js +4 -4
- package/dist/logging-BIeRw0WR.js +15 -0
- package/dist/logging-C7lb3Vjc.js +15 -0
- package/dist/login-DXWKewA2.js +59 -0
- package/dist/login-Fhh4uWmf.js +61 -0
- package/dist/login-pPs3UO38.js +61 -0
- package/dist/login-qr-CevLD8cV.js +326 -0
- package/dist/login-qr-GF2JMIy-.js +323 -0
- package/dist/login-qr-ZYYKD6Yt.js +321 -0
- package/dist/logs-cli-CzXbX8HZ.js +242 -0
- package/dist/logs-cli-D9ngH9PF.js +245 -0
- package/dist/manager-BD5rA3w0.js +3244 -0
- package/dist/manager-BDPgBQSH.js +3246 -0
- package/dist/manager-DRWMWM--.js +3244 -0
- package/dist/manifest-registry-DbvPaBXY.js +748 -0
- package/dist/manifest-registry-kHX_MFa1.js +748 -0
- package/dist/markdown-tables-CqwihY2m.js +347 -0
- package/dist/markdown-tables-DJV7eAJZ.js +348 -0
- package/dist/media-lUqN-0O9.js +1342 -0
- package/dist/memory-cli-BLXSpgnN.js +868 -0
- package/dist/memory-cli-BcGVkkRJ.js +869 -0
- package/dist/message-channel-D_jIO87f.js +110 -0
- package/dist/migrate-BpVOar4L.js +157 -0
- package/dist/migrate-CkgGDkWy.js +157 -0
- package/dist/model-selection-Cqt6aJ0G.js +2691 -0
- package/dist/models-CExsNQPH.js +2510 -0
- package/dist/models-cli-Ba3Jmwev.js +2739 -0
- package/dist/models-cli-iDAlsbL2.js +258 -0
- package/dist/net-0A_zcaQD.js +218 -0
- package/dist/node-cli-ATmwCXIk.js +1319 -0
- package/dist/node-cli-DYFR_V25.js +1322 -0
- package/dist/node-service-CN4LqR1A.js +67 -0
- package/dist/node-service-CWt3MdSC.js +67 -0
- package/dist/nodes-cli-BeVmhTz3.js +1197 -0
- package/dist/nodes-cli-QeJIfa18.js +1200 -0
- package/dist/nodes-screen-DHyWAlla.js +234 -0
- package/dist/nodes-screen-qs3jRBPk.js +234 -0
- package/dist/note-CSlg2BnB.js +73 -0
- package/dist/note-Ctvglhp1.js +73 -0
- package/dist/npm-registry-spec-DQd4M22q.js +351 -0
- package/dist/npm-registry-spec-PxisIMts.js +351 -0
- package/dist/onboard-DeruD10m.js +1166 -0
- package/dist/onboard-SAcu5N6N.js +1165 -0
- package/dist/onboard-channels-C4iSfFXR.js +672 -0
- package/dist/onboard-channels-oVTVgoyg.js +672 -0
- package/dist/onboard-helpers-B8roRwLP.js +365 -0
- package/dist/onboard-helpers-Dgh26hgP.js +365 -0
- package/dist/onboarding-Bi-ac8we.js +911 -0
- package/dist/onboarding-C2gjB2u8.js +910 -0
- package/dist/orchestrator-DlbAYMQP.js +357 -0
- package/dist/orchestrator-DlwVRVDA.js +357 -0
- package/dist/outbound-CkKgc6iR.js +2062 -0
- package/dist/outbound-Vfm5yDh3.js +214 -0
- package/dist/outbound-bs_VK51X.js +214 -0
- package/dist/outbound-send-deps-DDjiMfEL.js +55 -0
- package/dist/pairing-cli-CJYeuEik.js +118 -0
- package/dist/pairing-cli-mqopHI8s.js +121 -0
- package/dist/pairing-store-BsXzUDPv.js +388 -0
- package/dist/pairing-store-DoNj00-X.js +388 -0
- package/dist/path-env-C_xpiG8l.js +89 -0
- package/dist/path-env-DSSMHu5A.js +89 -0
- package/dist/paths-B1vRVCad.js +126 -0
- package/dist/paths-BMuHNFxg.js +238 -0
- package/dist/paths-BXQQzXGQ.js +129 -0
- package/dist/paths-Buw_geoe.js +54 -0
- package/dist/paths-DA9WYabg.js +222 -0
- package/dist/paths-DfQGx0_k.js +129 -0
- package/dist/pi-auth-json-DOPW3e4X.js +78 -0
- package/dist/pi-auth-json-MruLmI_X.js +82 -0
- package/dist/pi-auth-json-lae_wwwo.js +80 -0
- package/dist/pi-model-discovery-7q0GxMrp.js +3 -0
- package/dist/pi-tools.policy-Csmla32P.js +200 -0
- package/dist/pi-tools.policy-xYdDLEv9.js +200 -0
- package/dist/plugin-auto-enable-CViVVWgg.js +282 -0
- package/dist/plugin-auto-enable-CjZ238UI.js +282 -0
- package/dist/plugin-registry-B4Aw2hzq.js +32 -0
- package/dist/plugin-registry-DW81arxW.js +32 -0
- package/dist/plugin-sdk/cli/cli-name.d.ts +1 -1
- package/dist/plugin-sdk/config/paths.d.ts +2 -2
- package/dist/plugin-sdk/index.js +7 -7
- package/dist/plugins-DhcGAPDB.js +38 -0
- package/dist/plugins-DtghNRtM.js +168 -0
- package/dist/plugins-cli-4vWTmOAb.js +736 -0
- package/dist/plugins-cli-CdTMbP0X.js +734 -0
- package/dist/polls-D6eCdatA.js +1343 -0
- package/dist/ports-BtZx-JKD.js +96 -0
- package/dist/ports-C8bKN8s0.js +96 -0
- package/dist/ports-DHiKnPRX.js +344 -0
- package/dist/ports-vd93M_Pt.js +317 -0
- package/dist/program-CX3aUVeb.js +176 -0
- package/dist/program-context-BPos0ivo.js +496 -0
- package/dist/progress-oiAjiiNi.js +133 -0
- package/dist/prompt-style-Cm4wOtKm.js +9 -0
- package/dist/pw-ai-4QbK5YFe.js +1865 -0
- package/dist/pw-ai-BWz3Cxt7.js +1868 -0
- package/dist/pw-ai-C83HBue2.js +1867 -0
- package/dist/qmd-manager-BcMeZiGD.js +938 -0
- package/dist/qmd-manager-CPypGJ0P.js +935 -0
- package/dist/qmd-manager-CRrSkfia.js +937 -0
- package/dist/register.agent-DDY8KJhn.js +265 -0
- package/dist/register.agent-DKawm-9d.js +1003 -0
- package/dist/register.anima-CEWUo29k.js +193 -0
- package/dist/register.anima-DBWz2rk_.js +193 -0
- package/dist/register.configure-BX67qV8k.js +103 -0
- package/dist/register.configure-CWsySuiq.js +101 -0
- package/dist/register.maintenance-0k-ZNhDg.js +543 -0
- package/dist/register.maintenance-BIwx1fzX.js +543 -0
- package/dist/register.message-CXPsoakA.js +657 -0
- package/dist/register.message-DA3jvfgI.js +660 -0
- package/dist/register.onboard-C4HG7Hqv.js +170 -0
- package/dist/register.onboard-GOpdif-j.js +170 -0
- package/dist/register.setup-B17vZT7C.js +175 -0
- package/dist/register.setup-GJyUDCqh.js +175 -0
- package/dist/register.status-health-sessions-D5876dGx.js +313 -0
- package/dist/register.status-health-sessions-lOewVIZR.js +142 -0
- package/dist/register.subclis-Dwnujj5C.js +255 -0
- package/dist/reply-CR5T_oQJ.js +32212 -0
- package/dist/reply-prefix-BcrS4Umd.js +100 -0
- package/dist/reply-prefix-Btb5o2NH.js +100 -0
- package/dist/reply-r089HuRA.js +32212 -0
- package/dist/routes-B4czFzIb.js +1820 -0
- package/dist/routes-ucJWAk5O.js +1820 -0
- package/dist/rpc-BnKxnQ0v.js +70 -0
- package/dist/rpc-DgE-xnyx.js +70 -0
- package/dist/run-main-B74kv84C.js +371 -0
- package/dist/runtime-guard-CKFdts2L.js +60 -0
- package/dist/sandbox-CJTS3er6.js +858 -0
- package/dist/sandbox-DBSiVHt_.js +859 -0
- package/dist/sandbox-cli-CrkjyU5M.js +461 -0
- package/dist/sandbox-cli-D1r5y6Sz.js +458 -0
- package/dist/security-cli-BZUdnkhn.js +462 -0
- package/dist/security-cli-DS09ebvA.js +465 -0
- package/dist/server-context-C0xZbYhg.js +824 -0
- package/dist/server-context-DVh2z7om.js +824 -0
- package/dist/server-node-events-bu9lpkMH.js +233 -0
- package/dist/server-node-events-i1Rrww31.js +231 -0
- package/dist/service-CJJwLEor.js +642 -0
- package/dist/service-DxLxBhaU.js +642 -0
- package/dist/service-audit-DB4Y3Ekp.js +488 -0
- package/dist/service-audit-M8y4TXVb.js +488 -0
- package/dist/session-CGxOLFs2.js +179 -0
- package/dist/session-DTTbdKb0.js +181 -0
- package/dist/session-cost-usage-FcdJl9c3.js +600 -0
- package/dist/session-cost-usage-qdfsGU2a.js +600 -0
- package/dist/session-yOhWcsD2.js +181 -0
- package/dist/sessions-B-Cu7JZq.js +1296 -0
- package/dist/sessions-BgLN4KFr.js +180 -0
- package/dist/sessions-CnRjwdVr.js +1296 -0
- package/dist/sessions-wRKla1Qh.js +2038 -0
- package/dist/shared-DS3UaJSP.js +66 -0
- package/dist/shared-DxNHzky3.js +77 -0
- package/dist/shared-Qpt4hUDi.js +66 -0
- package/dist/shared-kzrojZ1B.js +77 -0
- package/dist/skill-scanner-DLJji5Ye.js +263 -0
- package/dist/skills-BWFIEp4j.js +807 -0
- package/dist/skills-DV4zKdCx.js +808 -0
- package/dist/skills-cli-BY53ILm2.js +289 -0
- package/dist/skills-cli-CO3gxl8A.js +286 -0
- package/dist/skills-status-DX5pcqY3.js +166 -0
- package/dist/skills-status-zhcKzGkp.js +166 -0
- package/dist/sqlite-B6MojU1I.js +321 -0
- package/dist/sqlite-CuprTGR7.js +453 -0
- package/dist/sqlite-dzD-jMjs.js +368 -0
- package/dist/start-Cu3aLoSf.js +297 -0
- package/dist/start-Dz7tMAl8.js +296 -0
- package/dist/status-CaSxhxfV.js +2132 -0
- package/dist/status-D2C0JCX3.js +2137 -0
- package/dist/status-DlFMsQzh.js +27 -0
- package/dist/status-G0CITnKR.js +27 -0
- package/dist/status.update-CHjhVxJY.js +79 -0
- package/dist/status.update-DVFelehi.js +79 -0
- package/dist/subagent-registry-3Xb4el-8.js +14 -0
- package/dist/subagent-registry-CdSjz14I.js +2760 -0
- package/dist/subagent-registry-DNDhbHWi.js +2759 -0
- package/dist/subsystem-DfKstnEK.js +860 -0
- package/dist/system-cli-B5mt0FWa.js +82 -0
- package/dist/system-cli-Dg3UQ3Zz.js +79 -0
- package/dist/systemd-B43AvOGx.js +452 -0
- package/dist/systemd-RpPE0XGg.js +452 -0
- package/dist/systemd-hints-DMJT-Bbc.js +36 -0
- package/dist/systemd-hints-vRInKcz9.js +36 -0
- package/dist/systemd-linger-Dzyxqsod.js +75 -0
- package/dist/systemd-linger-EujbmI5A.js +75 -0
- package/dist/table-DhXHfRX2.js +279 -0
- package/dist/table-bWCLW-3P.js +279 -0
- package/dist/timeout-Ddn-5kAO.js +232 -0
- package/dist/tokens-3psI_Qk2.js +14 -0
- package/dist/tokens-BaM53PEx.js +14 -0
- package/dist/trash-Bmxs1Rnm.js +23 -0
- package/dist/trash-C39a6hKA.js +23 -0
- package/dist/tui-BHgBWhHE.js +3894 -0
- package/dist/tui-cli-B9Sq5-cC.js +50 -0
- package/dist/tui-cli-Dw7v4JoJ.js +47 -0
- package/dist/tui-mUwDwqvd.js +3894 -0
- package/dist/update-DF0GHG0j.js +317 -0
- package/dist/update-DoZLVjva.js +317 -0
- package/dist/update-check-Bt1dVPVN.js +400 -0
- package/dist/update-check-D5qAKes7.js +400 -0
- package/dist/update-cli-BNu2Oi7H.js +1105 -0
- package/dist/update-cli-D36AmALA.js +1105 -0
- package/dist/update-runner-CNQQaTwA.js +894 -0
- package/dist/update-runner-CvxZmbu-.js +894 -0
- package/dist/usage-BGCwNnjk.js +4516 -0
- package/dist/utils-DZ8pnOD5.js +243 -0
- package/dist/web-B5QG839O.js +46842 -0
- package/dist/web-Cmnvk9v0.js +2203 -0
- package/dist/web-Cv2KnTnL.js +63 -0
- package/dist/webhooks-cli-B6y89Pj_.js +319 -0
- package/dist/webhooks-cli-BDzHON4w.js +316 -0
- package/dist/whatsapp-actions-C_5MwVxM.js +45 -0
- package/dist/whatsapp-actions-hgYA12To.js +53 -0
- package/dist/whatsapp-actions-zTiVOoOV.js +49 -0
- package/dist/widearea-dns-BeIdnISJ.js +127 -0
- package/dist/widearea-dns-CF1gxpJ-.js +127 -0
- package/dist/workspace-DLna1IxR.js +649 -0
- package/dist/ws-log-Q4wO1Ztb.js +267 -0
- package/dist/ws-log-xF0kxDzp.js +267 -0
- package/package.json +1 -2
- package/dist/accounts-Cc5E4IDO.js +0 -260
- package/dist/accounts-CcVrwKqv.js +0 -259
- package/dist/acp-cli-DvphOKuh.js +0 -1081
- package/dist/acp-cli-p28pQ65a.js +0 -1084
- package/dist/agent-Cj7uDJaZ.js +0 -725
- package/dist/agent-Cuj9-2sT.js +0 -725
- package/dist/agent-events-BEBQsyE5.js +0 -182
- package/dist/agent-scope-BVf4aSwY.js +0 -112
- package/dist/agent-scope-OZi7lb8S.js +0 -452
- package/dist/agent-scope-V1bi9OYL.js +0 -452
- package/dist/agents-BUWqn_Ui.js +0 -774
- package/dist/agents.config-Dvo2ULxs.js +0 -182
- package/dist/agents.config-d6H0_3oj.js +0 -182
- package/dist/argv-DqUHKf0o.js +0 -73
- package/dist/audit-C6okOOSh.js +0 -2401
- package/dist/audit-VWjIdwC7.js +0 -2401
- package/dist/auth-91o2YM96.js +0 -648
- package/dist/auth-choice-CAmACV13.js +0 -2681
- package/dist/auth-choice-p3SeHPj2.js +0 -2681
- package/dist/auth-health-B_jXrWe6.js +0 -149
- package/dist/auth-health-DCicUKYR.js +0 -149
- package/dist/auth-lZ26wsbN.js +0 -639
- package/dist/auth-profiles-CCDD56dU.js +0 -1564
- package/dist/auth-profiles-DxI8L7bs.js +0 -2689
- package/dist/banner-Cohn04J6.js +0 -294
- package/dist/browser-cli-DANzjztE.js +0 -1676
- package/dist/browser-cli-WjsVH741.js +0 -1679
- package/dist/call-BAHvlu2G.js +0 -282
- package/dist/call-Ct7EGP_L.js +0 -282
- package/dist/catalog-BAayBt1L.js +0 -185
- package/dist/catalog-BNsf97BM.js +0 -185
- package/dist/channel-options-Dx9nPlX8.js +0 -33
- package/dist/channel-options-ZdvXrTGs.js +0 -32
- package/dist/channel-selection-CujyiWGM.js +0 -51
- package/dist/channel-selection-DfGpCyh2.js +0 -51
- package/dist/channel-web-CC0hkgkR.js +0 -2162
- package/dist/channels-cli-D7lNBpIb.js +0 -1304
- package/dist/channels-cli-DUPG8WDv.js +0 -1306
- package/dist/channels-status-issues-DBc1pU_R.js +0 -18
- package/dist/channels-status-issues-DjO9MHIG.js +0 -18
- package/dist/chrome-Bi6iZ5sG.js +0 -1601
- package/dist/chrome-DNSv7Cpy.js +0 -1629
- package/dist/chrome-DScZx4Lk.js +0 -1601
- package/dist/chunk-mxPVo000.js +0 -348
- package/dist/clack-prompter-B0kl7shw.js +0 -92
- package/dist/clack-prompter-B1YxZdRy.js +0 -92
- package/dist/cli-CfHUkOD0.js +0 -101
- package/dist/cli-ClMrIh6l.js +0 -99
- package/dist/cli-session-BkPTd9Pk.js +0 -5463
- package/dist/cli-session-Dd8DKb5a.js +0 -5408
- package/dist/client-C1avc0vD.js +0 -1692
- package/dist/client-CC94YZrT.js +0 -1692
- package/dist/clipboard-B2fBy8tG.js +0 -31
- package/dist/clipboard-BbGnZskJ.js +0 -31
- package/dist/command-format-Clp46jkj.js +0 -38
- package/dist/command-format-DELazozB.js +0 -52
- package/dist/command-format-SkzzRqR1.js +0 -52
- package/dist/command-registry-DZ4hkmA0.js +0 -248
- package/dist/commands-DtYZJSPn.js +0 -568
- package/dist/commands-Dujk1JmY.js +0 -568
- package/dist/commands-registry-Bd0xbvwG.js +0 -766
- package/dist/commands-registry-DYfRSVF3.js +0 -766
- package/dist/common-D6bu0zHC.js +0 -287
- package/dist/common-zW9Y2P1B.js +0 -287
- package/dist/completion-cli-tSe7Pmqm.js +0 -431
- package/dist/completion-cli-vn4IScs5.js +0 -432
- package/dist/config-C8rUDJXY.js +0 -5704
- package/dist/config-CLZ_XGVw.js +0 -6523
- package/dist/config-SY8M0kM_.js +0 -5705
- package/dist/config-cli-1V7D2Wsw.js +0 -247
- package/dist/config-cli-CjWEC81L.js +0 -244
- package/dist/config-guard-BW2gpKj_.js +0 -93
- package/dist/config-guard-BvxuzHpo.js +0 -76
- package/dist/config-sync-CoIIbEOe.js +0 -91
- package/dist/config-sync-DvAttep0.js +0 -91
- package/dist/configure-Bf0oupCE.js +0 -959
- package/dist/configure-DRM-7zFf.js +0 -960
- package/dist/context-D5iEFzv9.js +0 -60
- package/dist/control-service-C8m8F9pr.js +0 -72
- package/dist/control-service-DKotCWCg.js +0 -72
- package/dist/cron-cli-DB_FLYHD.js +0 -448
- package/dist/cron-cli-bxm5lrrO.js +0 -451
- package/dist/daemon-cli-1LsOnICv.js +0 -566
- package/dist/daemon-cli-CC2NrJ7a.js +0 -565
- package/dist/daemon-runtime-BXZhtBL9.js +0 -460
- package/dist/daemon-runtime-DW4USC7r.js +0 -460
- package/dist/deliver-B4HuPwJA.js +0 -1162
- package/dist/deliver-LiY5oL52.js +0 -1097
- package/dist/deliver-xrmk7xjh.js +0 -1097
- package/dist/delivery-queue-TnQykYsg.js +0 -220
- package/dist/deps-CMMOiOsF.js +0 -42
- package/dist/devices-cli-Be5he2SA.js +0 -195
- package/dist/devices-cli-z6ecoFe9.js +0 -198
- package/dist/diagnostics-Dj75aEHN.js +0 -35
- package/dist/diagnostics-DlIw6fqD.js +0 -35
- package/dist/directory-cli-CEy-0nxj.js +0 -243
- package/dist/directory-cli-DpzKcigr.js +0 -246
- package/dist/dispatcher-10Shiuz3.js +0 -100
- package/dist/dispatcher-3Jae6AiW.js +0 -100
- package/dist/dns-cli-Bat1pkc-.js +0 -200
- package/dist/dns-cli-NohNyEo0.js +0 -197
- package/dist/dock-DbxBBv30.js +0 -753
- package/dist/dock-cPBY4qGl.js +0 -753
- package/dist/docs-cli-BWp6p-Tq.js +0 -161
- package/dist/docs-cli-x22FnZfL.js +0 -159
- package/dist/doctor-BrT5m_on.js +0 -1815
- package/dist/doctor-Pp2HVnjM.js +0 -1813
- package/dist/doctor-completion-DNTimX9o.js +0 -92
- package/dist/doctor-completion-ylN9QAJ6.js +0 -92
- package/dist/doctor-config-flow-D1w3700T.js +0 -1232
- package/dist/doctor-config-flow-Dq50iE1R.js +0 -1232
- package/dist/engine-B9avUJL5.js +0 -563
- package/dist/engine-BiUQ25D4.js +0 -563
- package/dist/env-0lJfCPsw.js +0 -32
- package/dist/exec-BenD3A5l.js +0 -1167
- package/dist/exec-Bv3pyjeM.js +0 -255
- package/dist/exec-approvals-CdLmKX2R.js +0 -1221
- package/dist/exec-approvals-cli-DXfV6G8H.js +0 -368
- package/dist/exec-approvals-cli-J2cZs10o.js +0 -371
- package/dist/frontmatter-YijVi0FQ.js +0 -204
- package/dist/gateway-cli-DOAbA0pc.js +0 -19972
- package/dist/gateway-cli-QpWtBhQy.js +0 -19971
- package/dist/gateway-rpc-DJKBil9s.js +0 -28
- package/dist/gateway-rpc-DVterpLP.js +0 -28
- package/dist/github-copilot-auth-4IUFp669.js +0 -1418
- package/dist/github-copilot-auth-C9E0IROs.js +0 -1418
- package/dist/gmail-setup-utils-BPo_LkKI.js +0 -428
- package/dist/gmail-setup-utils-D3Yqgor7.js +0 -428
- package/dist/health-BeZnqp6m.js +0 -1258
- package/dist/health-Cn2OoVWZ.js +0 -1253
- package/dist/health-format-CdP99j3Y.js +0 -208
- package/dist/health-format-JEChH08S.js +0 -208
- package/dist/heartbeat-visibility-BL3WAchI.js +0 -98
- package/dist/heartbeat-visibility-CQ9QimI7.js +0 -98
- package/dist/help-format-Dl4bsrLI.js +0 -17
- package/dist/helpers-ZKNRexvX.js +0 -10
- package/dist/hooks-cli-D99hXt7K.js +0 -991
- package/dist/hooks-cli-DMB8RiEO.js +0 -993
- package/dist/hooks-status-B-e96dZj.js +0 -356
- package/dist/hooks-status-C_9sE0ox.js +0 -356
- package/dist/image-ops-Dlt3T7th.js +0 -541
- package/dist/image-ops-omlvdfah.js +0 -541
- package/dist/init-Bm04RagW.js +0 -122
- package/dist/init-CaJBf4p1.js +0 -122
- package/dist/installs-C2iMRBVz.js +0 -383
- package/dist/installs-D-cPGdCw.js +0 -383
- package/dist/ipv4-Bf7NS3QU.js +0 -1964
- package/dist/ipv4-wWNs8IH_.js +0 -1964
- package/dist/lanes-CNxj3tit.js +0 -232
- package/dist/lifecycle-core-B_7XRcvF.js +0 -388
- package/dist/lifecycle-core-By83PVAK.js +0 -387
- package/dist/links-BfjHVTB_.js +0 -15
- package/dist/links-DPGe0OHw.js +0 -15
- package/dist/logging-DB6BQmhi.js +0 -15
- package/dist/logging-mcb66J0p.js +0 -15
- package/dist/login-BDCg6D0N.js +0 -61
- package/dist/login-BDfnbjnZ.js +0 -59
- package/dist/login-BqH1itcg.js +0 -61
- package/dist/login-qr-CyOw3R4r.js +0 -321
- package/dist/login-qr-D8ECtb72.js +0 -323
- package/dist/login-qr-RnR7e4Bw.js +0 -326
- package/dist/logs-cli--j89L74J.js +0 -245
- package/dist/logs-cli-DpEMg_Gq.js +0 -242
- package/dist/manager-B4OyvcxT.js +0 -3244
- package/dist/manager-Cqc1CeH7.js +0 -3246
- package/dist/manager-DUyQPFvj.js +0 -3244
- package/dist/manifest-registry-CW1zCyRF.js +0 -748
- package/dist/manifest-registry-D4lM2RdV.js +0 -748
- package/dist/markdown-tables-BT1X6jqH.js +0 -347
- package/dist/markdown-tables-DHgOK2vI.js +0 -348
- package/dist/media-THyainiE.js +0 -1342
- package/dist/memory-cli-BKocCWXM.js +0 -868
- package/dist/memory-cli-Jmma-xI_.js +0 -869
- package/dist/message-channel-dSTVVCyX.js +0 -110
- package/dist/migrate-BR6iAIjO.js +0 -157
- package/dist/migrate-D0EcMs0f.js +0 -157
- package/dist/model-selection-YcSr9CgC.js +0 -2691
- package/dist/models-1vUQBVfw.js +0 -2510
- package/dist/models-cli-BK3BwUhL.js +0 -2739
- package/dist/models-cli-DECrM8oA.js +0 -258
- package/dist/net-B5lXhYLV.js +0 -218
- package/dist/node-cli-cLHUNpPD.js +0 -1319
- package/dist/node-cli-fO7Y132S.js +0 -1322
- package/dist/node-service-BFxHJsno.js +0 -67
- package/dist/node-service-DUnan4uK.js +0 -67
- package/dist/nodes-cli-BCq35E6N.js +0 -1200
- package/dist/nodes-cli-vD7MwAKP.js +0 -1197
- package/dist/nodes-screen-1YiLkqr5.js +0 -234
- package/dist/nodes-screen-DZeD8hE5.js +0 -234
- package/dist/note-Bi8Wb8DV.js +0 -73
- package/dist/note-uiuPxhyX.js +0 -73
- package/dist/npm-registry-spec-B-XIShkB.js +0 -351
- package/dist/npm-registry-spec-za3itb5Y.js +0 -351
- package/dist/onboard-Ds6w_sWo.js +0 -1165
- package/dist/onboard-SAVx3bp4.js +0 -1166
- package/dist/onboard-channels-Cg_EkBa4.js +0 -672
- package/dist/onboard-channels-D7NbA55V.js +0 -672
- package/dist/onboard-helpers-DO_hgZb9.js +0 -365
- package/dist/onboard-helpers-_XgJgeqh.js +0 -365
- package/dist/onboarding-3hLmDd0r.js +0 -911
- package/dist/onboarding-B4LKLsbU.js +0 -910
- package/dist/orchestrator-BKzmyBWy.js +0 -357
- package/dist/orchestrator-BN3QCz2s.js +0 -357
- package/dist/outbound-BgA9hNlP.js +0 -2062
- package/dist/outbound-CjdvVhUI.js +0 -214
- package/dist/outbound-DOGe6qb2.js +0 -214
- package/dist/outbound-send-deps-Du5aBpd7.js +0 -55
- package/dist/pairing-cli-2vnyg_Nd.js +0 -118
- package/dist/pairing-cli-BH1KQtNV.js +0 -121
- package/dist/pairing-store-DJz_9Gv0.js +0 -388
- package/dist/pairing-store-DmOzxcuk.js +0 -388
- package/dist/path-env-Bu6k0jDQ.js +0 -89
- package/dist/path-env-C0zQSjw8.js +0 -89
- package/dist/paths-BTc4nk-6.js +0 -126
- package/dist/paths-BgUi2Z2G.js +0 -54
- package/dist/paths-C6VCWKo3.js +0 -238
- package/dist/paths-CCxa0o9c.js +0 -222
- package/dist/paths-CxRf2rBG.js +0 -129
- package/dist/paths-hcX1Gqg5.js +0 -129
- package/dist/pi-auth-json-B68R7q7_.js +0 -82
- package/dist/pi-auth-json-CR0jXAgq.js +0 -78
- package/dist/pi-auth-json-ZYzi3nxs.js +0 -80
- package/dist/pi-model-discovery-Cxs4pvC2.js +0 -3
- package/dist/pi-tools.policy-D81U5xy0.js +0 -200
- package/dist/pi-tools.policy-DSHkkb5b.js +0 -200
- package/dist/plugin-auto-enable-CxF4bpDN.js +0 -282
- package/dist/plugin-auto-enable-jNaAeyEh.js +0 -282
- package/dist/plugin-registry-C7XWotZG.js +0 -32
- package/dist/plugin-registry-DcUCbGax.js +0 -32
- package/dist/plugins-B362e77G.js +0 -168
- package/dist/plugins-CmSUIUNi.js +0 -38
- package/dist/plugins-cli-BsCEnoQ7.js +0 -734
- package/dist/plugins-cli-QSIsMUG7.js +0 -736
- package/dist/polls-CItfB1H8.js +0 -1343
- package/dist/ports-BVLMN1Sr.js +0 -96
- package/dist/ports-CqLSlU6Z.js +0 -317
- package/dist/ports-D94CwCrv.js +0 -344
- package/dist/ports-D_NHthOz.js +0 -96
- package/dist/program-DkJHjI0R.js +0 -176
- package/dist/program-context-DnyGM2SC.js +0 -496
- package/dist/progress-Bek_GyWS.js +0 -133
- package/dist/prompt-style-lu0clOOE.js +0 -9
- package/dist/pw-ai-BLVMuSLv.js +0 -1867
- package/dist/pw-ai-DZJWEF_f.js +0 -1865
- package/dist/pw-ai-dzf-ptcn.js +0 -1868
- package/dist/qmd-manager-Cur_Ekn0.js +0 -937
- package/dist/qmd-manager-DNAUuwjK.js +0 -938
- package/dist/qmd-manager-DepEoASu.js +0 -935
- package/dist/register.agent-CSWvzOkR.js +0 -265
- package/dist/register.agent-UeH2NXmH.js +0 -1003
- package/dist/register.anima-DOdee0dh.js +0 -193
- package/dist/register.anima-HHDWsz6r.js +0 -193
- package/dist/register.configure-CSJFxdz9.js +0 -103
- package/dist/register.configure-D84Fvcz4.js +0 -101
- package/dist/register.maintenance-B3pvNbZb.js +0 -543
- package/dist/register.maintenance-BKVOwkw6.js +0 -543
- package/dist/register.message-BAO6CPl2.js +0 -657
- package/dist/register.message-OXoOKE_6.js +0 -660
- package/dist/register.onboard-BK_ixVmD.js +0 -170
- package/dist/register.onboard-cfCaPx6j.js +0 -170
- package/dist/register.setup-BGfDnzph.js +0 -175
- package/dist/register.setup-Y-Q74M-0.js +0 -175
- package/dist/register.status-health-sessions-CT14eitH.js +0 -142
- package/dist/register.status-health-sessions-TfZMzAUn.js +0 -313
- package/dist/register.subclis-BZwdlNHC.js +0 -255
- package/dist/reply-mlsExaZm.js +0 -32212
- package/dist/reply-prefix-B0CfR4bM.js +0 -100
- package/dist/reply-prefix-w4a39ybC.js +0 -100
- package/dist/reply-qalRISe_.js +0 -32212
- package/dist/routes-CENsHJyg.js +0 -1820
- package/dist/routes-DO0HqW2e.js +0 -1820
- package/dist/rpc-C0pjNhBi.js +0 -70
- package/dist/rpc-DZ44PIXE.js +0 -70
- package/dist/run-main-BMpKw8Mp.js +0 -371
- package/dist/runtime-guard-BSUFiAQV.js +0 -60
- package/dist/sandbox-BIGfMYEI.js +0 -858
- package/dist/sandbox-DxP3IpUP.js +0 -859
- package/dist/sandbox-cli-DtLGH8sL.js +0 -461
- package/dist/sandbox-cli-_Tg7lfJ_.js +0 -458
- package/dist/security-cli-BRwgbedo.js +0 -462
- package/dist/security-cli-D3bSuyZt.js +0 -465
- package/dist/server-context-49XFFxFg.js +0 -824
- package/dist/server-context-LrlgrZzS.js +0 -824
- package/dist/server-node-events-Dm52i7NW.js +0 -231
- package/dist/server-node-events-QX523UyF.js +0 -233
- package/dist/service-BNVpYcQe.js +0 -642
- package/dist/service-D56aMXUB.js +0 -642
- package/dist/service-audit-D0X_XAB2.js +0 -488
- package/dist/service-audit-qmf6XMmP.js +0 -488
- package/dist/session-CrQQLLhx.js +0 -179
- package/dist/session-LocsOOWJ.js +0 -181
- package/dist/session-Vlce2BAT.js +0 -181
- package/dist/session-cost-usage-BwiTZuKl.js +0 -600
- package/dist/session-cost-usage-DT9YNXTJ.js +0 -600
- package/dist/sessions-BfV53TbG.js +0 -1296
- package/dist/sessions-BimpX_km.js +0 -180
- package/dist/sessions-DcXpzig0.js +0 -1296
- package/dist/sessions-Wd18dukK.js +0 -2038
- package/dist/shared-Bsr69u_7.js +0 -77
- package/dist/shared-Cgly1vPb.js +0 -66
- package/dist/shared-JOo05hST.js +0 -66
- package/dist/shared-f7dvQsi7.js +0 -77
- package/dist/skill-scanner-CkaVLABv.js +0 -263
- package/dist/skills-B-G7UHOa.js +0 -808
- package/dist/skills-B5LQx4lT.js +0 -807
- package/dist/skills-cli-DUGe2ZWW.js +0 -286
- package/dist/skills-cli-DtOk0bvK.js +0 -289
- package/dist/skills-status-Clq9ZnYu.js +0 -166
- package/dist/skills-status-JQluhU-P.js +0 -166
- package/dist/sqlite-BukcjdJa.js +0 -321
- package/dist/sqlite-CGcOZZ0C.js +0 -368
- package/dist/sqlite-Ck6f9KWc.js +0 -453
- package/dist/start--xmSFepB.js +0 -372
- package/dist/start-BdlZbqrr.js +0 -371
- package/dist/status-BgoeFm6g.js +0 -2137
- package/dist/status-BjjDrUq7.js +0 -27
- package/dist/status-Ct0DgOZ-.js +0 -2132
- package/dist/status-RA_uNmK0.js +0 -27
- package/dist/status.update-BjOH3GlS.js +0 -79
- package/dist/status.update-DLU1qBf0.js +0 -79
- package/dist/subagent-registry-9RLdKxES.js +0 -2760
- package/dist/subagent-registry-Byuex3zp.js +0 -2759
- package/dist/subagent-registry-DOBunBYS.js +0 -14
- package/dist/subsystem-Dowf8fSU.js +0 -860
- package/dist/system-cli-C5oBpzni.js +0 -79
- package/dist/system-cli-DXNKD_Id.js +0 -82
- package/dist/systemd-BSrHDyeU.js +0 -452
- package/dist/systemd-By5xdSB4.js +0 -452
- package/dist/systemd-hints-BtjL_5Rh.js +0 -36
- package/dist/systemd-hints-sJmr6cjb.js +0 -36
- package/dist/systemd-linger-CTmV2Gci.js +0 -75
- package/dist/systemd-linger-CmyqQkeC.js +0 -75
- package/dist/table-BL0lJzsm.js +0 -279
- package/dist/table-DoiRPsn0.js +0 -279
- package/dist/timeout-CswI_K-U.js +0 -232
- package/dist/tokens-C-X7wDKj.js +0 -14
- package/dist/tokens-DkvqA72p.js +0 -14
- package/dist/trash-BJLK1vMn.js +0 -23
- package/dist/trash-_x5UZ94k.js +0 -23
- package/dist/tui-BHjxDFZC.js +0 -3894
- package/dist/tui-CgOocwN8.js +0 -3894
- package/dist/tui-cli-5ANH8dE5.js +0 -47
- package/dist/tui-cli-BQ4P-JW_.js +0 -50
- package/dist/update-LFgxHHPd.js +0 -317
- package/dist/update-TxptCqk7.js +0 -317
- package/dist/update-check-CWc7YXmc.js +0 -400
- package/dist/update-check-IhlWaui6.js +0 -400
- package/dist/update-cli-PtXU62w7.js +0 -1105
- package/dist/update-cli-Va0EtETG.js +0 -1105
- package/dist/update-runner-BLeKFkiB.js +0 -894
- package/dist/update-runner-Iuzpc-_y.js +0 -894
- package/dist/usage-ApGvBLVg.js +0 -4516
- package/dist/utils-Bsw__U-F.js +0 -243
- package/dist/web-B6_Ky60G.js +0 -63
- package/dist/web-EZLQEWXY.js +0 -46842
- package/dist/web-pec8YJUX.js +0 -2203
- package/dist/webhooks-cli-BYQKTHTp.js +0 -319
- package/dist/webhooks-cli-C2_xtsUQ.js +0 -316
- package/dist/whatsapp-actions-C72VCq8f.js +0 -49
- package/dist/whatsapp-actions-Ck9Uv0Nw.js +0 -45
- package/dist/whatsapp-actions-D0reTj2k.js +0 -53
- package/dist/widearea-dns-B6ocX23x.js +0 -127
- package/dist/widearea-dns-NsEUNYwz.js +0 -127
- package/dist/workspace-Dcfoy5JJ.js +0 -649
- package/dist/ws-log-N8R5MvGE.js +0 -267
- package/dist/ws-log-gwFxPxj5.js +0 -267
- /package/dist/{auto-update-CUeF99gI.js → auto-update-CpF0fycd.js} +0 -0
- /package/dist/{auto-update-cgkp9ZTJ.js → auto-update-DNWdO7uF.js} +0 -0
- /package/dist/{brew-CVZkr0GU.js → brew-nqf_MiE4.js} +0 -0
- /package/dist/{budget-DxYQSekw.js → budget-CPedI-qW.js} +0 -0
- /package/dist/{budget-BWBp8Res.js → budget-CRpvqDRX.js} +0 -0
- /package/dist/{cli-utils-DtAxdCte.js → cli-utils-C1YHVD4o.js} +0 -0
- /package/dist/{command-options-CSbuuqHr.js → command-options-BbponVnw.js} +0 -0
- /package/dist/{command-options-Cp1tf96a.js → command-options-s0gnvXnS.js} +0 -0
- /package/dist/{constants-O8yBqCBv.js → constants-Dhb6zSIV.js} +0 -0
- /package/dist/{dangerous-tools-5ObDWy1N.js → dangerous-tools-DGTtJ_JR.js} +0 -0
- /package/dist/{dangerous-tools-Jwr7jqNw.js → dangerous-tools-DxrfTOfT.js} +0 -0
- /package/dist/{delivery-queue-B6IHz4Ry.js → delivery-queue-Bxm0nzw7.js} +0 -0
- /package/dist/{display-BDOsXu8F.js → display-Jy3UdGzA.js} +0 -0
- /package/dist/{errors-CHow2wtt.js → errors-CKaCqKga.js} +0 -0
- /package/dist/{exec-BizYYQgP.js → exec-DDmuVVNq.js} +0 -0
- /package/dist/{format-Mq6iU0_5.js → format-ByEjgyTF.js} +0 -0
- /package/dist/{format-duration-DhWzz_5b.js → format-duration-Aaj5tjJd.js} +0 -0
- /package/dist/{format-relative-C6kUHuOj.js → format-relative-79_Y1n2Y.js} +0 -0
- /package/dist/{help-format-DUBI91Ti.js → help-format-BMKzarov.js} +0 -0
- /package/dist/{helpers-eJFa4K6r.js → helpers-DpEB9Mh0.js} +0 -0
- /package/dist/{helpers-DLgbkcEn.js → helpers-FMld9sBT.js} +0 -0
- /package/dist/{input-provenance-DJBdpeKk.js → input-provenance-Cy_KnBlP.js} +0 -0
- /package/dist/{is-main-Dt9DTcH1.js → is-main-yjaVwMtJ.js} +0 -0
- /package/dist/{loader-l2OBdJ8x.js → loader-Br7Vr0zn.js} +0 -0
- /package/dist/{loader-BoYxRfcW.js → loader-CkmOrXcC.js} +0 -0
- /package/dist/{logging-BdnOSVPD.js → logging-CY-Q5cwf.js} +0 -0
- /package/dist/{message-channel-w4F2b2F6.js → message-channel-dua8OOGJ.js} +0 -0
- /package/dist/{mime-B1ZoR53M.js → mime-CBg4KybI.js} +0 -0
- /package/dist/{model-param-b-DPwyNGn8.js → model-param-b-DW9f0NN8.js} +0 -0
- /package/dist/{node-match-8XZnaid6.js → node-match-BV8bTBd4.js} +0 -0
- /package/dist/{normalize-GDK8JTNW.js → normalize-_lmlBOW9.js} +0 -0
- /package/dist/{openclaw-root-C85WMnVV.js → openclaw-root-JPvmPTf7.js} +0 -0
- /package/dist/{outbound-send-deps-ANnAhImn.js → outbound-send-deps-BfUvuWGa.js} +0 -0
- /package/dist/{parse-6-2MDhdT.js → parse-CZRwKocn.js} +0 -0
- /package/dist/{parse-log-line-Bqh1SSzC.js → parse-log-line-CvrZEK6A.js} +0 -0
- /package/dist/{parse-log-line-DUZCjXbl.js → parse-log-line-mLdat0AH.js} +0 -0
- /package/dist/{parse-port-BKB9Exlg.js → parse-port-BSOOdo7I.js} +0 -0
- /package/dist/{parse-port-DrfvwwiL.js → parse-port-Y0NK62x1.js} +0 -0
- /package/dist/{parse-timeout-Di_tcEmi.js → parse-timeout-DVPQ3n9j.js} +0 -0
- /package/dist/{paths-DcVEkYX5.js → paths-DHjlJ6cn.js} +0 -0
- /package/dist/{pi-model-discovery-DsRqYJLy.js → pi-model-discovery-DzEIEgHL.js} +0 -0
- /package/dist/{plugins-CDJw924T.js → plugins-D6PBOdkn.js} +0 -0
- /package/dist/{program-context-Bvn8046-.js → program-context-Q1hkT73c.js} +0 -0
- /package/dist/{progress-CbZ2D53A.js → progress-C9Ha1NJh.js} +0 -0
- /package/dist/{prompt-style-DKy6qQxR.js → prompt-style-DQi8j03a.js} +0 -0
- /package/dist/{prompts-BI__va99.js → prompts-BEHxUC3w.js} +0 -0
- /package/dist/{prompts-_dDWkCAz.js → prompts-CSOhuiqe.js} +0 -0
- /package/dist/{queue-D_u34pbL.js → queue-BJGo7kAB.js} +0 -0
- /package/dist/{queue-PG591iID.js → queue-DYgUbdoq.js} +0 -0
- /package/dist/{redact-ClVwO7Nn.js → redact-CyKvdFrg.js} +0 -0
- /package/dist/{registry-Bs_DJK9E.js → registry-C5MAYD4V.js} +0 -0
- /package/dist/{registry-D_zlP1U-.js → registry-CRrXXVs0.js} +0 -0
- /package/dist/{requirements-BzZxj2Wu.js → requirements-CGkxTCu4.js} +0 -0
- /package/dist/{requirements-DIW1svgA.js → requirements-CIDaOcbO.js} +0 -0
- /package/dist/{runtime-guard-DeOXA_86.js → runtime-guard-nL3Lp8T-.js} +0 -0
- /package/dist/{secret-equal-Dghy3xsA.js → secret-equal-DJpmLXlG.js} +0 -0
- /package/dist/{send-BhAfdGII.js → send-CTcxgDDU.js} +0 -0
- /package/dist/{send-ga9udK1_.js → send-DPezUR3-.js} +0 -0
- /package/dist/{send-C2t9xpXI.js → send-DZQTaG7-.js} +0 -0
- /package/dist/{send-DigO-i9j.js → send-VDff2gra.js} +0 -0
- /package/dist/{send-Dz2BDHll.js → send-bgQNV8d1.js} +0 -0
- /package/dist/{session-key-BGiG_JcT.js → session-key-CQT-NR6w.js} +0 -0
- /package/dist/{shell-argv-CAq1mLa2.js → shell-argv-n9IueeJQ.js} +0 -0
- /package/dist/{skill-scanner-Coo4QoCd.js → skill-scanner-o6NgVMD9.js} +0 -0
- /package/dist/{status-CMnlcBVc.js → status-C53kTIXF.js} +0 -0
- /package/dist/{status-tDZPwewW.js → status-CZDDA_Sy.js} +0 -0
- /package/dist/{system-run-command-X9lDJIy0.js → system-run-command-BCjUffN9.js} +0 -0
- /package/dist/{system-run-command-DGk7dwQP.js → system-run-command-CqAqKL9K.js} +0 -0
- /package/dist/{tailnet-CuiNECdL.js → tailnet-Ciwjv243.js} +0 -0
- /package/dist/{templates-CeYJjVzw.js → templates-37RKpACb.js} +0 -0
- /package/dist/{templates-I3Z0xplD.js → templates-DPalk30o.js} +0 -0
- /package/dist/{thinking-BXEswx1X.js → thinking-2hxwmvTl.js} +0 -0
- /package/dist/{transcript-events-C1hdue6u.js → transcript-events-Bp7fGnwv.js} +0 -0
- /package/dist/{transcript-tools-DuyYOkUq.js → transcript-tools-D4Lbxlka.js} +0 -0
- /package/dist/{usage-format-BAirWUSO.js → usage-format-6Uar63S0.js} +0 -0
- /package/dist/{utils-C9sj30YY.js → utils-DT8uXjFS.js} +0 -0
- /package/dist/{wsl-CqyuRvtM.js → wsl-CrPvx2kZ.js} +0 -0
- /package/dist/{wsl-ymJYvc9Q.js → wsl-UvJ5dHah.js} +0 -0
package/dist/usage-ApGvBLVg.js
DELETED
|
@@ -1,4516 +0,0 @@
|
|
|
1
|
-
import { E as resolveAgentIdFromSessionKey, M as parseAgentSessionKey, S as classifySessionKeyShape, _ as DEFAULT_AGENT_ID, f as loadWorkspaceBootstrapFiles, h as resolveAnimaPackageRootSync, m as resolveAnimaPackageRoot, u as filterBootstrapFilesForSession, w as normalizeAgentId } from "./workspace-Dcfoy5JJ.js";
|
|
2
|
-
import { M as isRecord, Y as logVerbose, Z as shouldLogVerbose, k as escapeRegExp, l as createSubsystemLogger, n as runExec, t as runCommandWithTimeout, w as CONFIG_DIR, z as resolveUserPath } from "./exec-BenD3A5l.js";
|
|
3
|
-
import { c as resolveDefaultAgentId, s as resolveAgentWorkspaceDir, u as resolveSessionAgentIds } from "./agent-scope-BVf4aSwY.js";
|
|
4
|
-
import { t as formatCliCommand } from "./command-format-SkzzRqR1.js";
|
|
5
|
-
import { h as resolveMemorySlotDecision, m as resolveEnableState, n as loadConfig, p as normalizePluginsConfig, u as loadPluginManifestRegistry } from "./config-CLZ_XGVw.js";
|
|
6
|
-
import { R as normalizeChatType, V as SILENT_REPLY_TOKEN, c as updateSessionStore, u as deliveryContextFromSession } from "./sessions-Wd18dukK.js";
|
|
7
|
-
import { E as requireApiKey, I as isTruthyEnvValue, R as DEFAULT_MODEL, S as resolveModelRefFromString, _ as normalizeModelRef, b as resolveConfiguredModelRef, c as resolveAnimaAgentDir, g as modelKey, m as buildModelAliasIndex, n as resolveAuthProfileOrder, o as ensureAuthProfileStore, p as buildConfiguredAllowlistKeys, r as isProfileInCooldown, v as normalizeProviderId$1, w as getApiKeyForModel, x as resolveDefaultModelForAgent, z as DEFAULT_PROVIDER } from "./auth-profiles-CCDD56dU.js";
|
|
8
|
-
import { _ as listDeliverableMessageChannels, f as INTERNAL_MESSAGE_CHANNEL, p as isDeliverableMessageChannel, r as normalizeChannelId, t as getChannelPlugin, v as normalizeMessageChannel } from "./plugins-B362e77G.js";
|
|
9
|
-
import { l as resolveHeartbeatPrompt } from "./agent-events-BEBQsyE5.js";
|
|
10
|
-
import { i as triggerInternalHook, t as createInternalHookEvent } from "./internal-hooks-DFTIurVM.js";
|
|
11
|
-
import { r as getFileExtension, s as normalizeMimeType } from "./mime-Bm1xTtpY.js";
|
|
12
|
-
import { a as parseFrontmatterBlock, c as resolveRuntimePlatform, i as resolveAnimaManifestBlock, n as normalizeStringList, o as hasBinary, r as parseFrontmatterBool, s as isConfigPathTruthyWithDefaults, t as getFrontmatterString } from "./frontmatter-YijVi0FQ.js";
|
|
13
|
-
import fs from "node:fs/promises";
|
|
14
|
-
import os, { tmpdir } from "node:os";
|
|
15
|
-
import path from "node:path";
|
|
16
|
-
import fs$1, { existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
17
|
-
import { execSync, spawn } from "node:child_process";
|
|
18
|
-
import { fileURLToPath } from "node:url";
|
|
19
|
-
import crypto, { randomUUID } from "node:crypto";
|
|
20
|
-
import { completeSimple } from "@mariozechner/pi-ai";
|
|
21
|
-
import { formatSkillsForPrompt, loadSkillsFromDir } from "@mariozechner/pi-coding-agent";
|
|
22
|
-
import { EdgeTTS } from "node-edge-tts";
|
|
23
|
-
import chokidar from "chokidar";
|
|
24
|
-
|
|
25
|
-
//#region src/agents/auth-profiles/session-override.ts
|
|
26
|
-
function isProfileForProvider(params) {
|
|
27
|
-
const entry = params.store.profiles[params.profileId];
|
|
28
|
-
if (!entry?.provider) return false;
|
|
29
|
-
return normalizeProviderId$1(entry.provider) === normalizeProviderId$1(params.provider);
|
|
30
|
-
}
|
|
31
|
-
async function clearSessionAuthProfileOverride(params) {
|
|
32
|
-
const { sessionEntry, sessionStore, sessionKey, storePath } = params;
|
|
33
|
-
delete sessionEntry.authProfileOverride;
|
|
34
|
-
delete sessionEntry.authProfileOverrideSource;
|
|
35
|
-
delete sessionEntry.authProfileOverrideCompactionCount;
|
|
36
|
-
sessionEntry.updatedAt = Date.now();
|
|
37
|
-
sessionStore[sessionKey] = sessionEntry;
|
|
38
|
-
if (storePath) await updateSessionStore(storePath, (store) => {
|
|
39
|
-
store[sessionKey] = sessionEntry;
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
async function resolveSessionAuthProfileOverride(params) {
|
|
43
|
-
const { cfg, provider, agentDir, sessionEntry, sessionStore, sessionKey, storePath, isNewSession } = params;
|
|
44
|
-
if (!sessionEntry || !sessionStore || !sessionKey) return sessionEntry?.authProfileOverride;
|
|
45
|
-
const store = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false });
|
|
46
|
-
const order = resolveAuthProfileOrder({
|
|
47
|
-
cfg,
|
|
48
|
-
store,
|
|
49
|
-
provider
|
|
50
|
-
});
|
|
51
|
-
let current = sessionEntry.authProfileOverride?.trim();
|
|
52
|
-
if (current && !store.profiles[current]) {
|
|
53
|
-
await clearSessionAuthProfileOverride({
|
|
54
|
-
sessionEntry,
|
|
55
|
-
sessionStore,
|
|
56
|
-
sessionKey,
|
|
57
|
-
storePath
|
|
58
|
-
});
|
|
59
|
-
current = void 0;
|
|
60
|
-
}
|
|
61
|
-
if (current && !isProfileForProvider({
|
|
62
|
-
provider,
|
|
63
|
-
profileId: current,
|
|
64
|
-
store
|
|
65
|
-
})) {
|
|
66
|
-
await clearSessionAuthProfileOverride({
|
|
67
|
-
sessionEntry,
|
|
68
|
-
sessionStore,
|
|
69
|
-
sessionKey,
|
|
70
|
-
storePath
|
|
71
|
-
});
|
|
72
|
-
current = void 0;
|
|
73
|
-
}
|
|
74
|
-
if (current && order.length > 0 && !order.includes(current)) {
|
|
75
|
-
await clearSessionAuthProfileOverride({
|
|
76
|
-
sessionEntry,
|
|
77
|
-
sessionStore,
|
|
78
|
-
sessionKey,
|
|
79
|
-
storePath
|
|
80
|
-
});
|
|
81
|
-
current = void 0;
|
|
82
|
-
}
|
|
83
|
-
if (order.length === 0) return;
|
|
84
|
-
const pickFirstAvailable = () => order.find((profileId) => !isProfileInCooldown(store, profileId)) ?? order[0];
|
|
85
|
-
const pickNextAvailable = (active) => {
|
|
86
|
-
const startIndex = order.indexOf(active);
|
|
87
|
-
if (startIndex < 0) return pickFirstAvailable();
|
|
88
|
-
for (let offset = 1; offset <= order.length; offset += 1) {
|
|
89
|
-
const candidate = order[(startIndex + offset) % order.length];
|
|
90
|
-
if (!isProfileInCooldown(store, candidate)) return candidate;
|
|
91
|
-
}
|
|
92
|
-
return order[startIndex] ?? order[0];
|
|
93
|
-
};
|
|
94
|
-
const compactionCount = sessionEntry.compactionCount ?? 0;
|
|
95
|
-
const storedCompaction = typeof sessionEntry.authProfileOverrideCompactionCount === "number" ? sessionEntry.authProfileOverrideCompactionCount : compactionCount;
|
|
96
|
-
if ((sessionEntry.authProfileOverrideSource ?? (typeof sessionEntry.authProfileOverrideCompactionCount === "number" ? "auto" : current ? "user" : void 0)) === "user" && current && !isNewSession) return current;
|
|
97
|
-
let next = current;
|
|
98
|
-
if (isNewSession) next = current ? pickNextAvailable(current) : pickFirstAvailable();
|
|
99
|
-
else if (current && compactionCount > storedCompaction) next = pickNextAvailable(current);
|
|
100
|
-
else if (!current || isProfileInCooldown(store, current)) next = pickFirstAvailable();
|
|
101
|
-
if (!next) return current;
|
|
102
|
-
if (next !== sessionEntry.authProfileOverride || sessionEntry.authProfileOverrideSource !== "auto" || sessionEntry.authProfileOverrideCompactionCount !== compactionCount) {
|
|
103
|
-
sessionEntry.authProfileOverride = next;
|
|
104
|
-
sessionEntry.authProfileOverrideSource = "auto";
|
|
105
|
-
sessionEntry.authProfileOverrideCompactionCount = compactionCount;
|
|
106
|
-
sessionEntry.updatedAt = Date.now();
|
|
107
|
-
sessionStore[sessionKey] = sessionEntry;
|
|
108
|
-
if (storePath) await updateSessionStore(storePath, (store) => {
|
|
109
|
-
store[sessionKey] = sessionEntry;
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
return next;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
//#endregion
|
|
116
|
-
//#region src/agents/bootstrap-hooks.ts
|
|
117
|
-
async function applyBootstrapHookOverrides(params) {
|
|
118
|
-
const sessionKey = params.sessionKey ?? params.sessionId ?? "unknown";
|
|
119
|
-
const agentId = params.agentId ?? (params.sessionKey ? resolveAgentIdFromSessionKey(params.sessionKey) : void 0);
|
|
120
|
-
const event = createInternalHookEvent("agent", "bootstrap", sessionKey, {
|
|
121
|
-
workspaceDir: params.workspaceDir,
|
|
122
|
-
bootstrapFiles: params.files,
|
|
123
|
-
cfg: params.config,
|
|
124
|
-
sessionKey: params.sessionKey,
|
|
125
|
-
sessionId: params.sessionId,
|
|
126
|
-
agentId
|
|
127
|
-
});
|
|
128
|
-
await triggerInternalHook(event);
|
|
129
|
-
const updated = event.context.bootstrapFiles;
|
|
130
|
-
return Array.isArray(updated) ? updated : params.files;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
//#endregion
|
|
134
|
-
//#region src/agents/bootstrap-files.ts
|
|
135
|
-
function makeBootstrapWarn(params) {
|
|
136
|
-
if (!params.warn) return;
|
|
137
|
-
return (message) => params.warn?.(`${message} (sessionKey=${params.sessionLabel})`);
|
|
138
|
-
}
|
|
139
|
-
async function resolveBootstrapFilesForRun(params) {
|
|
140
|
-
const sessionKey = params.sessionKey ?? params.sessionId;
|
|
141
|
-
return applyBootstrapHookOverrides({
|
|
142
|
-
files: filterBootstrapFilesForSession(await loadWorkspaceBootstrapFiles(params.workspaceDir), sessionKey),
|
|
143
|
-
workspaceDir: params.workspaceDir,
|
|
144
|
-
config: params.config,
|
|
145
|
-
sessionKey: params.sessionKey,
|
|
146
|
-
sessionId: params.sessionId,
|
|
147
|
-
agentId: params.agentId
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
async function resolveBootstrapContextForRun(params) {
|
|
151
|
-
const bootstrapFiles = await resolveBootstrapFilesForRun(params);
|
|
152
|
-
return {
|
|
153
|
-
bootstrapFiles,
|
|
154
|
-
contextFiles: buildBootstrapContextFiles(bootstrapFiles, {
|
|
155
|
-
maxChars: resolveBootstrapMaxChars(params.config),
|
|
156
|
-
totalMaxChars: resolveBootstrapTotalMaxChars(params.config),
|
|
157
|
-
warn: params.warn
|
|
158
|
-
})
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
//#endregion
|
|
163
|
-
//#region src/agents/cli-backends.ts
|
|
164
|
-
const DEFAULT_CLAUDE_BACKEND = {
|
|
165
|
-
command: "claude",
|
|
166
|
-
args: [
|
|
167
|
-
"-p",
|
|
168
|
-
"--output-format",
|
|
169
|
-
"json",
|
|
170
|
-
"--dangerously-skip-permissions"
|
|
171
|
-
],
|
|
172
|
-
resumeArgs: [
|
|
173
|
-
"-p",
|
|
174
|
-
"--output-format",
|
|
175
|
-
"json",
|
|
176
|
-
"--dangerously-skip-permissions",
|
|
177
|
-
"--resume",
|
|
178
|
-
"{sessionId}"
|
|
179
|
-
],
|
|
180
|
-
output: "json",
|
|
181
|
-
input: "arg",
|
|
182
|
-
modelArg: "--model",
|
|
183
|
-
modelAliases: {
|
|
184
|
-
opus: "opus",
|
|
185
|
-
"opus-4.6": "opus",
|
|
186
|
-
"opus-4.5": "opus",
|
|
187
|
-
"opus-4": "opus",
|
|
188
|
-
"claude-opus-4-6": "opus",
|
|
189
|
-
"claude-opus-4-5": "opus",
|
|
190
|
-
"claude-opus-4": "opus",
|
|
191
|
-
sonnet: "sonnet",
|
|
192
|
-
"sonnet-4.5": "sonnet",
|
|
193
|
-
"sonnet-4.1": "sonnet",
|
|
194
|
-
"sonnet-4.0": "sonnet",
|
|
195
|
-
"claude-sonnet-4-5": "sonnet",
|
|
196
|
-
"claude-sonnet-4-1": "sonnet",
|
|
197
|
-
"claude-sonnet-4-0": "sonnet",
|
|
198
|
-
haiku: "haiku",
|
|
199
|
-
"haiku-3.5": "haiku",
|
|
200
|
-
"claude-haiku-3-5": "haiku"
|
|
201
|
-
},
|
|
202
|
-
sessionArg: "--session-id",
|
|
203
|
-
sessionMode: "always",
|
|
204
|
-
sessionIdFields: [
|
|
205
|
-
"session_id",
|
|
206
|
-
"sessionId",
|
|
207
|
-
"conversation_id",
|
|
208
|
-
"conversationId"
|
|
209
|
-
],
|
|
210
|
-
systemPromptArg: "--append-system-prompt",
|
|
211
|
-
systemPromptMode: "append",
|
|
212
|
-
systemPromptWhen: "first",
|
|
213
|
-
clearEnv: ["ANTHROPIC_API_KEY", "ANTHROPIC_API_KEY_OLD"],
|
|
214
|
-
serialize: true
|
|
215
|
-
};
|
|
216
|
-
const DEFAULT_CODEX_BACKEND = {
|
|
217
|
-
command: "codex",
|
|
218
|
-
args: [
|
|
219
|
-
"exec",
|
|
220
|
-
"--json",
|
|
221
|
-
"--color",
|
|
222
|
-
"never",
|
|
223
|
-
"--sandbox",
|
|
224
|
-
"read-only",
|
|
225
|
-
"--skip-git-repo-check"
|
|
226
|
-
],
|
|
227
|
-
resumeArgs: [
|
|
228
|
-
"exec",
|
|
229
|
-
"resume",
|
|
230
|
-
"{sessionId}",
|
|
231
|
-
"--color",
|
|
232
|
-
"never",
|
|
233
|
-
"--sandbox",
|
|
234
|
-
"read-only",
|
|
235
|
-
"--skip-git-repo-check"
|
|
236
|
-
],
|
|
237
|
-
output: "jsonl",
|
|
238
|
-
resumeOutput: "text",
|
|
239
|
-
input: "arg",
|
|
240
|
-
modelArg: "--model",
|
|
241
|
-
sessionIdFields: ["thread_id"],
|
|
242
|
-
sessionMode: "existing",
|
|
243
|
-
imageArg: "--image",
|
|
244
|
-
imageMode: "repeat",
|
|
245
|
-
serialize: true
|
|
246
|
-
};
|
|
247
|
-
function normalizeBackendKey(key) {
|
|
248
|
-
return normalizeProviderId$1(key);
|
|
249
|
-
}
|
|
250
|
-
function pickBackendConfig(config, normalizedId) {
|
|
251
|
-
for (const [key, entry] of Object.entries(config)) if (normalizeBackendKey(key) === normalizedId) return entry;
|
|
252
|
-
}
|
|
253
|
-
function mergeBackendConfig(base, override) {
|
|
254
|
-
if (!override) return { ...base };
|
|
255
|
-
return {
|
|
256
|
-
...base,
|
|
257
|
-
...override,
|
|
258
|
-
args: override.args ?? base.args,
|
|
259
|
-
env: {
|
|
260
|
-
...base.env,
|
|
261
|
-
...override.env
|
|
262
|
-
},
|
|
263
|
-
modelAliases: {
|
|
264
|
-
...base.modelAliases,
|
|
265
|
-
...override.modelAliases
|
|
266
|
-
},
|
|
267
|
-
clearEnv: Array.from(new Set([...base.clearEnv ?? [], ...override.clearEnv ?? []])),
|
|
268
|
-
sessionIdFields: override.sessionIdFields ?? base.sessionIdFields,
|
|
269
|
-
sessionArgs: override.sessionArgs ?? base.sessionArgs,
|
|
270
|
-
resumeArgs: override.resumeArgs ?? base.resumeArgs
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
function resolveCliBackendConfig(provider, cfg) {
|
|
274
|
-
const normalized = normalizeBackendKey(provider);
|
|
275
|
-
const override = pickBackendConfig(cfg?.agents?.defaults?.cliBackends ?? {}, normalized);
|
|
276
|
-
if (normalized === "claude-cli") {
|
|
277
|
-
const merged = mergeBackendConfig(DEFAULT_CLAUDE_BACKEND, override);
|
|
278
|
-
const command = merged.command?.trim();
|
|
279
|
-
if (!command) return null;
|
|
280
|
-
return {
|
|
281
|
-
id: normalized,
|
|
282
|
-
config: {
|
|
283
|
-
...merged,
|
|
284
|
-
command
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
if (normalized === "codex-cli") {
|
|
289
|
-
const merged = mergeBackendConfig(DEFAULT_CODEX_BACKEND, override);
|
|
290
|
-
const command = merged.command?.trim();
|
|
291
|
-
if (!command) return null;
|
|
292
|
-
return {
|
|
293
|
-
id: normalized,
|
|
294
|
-
config: {
|
|
295
|
-
...merged,
|
|
296
|
-
command
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
if (!override) return null;
|
|
301
|
-
const command = override.command?.trim();
|
|
302
|
-
if (!command) return null;
|
|
303
|
-
return {
|
|
304
|
-
id: normalized,
|
|
305
|
-
config: {
|
|
306
|
-
...override,
|
|
307
|
-
command
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
//#endregion
|
|
313
|
-
//#region src/line/markdown-to-line.ts
|
|
314
|
-
function stripMarkdown(text) {
|
|
315
|
-
return text.replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/__([^_]+)__/g, "$1").replace(/_([^_]+)_/g, "$1").replace(/~~([^~]+)~~/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/```[^`]*```/gs, "").replace(/^#{1,6}\s+/gm, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^[-*+]\s+/gm, "").replace(/^\d+\.\s+/gm, "");
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
//#endregion
|
|
319
|
-
//#region src/media/audio.ts
|
|
320
|
-
const TELEGRAM_VOICE_AUDIO_EXTENSIONS = new Set([
|
|
321
|
-
".oga",
|
|
322
|
-
".ogg",
|
|
323
|
-
".opus",
|
|
324
|
-
".mp3",
|
|
325
|
-
".m4a"
|
|
326
|
-
]);
|
|
327
|
-
/**
|
|
328
|
-
* MIME types compatible with voice messages.
|
|
329
|
-
* Telegram sendVoice supports OGG/Opus, MP3, and M4A.
|
|
330
|
-
* https://core.telegram.org/bots/api#sendvoice
|
|
331
|
-
*/
|
|
332
|
-
const TELEGRAM_VOICE_MIME_TYPES = new Set([
|
|
333
|
-
"audio/ogg",
|
|
334
|
-
"audio/opus",
|
|
335
|
-
"audio/mpeg",
|
|
336
|
-
"audio/mp3",
|
|
337
|
-
"audio/mp4",
|
|
338
|
-
"audio/x-m4a",
|
|
339
|
-
"audio/m4a"
|
|
340
|
-
]);
|
|
341
|
-
function isTelegramVoiceCompatibleAudio(opts) {
|
|
342
|
-
const mime = normalizeMimeType(opts.contentType);
|
|
343
|
-
if (mime && TELEGRAM_VOICE_MIME_TYPES.has(mime)) return true;
|
|
344
|
-
const fileName = opts.fileName?.trim();
|
|
345
|
-
if (!fileName) return false;
|
|
346
|
-
const ext = getFileExtension(fileName);
|
|
347
|
-
if (!ext) return false;
|
|
348
|
-
return TELEGRAM_VOICE_AUDIO_EXTENSIONS.has(ext);
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Backward-compatible alias used across plugin/runtime call sites.
|
|
352
|
-
* Keeps existing behavior while making Telegram-specific policy explicit.
|
|
353
|
-
*/
|
|
354
|
-
function isVoiceCompatibleAudio(opts) {
|
|
355
|
-
return isTelegramVoiceCompatibleAudio(opts);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
//#endregion
|
|
359
|
-
//#region src/agents/pi-embedded-runner/model.ts
|
|
360
|
-
function resolveModel(..._args) {
|
|
361
|
-
return "default";
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
//#endregion
|
|
365
|
-
//#region src/tts/tts-core.ts
|
|
366
|
-
const DEFAULT_ELEVENLABS_BASE_URL$1 = "https://api.elevenlabs.io";
|
|
367
|
-
const TEMP_FILE_CLEANUP_DELAY_MS = 300 * 1e3;
|
|
368
|
-
function isValidVoiceId(voiceId) {
|
|
369
|
-
return /^[a-zA-Z0-9]{10,40}$/.test(voiceId);
|
|
370
|
-
}
|
|
371
|
-
function normalizeElevenLabsBaseUrl(baseUrl) {
|
|
372
|
-
const trimmed = baseUrl.trim();
|
|
373
|
-
if (!trimmed) return DEFAULT_ELEVENLABS_BASE_URL$1;
|
|
374
|
-
return trimmed.replace(/\/+$/, "");
|
|
375
|
-
}
|
|
376
|
-
function requireInRange(value, min, max, label) {
|
|
377
|
-
if (!Number.isFinite(value) || value < min || value > max) throw new Error(`${label} must be between ${min} and ${max}`);
|
|
378
|
-
}
|
|
379
|
-
function assertElevenLabsVoiceSettings(settings) {
|
|
380
|
-
requireInRange(settings.stability, 0, 1, "stability");
|
|
381
|
-
requireInRange(settings.similarityBoost, 0, 1, "similarityBoost");
|
|
382
|
-
requireInRange(settings.style, 0, 1, "style");
|
|
383
|
-
requireInRange(settings.speed, .5, 2, "speed");
|
|
384
|
-
}
|
|
385
|
-
function normalizeLanguageCode(code) {
|
|
386
|
-
const trimmed = code?.trim();
|
|
387
|
-
if (!trimmed) return;
|
|
388
|
-
const normalized = trimmed.toLowerCase();
|
|
389
|
-
if (!/^[a-z]{2}$/.test(normalized)) throw new Error("languageCode must be a 2-letter ISO 639-1 code (e.g. en, de, fr)");
|
|
390
|
-
return normalized;
|
|
391
|
-
}
|
|
392
|
-
function normalizeApplyTextNormalization(mode) {
|
|
393
|
-
const trimmed = mode?.trim();
|
|
394
|
-
if (!trimmed) return;
|
|
395
|
-
const normalized = trimmed.toLowerCase();
|
|
396
|
-
if (normalized === "auto" || normalized === "on" || normalized === "off") return normalized;
|
|
397
|
-
throw new Error("applyTextNormalization must be one of: auto, on, off");
|
|
398
|
-
}
|
|
399
|
-
function normalizeSeed(seed) {
|
|
400
|
-
if (seed == null) return;
|
|
401
|
-
const next = Math.floor(seed);
|
|
402
|
-
if (!Number.isFinite(next) || next < 0 || next > 4294967295) throw new Error("seed must be between 0 and 4294967295");
|
|
403
|
-
return next;
|
|
404
|
-
}
|
|
405
|
-
function parseBooleanValue(value) {
|
|
406
|
-
const normalized = value.trim().toLowerCase();
|
|
407
|
-
if ([
|
|
408
|
-
"true",
|
|
409
|
-
"1",
|
|
410
|
-
"yes",
|
|
411
|
-
"on"
|
|
412
|
-
].includes(normalized)) return true;
|
|
413
|
-
if ([
|
|
414
|
-
"false",
|
|
415
|
-
"0",
|
|
416
|
-
"no",
|
|
417
|
-
"off"
|
|
418
|
-
].includes(normalized)) return false;
|
|
419
|
-
}
|
|
420
|
-
function parseNumberValue(value) {
|
|
421
|
-
const parsed = Number.parseFloat(value);
|
|
422
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
423
|
-
}
|
|
424
|
-
function parseTtsDirectives(text, policy) {
|
|
425
|
-
if (!policy.enabled) return {
|
|
426
|
-
cleanedText: text,
|
|
427
|
-
overrides: {},
|
|
428
|
-
warnings: [],
|
|
429
|
-
hasDirective: false
|
|
430
|
-
};
|
|
431
|
-
const overrides = {};
|
|
432
|
-
const warnings = [];
|
|
433
|
-
let cleanedText = text;
|
|
434
|
-
let hasDirective = false;
|
|
435
|
-
cleanedText = cleanedText.replace(/\[\[tts:text\]\]([\s\S]*?)\[\[\/tts:text\]\]/gi, (_match, inner) => {
|
|
436
|
-
hasDirective = true;
|
|
437
|
-
if (policy.allowText && overrides.ttsText == null) overrides.ttsText = inner.trim();
|
|
438
|
-
return "";
|
|
439
|
-
});
|
|
440
|
-
cleanedText = cleanedText.replace(/\[\[tts:([^\]]+)\]\]/gi, (_match, body) => {
|
|
441
|
-
hasDirective = true;
|
|
442
|
-
const tokens = body.split(/\s+/).filter(Boolean);
|
|
443
|
-
for (const token of tokens) {
|
|
444
|
-
const eqIndex = token.indexOf("=");
|
|
445
|
-
if (eqIndex === -1) continue;
|
|
446
|
-
const rawKey = token.slice(0, eqIndex).trim();
|
|
447
|
-
const rawValue = token.slice(eqIndex + 1).trim();
|
|
448
|
-
if (!rawKey || !rawValue) continue;
|
|
449
|
-
const key = rawKey.toLowerCase();
|
|
450
|
-
try {
|
|
451
|
-
switch (key) {
|
|
452
|
-
case "provider":
|
|
453
|
-
if (!policy.allowProvider) break;
|
|
454
|
-
if (rawValue === "openai" || rawValue === "elevenlabs" || rawValue === "edge") overrides.provider = rawValue;
|
|
455
|
-
else warnings.push(`unsupported provider "${rawValue}"`);
|
|
456
|
-
break;
|
|
457
|
-
case "voice":
|
|
458
|
-
case "openai_voice":
|
|
459
|
-
case "openaivoice":
|
|
460
|
-
if (!policy.allowVoice) break;
|
|
461
|
-
if (isValidOpenAIVoice(rawValue)) overrides.openai = {
|
|
462
|
-
...overrides.openai,
|
|
463
|
-
voice: rawValue
|
|
464
|
-
};
|
|
465
|
-
else warnings.push(`invalid OpenAI voice "${rawValue}"`);
|
|
466
|
-
break;
|
|
467
|
-
case "voiceid":
|
|
468
|
-
case "voice_id":
|
|
469
|
-
case "elevenlabs_voice":
|
|
470
|
-
case "elevenlabsvoice":
|
|
471
|
-
if (!policy.allowVoice) break;
|
|
472
|
-
if (isValidVoiceId(rawValue)) overrides.elevenlabs = {
|
|
473
|
-
...overrides.elevenlabs,
|
|
474
|
-
voiceId: rawValue
|
|
475
|
-
};
|
|
476
|
-
else warnings.push(`invalid ElevenLabs voiceId "${rawValue}"`);
|
|
477
|
-
break;
|
|
478
|
-
case "model":
|
|
479
|
-
case "modelid":
|
|
480
|
-
case "model_id":
|
|
481
|
-
case "elevenlabs_model":
|
|
482
|
-
case "elevenlabsmodel":
|
|
483
|
-
case "openai_model":
|
|
484
|
-
case "openaimodel":
|
|
485
|
-
if (!policy.allowModelId) break;
|
|
486
|
-
if (isValidOpenAIModel(rawValue)) overrides.openai = {
|
|
487
|
-
...overrides.openai,
|
|
488
|
-
model: rawValue
|
|
489
|
-
};
|
|
490
|
-
else overrides.elevenlabs = {
|
|
491
|
-
...overrides.elevenlabs,
|
|
492
|
-
modelId: rawValue
|
|
493
|
-
};
|
|
494
|
-
break;
|
|
495
|
-
case "stability":
|
|
496
|
-
if (!policy.allowVoiceSettings) break;
|
|
497
|
-
{
|
|
498
|
-
const value = parseNumberValue(rawValue);
|
|
499
|
-
if (value == null) {
|
|
500
|
-
warnings.push("invalid stability value");
|
|
501
|
-
break;
|
|
502
|
-
}
|
|
503
|
-
requireInRange(value, 0, 1, "stability");
|
|
504
|
-
overrides.elevenlabs = {
|
|
505
|
-
...overrides.elevenlabs,
|
|
506
|
-
voiceSettings: {
|
|
507
|
-
...overrides.elevenlabs?.voiceSettings,
|
|
508
|
-
stability: value
|
|
509
|
-
}
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
break;
|
|
513
|
-
case "similarity":
|
|
514
|
-
case "similarityboost":
|
|
515
|
-
case "similarity_boost":
|
|
516
|
-
if (!policy.allowVoiceSettings) break;
|
|
517
|
-
{
|
|
518
|
-
const value = parseNumberValue(rawValue);
|
|
519
|
-
if (value == null) {
|
|
520
|
-
warnings.push("invalid similarityBoost value");
|
|
521
|
-
break;
|
|
522
|
-
}
|
|
523
|
-
requireInRange(value, 0, 1, "similarityBoost");
|
|
524
|
-
overrides.elevenlabs = {
|
|
525
|
-
...overrides.elevenlabs,
|
|
526
|
-
voiceSettings: {
|
|
527
|
-
...overrides.elevenlabs?.voiceSettings,
|
|
528
|
-
similarityBoost: value
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
break;
|
|
533
|
-
case "style":
|
|
534
|
-
if (!policy.allowVoiceSettings) break;
|
|
535
|
-
{
|
|
536
|
-
const value = parseNumberValue(rawValue);
|
|
537
|
-
if (value == null) {
|
|
538
|
-
warnings.push("invalid style value");
|
|
539
|
-
break;
|
|
540
|
-
}
|
|
541
|
-
requireInRange(value, 0, 1, "style");
|
|
542
|
-
overrides.elevenlabs = {
|
|
543
|
-
...overrides.elevenlabs,
|
|
544
|
-
voiceSettings: {
|
|
545
|
-
...overrides.elevenlabs?.voiceSettings,
|
|
546
|
-
style: value
|
|
547
|
-
}
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
break;
|
|
551
|
-
case "speed":
|
|
552
|
-
if (!policy.allowVoiceSettings) break;
|
|
553
|
-
{
|
|
554
|
-
const value = parseNumberValue(rawValue);
|
|
555
|
-
if (value == null) {
|
|
556
|
-
warnings.push("invalid speed value");
|
|
557
|
-
break;
|
|
558
|
-
}
|
|
559
|
-
requireInRange(value, .5, 2, "speed");
|
|
560
|
-
overrides.elevenlabs = {
|
|
561
|
-
...overrides.elevenlabs,
|
|
562
|
-
voiceSettings: {
|
|
563
|
-
...overrides.elevenlabs?.voiceSettings,
|
|
564
|
-
speed: value
|
|
565
|
-
}
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
break;
|
|
569
|
-
case "speakerboost":
|
|
570
|
-
case "speaker_boost":
|
|
571
|
-
case "usespeakerboost":
|
|
572
|
-
case "use_speaker_boost":
|
|
573
|
-
if (!policy.allowVoiceSettings) break;
|
|
574
|
-
{
|
|
575
|
-
const value = parseBooleanValue(rawValue);
|
|
576
|
-
if (value == null) {
|
|
577
|
-
warnings.push("invalid useSpeakerBoost value");
|
|
578
|
-
break;
|
|
579
|
-
}
|
|
580
|
-
overrides.elevenlabs = {
|
|
581
|
-
...overrides.elevenlabs,
|
|
582
|
-
voiceSettings: {
|
|
583
|
-
...overrides.elevenlabs?.voiceSettings,
|
|
584
|
-
useSpeakerBoost: value
|
|
585
|
-
}
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
break;
|
|
589
|
-
case "normalize":
|
|
590
|
-
case "applytextnormalization":
|
|
591
|
-
case "apply_text_normalization":
|
|
592
|
-
if (!policy.allowNormalization) break;
|
|
593
|
-
overrides.elevenlabs = {
|
|
594
|
-
...overrides.elevenlabs,
|
|
595
|
-
applyTextNormalization: normalizeApplyTextNormalization(rawValue)
|
|
596
|
-
};
|
|
597
|
-
break;
|
|
598
|
-
case "language":
|
|
599
|
-
case "languagecode":
|
|
600
|
-
case "language_code":
|
|
601
|
-
if (!policy.allowNormalization) break;
|
|
602
|
-
overrides.elevenlabs = {
|
|
603
|
-
...overrides.elevenlabs,
|
|
604
|
-
languageCode: normalizeLanguageCode(rawValue)
|
|
605
|
-
};
|
|
606
|
-
break;
|
|
607
|
-
case "seed":
|
|
608
|
-
if (!policy.allowSeed) break;
|
|
609
|
-
overrides.elevenlabs = {
|
|
610
|
-
...overrides.elevenlabs,
|
|
611
|
-
seed: normalizeSeed(Number.parseInt(rawValue, 10))
|
|
612
|
-
};
|
|
613
|
-
break;
|
|
614
|
-
default: break;
|
|
615
|
-
}
|
|
616
|
-
} catch (err) {
|
|
617
|
-
warnings.push(err.message);
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
return "";
|
|
621
|
-
});
|
|
622
|
-
return {
|
|
623
|
-
cleanedText,
|
|
624
|
-
ttsText: overrides.ttsText,
|
|
625
|
-
hasDirective,
|
|
626
|
-
overrides,
|
|
627
|
-
warnings
|
|
628
|
-
};
|
|
629
|
-
}
|
|
630
|
-
const OPENAI_TTS_MODELS = [
|
|
631
|
-
"gpt-4o-mini-tts",
|
|
632
|
-
"tts-1",
|
|
633
|
-
"tts-1-hd"
|
|
634
|
-
];
|
|
635
|
-
/**
|
|
636
|
-
* Custom OpenAI-compatible TTS endpoint.
|
|
637
|
-
* When set, model/voice validation is relaxed to allow non-OpenAI models.
|
|
638
|
-
* Example: OPENAI_TTS_BASE_URL=http://localhost:8880/v1
|
|
639
|
-
*
|
|
640
|
-
* Note: Read at runtime (not module load) to support config.env loading.
|
|
641
|
-
*/
|
|
642
|
-
function getOpenAITtsBaseUrl() {
|
|
643
|
-
return (process.env.OPENAI_TTS_BASE_URL?.trim() || "https://api.openai.com/v1").replace(/\/+$/, "");
|
|
644
|
-
}
|
|
645
|
-
function isCustomOpenAIEndpoint() {
|
|
646
|
-
return getOpenAITtsBaseUrl() !== "https://api.openai.com/v1";
|
|
647
|
-
}
|
|
648
|
-
const OPENAI_TTS_VOICES = [
|
|
649
|
-
"alloy",
|
|
650
|
-
"ash",
|
|
651
|
-
"ballad",
|
|
652
|
-
"cedar",
|
|
653
|
-
"coral",
|
|
654
|
-
"echo",
|
|
655
|
-
"fable",
|
|
656
|
-
"juniper",
|
|
657
|
-
"marin",
|
|
658
|
-
"onyx",
|
|
659
|
-
"nova",
|
|
660
|
-
"sage",
|
|
661
|
-
"shimmer",
|
|
662
|
-
"verse"
|
|
663
|
-
];
|
|
664
|
-
function isValidOpenAIModel(model) {
|
|
665
|
-
if (isCustomOpenAIEndpoint()) return true;
|
|
666
|
-
return OPENAI_TTS_MODELS.includes(model);
|
|
667
|
-
}
|
|
668
|
-
function isValidOpenAIVoice(voice) {
|
|
669
|
-
if (isCustomOpenAIEndpoint()) return true;
|
|
670
|
-
return OPENAI_TTS_VOICES.includes(voice);
|
|
671
|
-
}
|
|
672
|
-
function resolveSummaryModelRef(cfg, config) {
|
|
673
|
-
const defaultRef = resolveDefaultModelForAgent({ cfg });
|
|
674
|
-
const override = config.summaryModel?.trim();
|
|
675
|
-
if (!override) return {
|
|
676
|
-
ref: defaultRef,
|
|
677
|
-
source: "default"
|
|
678
|
-
};
|
|
679
|
-
const aliasIndex = buildModelAliasIndex({
|
|
680
|
-
cfg,
|
|
681
|
-
defaultProvider: defaultRef.provider
|
|
682
|
-
});
|
|
683
|
-
const resolved = resolveModelRefFromString({
|
|
684
|
-
raw: override,
|
|
685
|
-
defaultProvider: defaultRef.provider,
|
|
686
|
-
aliasIndex
|
|
687
|
-
});
|
|
688
|
-
if (!resolved) return {
|
|
689
|
-
ref: defaultRef,
|
|
690
|
-
source: "default"
|
|
691
|
-
};
|
|
692
|
-
return {
|
|
693
|
-
ref: resolved.ref,
|
|
694
|
-
source: "summaryModel"
|
|
695
|
-
};
|
|
696
|
-
}
|
|
697
|
-
function isTextContentBlock(block) {
|
|
698
|
-
return block.type === "text";
|
|
699
|
-
}
|
|
700
|
-
async function summarizeText(params) {
|
|
701
|
-
const { text, targetLength, cfg, config, timeoutMs } = params;
|
|
702
|
-
if (targetLength < 100 || targetLength > 1e4) throw new Error(`Invalid targetLength: ${targetLength}`);
|
|
703
|
-
const startTime = Date.now();
|
|
704
|
-
const { ref } = resolveSummaryModelRef(cfg, config);
|
|
705
|
-
const resolved = resolveModel(ref.provider, ref.model, void 0, cfg);
|
|
706
|
-
if (!resolved.model) throw new Error(resolved.error ?? `Unknown summary model: ${ref.provider}/${ref.model}`);
|
|
707
|
-
const apiKey = requireApiKey(await getApiKeyForModel({
|
|
708
|
-
model: resolved.model,
|
|
709
|
-
cfg
|
|
710
|
-
}), ref.provider);
|
|
711
|
-
try {
|
|
712
|
-
const controller = new AbortController();
|
|
713
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
714
|
-
try {
|
|
715
|
-
const summary = (await completeSimple(resolved.model, { messages: [{
|
|
716
|
-
role: "user",
|
|
717
|
-
content: `You are an assistant that summarizes texts concisely while keeping the most important information. Summarize the text to approximately ${targetLength} characters. Maintain the original tone and style. Reply only with the summary, without additional explanations.\n\n<text_to_summarize>\n${text}\n</text_to_summarize>`,
|
|
718
|
-
timestamp: Date.now()
|
|
719
|
-
}] }, {
|
|
720
|
-
apiKey,
|
|
721
|
-
maxTokens: Math.ceil(targetLength / 2),
|
|
722
|
-
temperature: .3,
|
|
723
|
-
signal: controller.signal
|
|
724
|
-
})).content.filter(isTextContentBlock).map((block) => block.text.trim()).filter(Boolean).join(" ").trim();
|
|
725
|
-
if (!summary) throw new Error("No summary returned");
|
|
726
|
-
return {
|
|
727
|
-
summary,
|
|
728
|
-
latencyMs: Date.now() - startTime,
|
|
729
|
-
inputLength: text.length,
|
|
730
|
-
outputLength: summary.length
|
|
731
|
-
};
|
|
732
|
-
} finally {
|
|
733
|
-
clearTimeout(timeout);
|
|
734
|
-
}
|
|
735
|
-
} catch (err) {
|
|
736
|
-
if (err.name === "AbortError") throw new Error("Summarization timed out", { cause: err });
|
|
737
|
-
throw err;
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
function scheduleCleanup(tempDir, delayMs = TEMP_FILE_CLEANUP_DELAY_MS) {
|
|
741
|
-
setTimeout(() => {
|
|
742
|
-
try {
|
|
743
|
-
rmSync(tempDir, {
|
|
744
|
-
recursive: true,
|
|
745
|
-
force: true
|
|
746
|
-
});
|
|
747
|
-
} catch {}
|
|
748
|
-
}, delayMs).unref();
|
|
749
|
-
}
|
|
750
|
-
async function elevenLabsTTS(params) {
|
|
751
|
-
const { text, apiKey, baseUrl, voiceId, modelId, outputFormat, seed, applyTextNormalization, languageCode, voiceSettings, timeoutMs } = params;
|
|
752
|
-
if (!isValidVoiceId(voiceId)) throw new Error("Invalid voiceId format");
|
|
753
|
-
assertElevenLabsVoiceSettings(voiceSettings);
|
|
754
|
-
const normalizedLanguage = normalizeLanguageCode(languageCode);
|
|
755
|
-
const normalizedNormalization = normalizeApplyTextNormalization(applyTextNormalization);
|
|
756
|
-
const normalizedSeed = normalizeSeed(seed);
|
|
757
|
-
const controller = new AbortController();
|
|
758
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
759
|
-
try {
|
|
760
|
-
const url = new URL(`${normalizeElevenLabsBaseUrl(baseUrl)}/v1/text-to-speech/${voiceId}`);
|
|
761
|
-
if (outputFormat) url.searchParams.set("output_format", outputFormat);
|
|
762
|
-
const response = await fetch(url.toString(), {
|
|
763
|
-
method: "POST",
|
|
764
|
-
headers: {
|
|
765
|
-
"xi-api-key": apiKey,
|
|
766
|
-
"Content-Type": "application/json",
|
|
767
|
-
Accept: "audio/mpeg"
|
|
768
|
-
},
|
|
769
|
-
body: JSON.stringify({
|
|
770
|
-
text,
|
|
771
|
-
model_id: modelId,
|
|
772
|
-
seed: normalizedSeed,
|
|
773
|
-
apply_text_normalization: normalizedNormalization,
|
|
774
|
-
language_code: normalizedLanguage,
|
|
775
|
-
voice_settings: {
|
|
776
|
-
stability: voiceSettings.stability,
|
|
777
|
-
similarity_boost: voiceSettings.similarityBoost,
|
|
778
|
-
style: voiceSettings.style,
|
|
779
|
-
use_speaker_boost: voiceSettings.useSpeakerBoost,
|
|
780
|
-
speed: voiceSettings.speed
|
|
781
|
-
}
|
|
782
|
-
}),
|
|
783
|
-
signal: controller.signal
|
|
784
|
-
});
|
|
785
|
-
if (!response.ok) throw new Error(`ElevenLabs API error (${response.status})`);
|
|
786
|
-
return Buffer.from(await response.arrayBuffer());
|
|
787
|
-
} finally {
|
|
788
|
-
clearTimeout(timeout);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
async function openaiTTS(params) {
|
|
792
|
-
const { text, apiKey, model, voice, responseFormat, timeoutMs } = params;
|
|
793
|
-
if (!isValidOpenAIModel(model)) throw new Error(`Invalid model: ${model}`);
|
|
794
|
-
if (!isValidOpenAIVoice(voice)) throw new Error(`Invalid voice: ${voice}`);
|
|
795
|
-
const controller = new AbortController();
|
|
796
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
797
|
-
try {
|
|
798
|
-
const response = await fetch(`${getOpenAITtsBaseUrl()}/audio/speech`, {
|
|
799
|
-
method: "POST",
|
|
800
|
-
headers: {
|
|
801
|
-
Authorization: `Bearer ${apiKey}`,
|
|
802
|
-
"Content-Type": "application/json"
|
|
803
|
-
},
|
|
804
|
-
body: JSON.stringify({
|
|
805
|
-
model,
|
|
806
|
-
input: text,
|
|
807
|
-
voice,
|
|
808
|
-
response_format: responseFormat
|
|
809
|
-
}),
|
|
810
|
-
signal: controller.signal
|
|
811
|
-
});
|
|
812
|
-
if (!response.ok) throw new Error(`OpenAI TTS API error (${response.status})`);
|
|
813
|
-
return Buffer.from(await response.arrayBuffer());
|
|
814
|
-
} finally {
|
|
815
|
-
clearTimeout(timeout);
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
function inferEdgeExtension(outputFormat) {
|
|
819
|
-
const normalized = outputFormat.toLowerCase();
|
|
820
|
-
if (normalized.includes("webm")) return ".webm";
|
|
821
|
-
if (normalized.includes("ogg")) return ".ogg";
|
|
822
|
-
if (normalized.includes("opus")) return ".opus";
|
|
823
|
-
if (normalized.includes("wav") || normalized.includes("riff") || normalized.includes("pcm")) return ".wav";
|
|
824
|
-
return ".mp3";
|
|
825
|
-
}
|
|
826
|
-
async function edgeTTS(params) {
|
|
827
|
-
const { text, outputPath, config, timeoutMs } = params;
|
|
828
|
-
await new EdgeTTS({
|
|
829
|
-
voice: config.voice,
|
|
830
|
-
lang: config.lang,
|
|
831
|
-
outputFormat: config.outputFormat,
|
|
832
|
-
saveSubtitles: config.saveSubtitles,
|
|
833
|
-
proxy: config.proxy,
|
|
834
|
-
rate: config.rate,
|
|
835
|
-
pitch: config.pitch,
|
|
836
|
-
volume: config.volume,
|
|
837
|
-
timeout: config.timeoutMs ?? timeoutMs
|
|
838
|
-
}).ttsPromise(text, outputPath);
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
//#endregion
|
|
842
|
-
//#region src/tts/tts.ts
|
|
843
|
-
const DEFAULT_TIMEOUT_MS = 3e4;
|
|
844
|
-
const DEFAULT_TTS_MAX_LENGTH = 1500;
|
|
845
|
-
const DEFAULT_TTS_SUMMARIZE = true;
|
|
846
|
-
const DEFAULT_MAX_TEXT_LENGTH = 4096;
|
|
847
|
-
const DEFAULT_ELEVENLABS_BASE_URL = "https://api.elevenlabs.io";
|
|
848
|
-
const DEFAULT_ELEVENLABS_VOICE_ID = "pMsXgVXv3BLzUgSXRplE";
|
|
849
|
-
const DEFAULT_ELEVENLABS_MODEL_ID = "eleven_multilingual_v2";
|
|
850
|
-
const DEFAULT_OPENAI_MODEL = "gpt-4o-mini-tts";
|
|
851
|
-
const DEFAULT_OPENAI_VOICE = "alloy";
|
|
852
|
-
const DEFAULT_EDGE_VOICE = "en-US-MichelleNeural";
|
|
853
|
-
const DEFAULT_EDGE_LANG = "en-US";
|
|
854
|
-
const DEFAULT_EDGE_OUTPUT_FORMAT = "audio-24khz-48kbitrate-mono-mp3";
|
|
855
|
-
const DEFAULT_ELEVENLABS_VOICE_SETTINGS = {
|
|
856
|
-
stability: .5,
|
|
857
|
-
similarityBoost: .75,
|
|
858
|
-
style: 0,
|
|
859
|
-
useSpeakerBoost: true,
|
|
860
|
-
speed: 1
|
|
861
|
-
};
|
|
862
|
-
const TELEGRAM_OUTPUT = {
|
|
863
|
-
openai: "opus",
|
|
864
|
-
elevenlabs: "opus_48000_64",
|
|
865
|
-
extension: ".opus",
|
|
866
|
-
voiceCompatible: true
|
|
867
|
-
};
|
|
868
|
-
const DEFAULT_OUTPUT = {
|
|
869
|
-
openai: "mp3",
|
|
870
|
-
elevenlabs: "mp3_44100_128",
|
|
871
|
-
extension: ".mp3",
|
|
872
|
-
voiceCompatible: false
|
|
873
|
-
};
|
|
874
|
-
const TELEPHONY_OUTPUT = {
|
|
875
|
-
openai: {
|
|
876
|
-
format: "pcm",
|
|
877
|
-
sampleRate: 24e3
|
|
878
|
-
},
|
|
879
|
-
elevenlabs: {
|
|
880
|
-
format: "pcm_22050",
|
|
881
|
-
sampleRate: 22050
|
|
882
|
-
}
|
|
883
|
-
};
|
|
884
|
-
const TTS_AUTO_MODES = new Set([
|
|
885
|
-
"off",
|
|
886
|
-
"always",
|
|
887
|
-
"inbound",
|
|
888
|
-
"tagged"
|
|
889
|
-
]);
|
|
890
|
-
let lastTtsAttempt;
|
|
891
|
-
function normalizeTtsAutoMode(value) {
|
|
892
|
-
if (typeof value !== "string") return;
|
|
893
|
-
const normalized = value.trim().toLowerCase();
|
|
894
|
-
if (TTS_AUTO_MODES.has(normalized)) return normalized;
|
|
895
|
-
}
|
|
896
|
-
function resolveModelOverridePolicy(overrides) {
|
|
897
|
-
if (!(overrides?.enabled ?? true)) return {
|
|
898
|
-
enabled: false,
|
|
899
|
-
allowText: false,
|
|
900
|
-
allowProvider: false,
|
|
901
|
-
allowVoice: false,
|
|
902
|
-
allowModelId: false,
|
|
903
|
-
allowVoiceSettings: false,
|
|
904
|
-
allowNormalization: false,
|
|
905
|
-
allowSeed: false
|
|
906
|
-
};
|
|
907
|
-
const allow = (value) => value ?? true;
|
|
908
|
-
return {
|
|
909
|
-
enabled: true,
|
|
910
|
-
allowText: allow(overrides?.allowText),
|
|
911
|
-
allowProvider: allow(overrides?.allowProvider),
|
|
912
|
-
allowVoice: allow(overrides?.allowVoice),
|
|
913
|
-
allowModelId: allow(overrides?.allowModelId),
|
|
914
|
-
allowVoiceSettings: allow(overrides?.allowVoiceSettings),
|
|
915
|
-
allowNormalization: allow(overrides?.allowNormalization),
|
|
916
|
-
allowSeed: allow(overrides?.allowSeed)
|
|
917
|
-
};
|
|
918
|
-
}
|
|
919
|
-
function resolveTtsConfig(cfg) {
|
|
920
|
-
const raw = cfg.messages?.tts ?? {};
|
|
921
|
-
const providerSource = raw.provider ? "config" : "default";
|
|
922
|
-
const edgeOutputFormat = raw.edge?.outputFormat?.trim();
|
|
923
|
-
return {
|
|
924
|
-
auto: normalizeTtsAutoMode(raw.auto) ?? (raw.enabled ? "always" : "off"),
|
|
925
|
-
mode: raw.mode ?? "final",
|
|
926
|
-
provider: raw.provider ?? "edge",
|
|
927
|
-
providerSource,
|
|
928
|
-
summaryModel: raw.summaryModel?.trim() || void 0,
|
|
929
|
-
modelOverrides: resolveModelOverridePolicy(raw.modelOverrides),
|
|
930
|
-
elevenlabs: {
|
|
931
|
-
apiKey: raw.elevenlabs?.apiKey,
|
|
932
|
-
baseUrl: raw.elevenlabs?.baseUrl?.trim() || DEFAULT_ELEVENLABS_BASE_URL,
|
|
933
|
-
voiceId: raw.elevenlabs?.voiceId ?? DEFAULT_ELEVENLABS_VOICE_ID,
|
|
934
|
-
modelId: raw.elevenlabs?.modelId ?? DEFAULT_ELEVENLABS_MODEL_ID,
|
|
935
|
-
seed: raw.elevenlabs?.seed,
|
|
936
|
-
applyTextNormalization: raw.elevenlabs?.applyTextNormalization,
|
|
937
|
-
languageCode: raw.elevenlabs?.languageCode,
|
|
938
|
-
voiceSettings: {
|
|
939
|
-
stability: raw.elevenlabs?.voiceSettings?.stability ?? DEFAULT_ELEVENLABS_VOICE_SETTINGS.stability,
|
|
940
|
-
similarityBoost: raw.elevenlabs?.voiceSettings?.similarityBoost ?? DEFAULT_ELEVENLABS_VOICE_SETTINGS.similarityBoost,
|
|
941
|
-
style: raw.elevenlabs?.voiceSettings?.style ?? DEFAULT_ELEVENLABS_VOICE_SETTINGS.style,
|
|
942
|
-
useSpeakerBoost: raw.elevenlabs?.voiceSettings?.useSpeakerBoost ?? DEFAULT_ELEVENLABS_VOICE_SETTINGS.useSpeakerBoost,
|
|
943
|
-
speed: raw.elevenlabs?.voiceSettings?.speed ?? DEFAULT_ELEVENLABS_VOICE_SETTINGS.speed
|
|
944
|
-
}
|
|
945
|
-
},
|
|
946
|
-
openai: {
|
|
947
|
-
apiKey: raw.openai?.apiKey,
|
|
948
|
-
model: raw.openai?.model ?? DEFAULT_OPENAI_MODEL,
|
|
949
|
-
voice: raw.openai?.voice ?? DEFAULT_OPENAI_VOICE
|
|
950
|
-
},
|
|
951
|
-
edge: {
|
|
952
|
-
enabled: raw.edge?.enabled ?? true,
|
|
953
|
-
voice: raw.edge?.voice?.trim() || DEFAULT_EDGE_VOICE,
|
|
954
|
-
lang: raw.edge?.lang?.trim() || DEFAULT_EDGE_LANG,
|
|
955
|
-
outputFormat: edgeOutputFormat || DEFAULT_EDGE_OUTPUT_FORMAT,
|
|
956
|
-
outputFormatConfigured: Boolean(edgeOutputFormat),
|
|
957
|
-
pitch: raw.edge?.pitch?.trim() || void 0,
|
|
958
|
-
rate: raw.edge?.rate?.trim() || void 0,
|
|
959
|
-
volume: raw.edge?.volume?.trim() || void 0,
|
|
960
|
-
saveSubtitles: raw.edge?.saveSubtitles ?? false,
|
|
961
|
-
proxy: raw.edge?.proxy?.trim() || void 0,
|
|
962
|
-
timeoutMs: raw.edge?.timeoutMs
|
|
963
|
-
},
|
|
964
|
-
prefsPath: raw.prefsPath,
|
|
965
|
-
maxTextLength: raw.maxTextLength ?? DEFAULT_MAX_TEXT_LENGTH,
|
|
966
|
-
timeoutMs: raw.timeoutMs ?? DEFAULT_TIMEOUT_MS
|
|
967
|
-
};
|
|
968
|
-
}
|
|
969
|
-
function resolveTtsPrefsPath(config) {
|
|
970
|
-
if (config.prefsPath?.trim()) return resolveUserPath(config.prefsPath.trim());
|
|
971
|
-
const envPath = process.env.ANIMA_TTS_PREFS?.trim();
|
|
972
|
-
if (envPath) return resolveUserPath(envPath);
|
|
973
|
-
return path.join(CONFIG_DIR, "settings", "tts.json");
|
|
974
|
-
}
|
|
975
|
-
function resolveTtsAutoModeFromPrefs(prefs) {
|
|
976
|
-
const auto = normalizeTtsAutoMode(prefs.tts?.auto);
|
|
977
|
-
if (auto) return auto;
|
|
978
|
-
if (typeof prefs.tts?.enabled === "boolean") return prefs.tts.enabled ? "always" : "off";
|
|
979
|
-
}
|
|
980
|
-
function resolveTtsAutoMode(params) {
|
|
981
|
-
const sessionAuto = normalizeTtsAutoMode(params.sessionAuto);
|
|
982
|
-
if (sessionAuto) return sessionAuto;
|
|
983
|
-
const prefsAuto = resolveTtsAutoModeFromPrefs(readPrefs(params.prefsPath));
|
|
984
|
-
if (prefsAuto) return prefsAuto;
|
|
985
|
-
return params.config.auto;
|
|
986
|
-
}
|
|
987
|
-
function buildTtsSystemPromptHint(cfg) {
|
|
988
|
-
const config = resolveTtsConfig(cfg);
|
|
989
|
-
const prefsPath = resolveTtsPrefsPath(config);
|
|
990
|
-
const autoMode = resolveTtsAutoMode({
|
|
991
|
-
config,
|
|
992
|
-
prefsPath
|
|
993
|
-
});
|
|
994
|
-
if (autoMode === "off") return;
|
|
995
|
-
const maxLength = getTtsMaxLength(prefsPath);
|
|
996
|
-
const summarize = isSummarizationEnabled(prefsPath) ? "on" : "off";
|
|
997
|
-
return [
|
|
998
|
-
"Voice (TTS) is enabled.",
|
|
999
|
-
autoMode === "inbound" ? "Only use TTS when the user's last message includes audio/voice." : autoMode === "tagged" ? "Only use TTS when you include [[tts]] or [[tts:text]] tags." : void 0,
|
|
1000
|
-
`Keep spoken text ≤${maxLength} chars to avoid auto-summary (summary ${summarize}).`,
|
|
1001
|
-
"Use [[tts:...]] and optional [[tts:text]]...[[/tts:text]] to control voice/expressiveness."
|
|
1002
|
-
].filter(Boolean).join("\n");
|
|
1003
|
-
}
|
|
1004
|
-
function readPrefs(prefsPath) {
|
|
1005
|
-
try {
|
|
1006
|
-
if (!existsSync(prefsPath)) return {};
|
|
1007
|
-
return JSON.parse(readFileSync(prefsPath, "utf8"));
|
|
1008
|
-
} catch {
|
|
1009
|
-
return {};
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
function atomicWriteFileSync(filePath, content) {
|
|
1013
|
-
const tmpPath = `${filePath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
1014
|
-
writeFileSync(tmpPath, content);
|
|
1015
|
-
try {
|
|
1016
|
-
renameSync(tmpPath, filePath);
|
|
1017
|
-
} catch (err) {
|
|
1018
|
-
try {
|
|
1019
|
-
unlinkSync(tmpPath);
|
|
1020
|
-
} catch {}
|
|
1021
|
-
throw err;
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
function updatePrefs(prefsPath, update) {
|
|
1025
|
-
const prefs = readPrefs(prefsPath);
|
|
1026
|
-
update(prefs);
|
|
1027
|
-
mkdirSync(path.dirname(prefsPath), { recursive: true });
|
|
1028
|
-
atomicWriteFileSync(prefsPath, JSON.stringify(prefs, null, 2));
|
|
1029
|
-
}
|
|
1030
|
-
function isTtsEnabled(config, prefsPath, sessionAuto) {
|
|
1031
|
-
return resolveTtsAutoMode({
|
|
1032
|
-
config,
|
|
1033
|
-
prefsPath,
|
|
1034
|
-
sessionAuto
|
|
1035
|
-
}) !== "off";
|
|
1036
|
-
}
|
|
1037
|
-
function setTtsAutoMode(prefsPath, mode) {
|
|
1038
|
-
updatePrefs(prefsPath, (prefs) => {
|
|
1039
|
-
const next = { ...prefs.tts };
|
|
1040
|
-
delete next.enabled;
|
|
1041
|
-
next.auto = mode;
|
|
1042
|
-
prefs.tts = next;
|
|
1043
|
-
});
|
|
1044
|
-
}
|
|
1045
|
-
function setTtsEnabled(prefsPath, enabled) {
|
|
1046
|
-
setTtsAutoMode(prefsPath, enabled ? "always" : "off");
|
|
1047
|
-
}
|
|
1048
|
-
function getTtsProvider(config, prefsPath) {
|
|
1049
|
-
const prefs = readPrefs(prefsPath);
|
|
1050
|
-
if (prefs.tts?.provider) return prefs.tts.provider;
|
|
1051
|
-
if (config.providerSource === "config") return config.provider;
|
|
1052
|
-
if (resolveTtsApiKey(config, "openai")) return "openai";
|
|
1053
|
-
if (resolveTtsApiKey(config, "elevenlabs")) return "elevenlabs";
|
|
1054
|
-
return "edge";
|
|
1055
|
-
}
|
|
1056
|
-
function setTtsProvider(prefsPath, provider) {
|
|
1057
|
-
updatePrefs(prefsPath, (prefs) => {
|
|
1058
|
-
prefs.tts = {
|
|
1059
|
-
...prefs.tts,
|
|
1060
|
-
provider
|
|
1061
|
-
};
|
|
1062
|
-
});
|
|
1063
|
-
}
|
|
1064
|
-
function getTtsMaxLength(prefsPath) {
|
|
1065
|
-
return readPrefs(prefsPath).tts?.maxLength ?? DEFAULT_TTS_MAX_LENGTH;
|
|
1066
|
-
}
|
|
1067
|
-
function setTtsMaxLength(prefsPath, maxLength) {
|
|
1068
|
-
updatePrefs(prefsPath, (prefs) => {
|
|
1069
|
-
prefs.tts = {
|
|
1070
|
-
...prefs.tts,
|
|
1071
|
-
maxLength
|
|
1072
|
-
};
|
|
1073
|
-
});
|
|
1074
|
-
}
|
|
1075
|
-
function isSummarizationEnabled(prefsPath) {
|
|
1076
|
-
return readPrefs(prefsPath).tts?.summarize ?? DEFAULT_TTS_SUMMARIZE;
|
|
1077
|
-
}
|
|
1078
|
-
function setSummarizationEnabled(prefsPath, enabled) {
|
|
1079
|
-
updatePrefs(prefsPath, (prefs) => {
|
|
1080
|
-
prefs.tts = {
|
|
1081
|
-
...prefs.tts,
|
|
1082
|
-
summarize: enabled
|
|
1083
|
-
};
|
|
1084
|
-
});
|
|
1085
|
-
}
|
|
1086
|
-
function getLastTtsAttempt() {
|
|
1087
|
-
return lastTtsAttempt;
|
|
1088
|
-
}
|
|
1089
|
-
function setLastTtsAttempt(entry) {
|
|
1090
|
-
lastTtsAttempt = entry;
|
|
1091
|
-
}
|
|
1092
|
-
function resolveOutputFormat(channelId) {
|
|
1093
|
-
if (channelId === "telegram") return TELEGRAM_OUTPUT;
|
|
1094
|
-
return DEFAULT_OUTPUT;
|
|
1095
|
-
}
|
|
1096
|
-
function resolveChannelId(channel) {
|
|
1097
|
-
return channel ? normalizeChannelId(channel) : null;
|
|
1098
|
-
}
|
|
1099
|
-
function resolveEdgeOutputFormat(config) {
|
|
1100
|
-
return config.edge.outputFormat;
|
|
1101
|
-
}
|
|
1102
|
-
function resolveTtsApiKey(config, provider) {
|
|
1103
|
-
if (provider === "elevenlabs") return config.elevenlabs.apiKey || process.env.ELEVENLABS_API_KEY || process.env.XI_API_KEY;
|
|
1104
|
-
if (provider === "openai") return config.openai.apiKey || process.env.OPENAI_API_KEY;
|
|
1105
|
-
}
|
|
1106
|
-
const TTS_PROVIDERS = [
|
|
1107
|
-
"openai",
|
|
1108
|
-
"elevenlabs",
|
|
1109
|
-
"edge"
|
|
1110
|
-
];
|
|
1111
|
-
function resolveTtsProviderOrder(primary) {
|
|
1112
|
-
return [primary, ...TTS_PROVIDERS.filter((provider) => provider !== primary)];
|
|
1113
|
-
}
|
|
1114
|
-
function isTtsProviderConfigured(config, provider) {
|
|
1115
|
-
if (provider === "edge") return config.edge.enabled;
|
|
1116
|
-
return Boolean(resolveTtsApiKey(config, provider));
|
|
1117
|
-
}
|
|
1118
|
-
async function textToSpeech(params) {
|
|
1119
|
-
const config = resolveTtsConfig(params.cfg);
|
|
1120
|
-
const prefsPath = params.prefsPath ?? resolveTtsPrefsPath(config);
|
|
1121
|
-
const output = resolveOutputFormat(resolveChannelId(params.channel));
|
|
1122
|
-
if (params.text.length > config.maxTextLength) return {
|
|
1123
|
-
success: false,
|
|
1124
|
-
error: `Text too long (${params.text.length} chars, max ${config.maxTextLength})`
|
|
1125
|
-
};
|
|
1126
|
-
const userProvider = getTtsProvider(config, prefsPath);
|
|
1127
|
-
const providers = resolveTtsProviderOrder(params.overrides?.provider ?? userProvider);
|
|
1128
|
-
let lastError;
|
|
1129
|
-
for (const provider of providers) {
|
|
1130
|
-
const providerStart = Date.now();
|
|
1131
|
-
try {
|
|
1132
|
-
if (provider === "edge") {
|
|
1133
|
-
if (!config.edge.enabled) {
|
|
1134
|
-
lastError = "edge: disabled";
|
|
1135
|
-
continue;
|
|
1136
|
-
}
|
|
1137
|
-
const tempDir = mkdtempSync(path.join(tmpdir(), "tts-"));
|
|
1138
|
-
let edgeOutputFormat = resolveEdgeOutputFormat(config);
|
|
1139
|
-
const fallbackEdgeOutputFormat = edgeOutputFormat !== DEFAULT_EDGE_OUTPUT_FORMAT ? DEFAULT_EDGE_OUTPUT_FORMAT : void 0;
|
|
1140
|
-
const attemptEdgeTts = async (outputFormat) => {
|
|
1141
|
-
const extension = inferEdgeExtension(outputFormat);
|
|
1142
|
-
const audioPath = path.join(tempDir, `voice-${Date.now()}${extension}`);
|
|
1143
|
-
await edgeTTS({
|
|
1144
|
-
text: params.text,
|
|
1145
|
-
outputPath: audioPath,
|
|
1146
|
-
config: {
|
|
1147
|
-
...config.edge,
|
|
1148
|
-
outputFormat
|
|
1149
|
-
},
|
|
1150
|
-
timeoutMs: config.timeoutMs
|
|
1151
|
-
});
|
|
1152
|
-
return {
|
|
1153
|
-
audioPath,
|
|
1154
|
-
outputFormat
|
|
1155
|
-
};
|
|
1156
|
-
};
|
|
1157
|
-
let edgeResult;
|
|
1158
|
-
try {
|
|
1159
|
-
edgeResult = await attemptEdgeTts(edgeOutputFormat);
|
|
1160
|
-
} catch (err) {
|
|
1161
|
-
if (fallbackEdgeOutputFormat && fallbackEdgeOutputFormat !== edgeOutputFormat) {
|
|
1162
|
-
logVerbose(`TTS: Edge output ${edgeOutputFormat} failed; retrying with ${fallbackEdgeOutputFormat}.`);
|
|
1163
|
-
edgeOutputFormat = fallbackEdgeOutputFormat;
|
|
1164
|
-
try {
|
|
1165
|
-
edgeResult = await attemptEdgeTts(edgeOutputFormat);
|
|
1166
|
-
} catch (fallbackErr) {
|
|
1167
|
-
try {
|
|
1168
|
-
rmSync(tempDir, {
|
|
1169
|
-
recursive: true,
|
|
1170
|
-
force: true
|
|
1171
|
-
});
|
|
1172
|
-
} catch {}
|
|
1173
|
-
throw fallbackErr;
|
|
1174
|
-
}
|
|
1175
|
-
} else {
|
|
1176
|
-
try {
|
|
1177
|
-
rmSync(tempDir, {
|
|
1178
|
-
recursive: true,
|
|
1179
|
-
force: true
|
|
1180
|
-
});
|
|
1181
|
-
} catch {}
|
|
1182
|
-
throw err;
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
scheduleCleanup(tempDir);
|
|
1186
|
-
const voiceCompatible = isVoiceCompatibleAudio({ fileName: edgeResult.audioPath });
|
|
1187
|
-
return {
|
|
1188
|
-
success: true,
|
|
1189
|
-
audioPath: edgeResult.audioPath,
|
|
1190
|
-
latencyMs: Date.now() - providerStart,
|
|
1191
|
-
provider,
|
|
1192
|
-
outputFormat: edgeResult.outputFormat,
|
|
1193
|
-
voiceCompatible
|
|
1194
|
-
};
|
|
1195
|
-
}
|
|
1196
|
-
const apiKey = resolveTtsApiKey(config, provider);
|
|
1197
|
-
if (!apiKey) {
|
|
1198
|
-
lastError = `No API key for ${provider}`;
|
|
1199
|
-
continue;
|
|
1200
|
-
}
|
|
1201
|
-
let audioBuffer;
|
|
1202
|
-
if (provider === "elevenlabs") {
|
|
1203
|
-
const voiceIdOverride = params.overrides?.elevenlabs?.voiceId;
|
|
1204
|
-
const modelIdOverride = params.overrides?.elevenlabs?.modelId;
|
|
1205
|
-
const voiceSettings = {
|
|
1206
|
-
...config.elevenlabs.voiceSettings,
|
|
1207
|
-
...params.overrides?.elevenlabs?.voiceSettings
|
|
1208
|
-
};
|
|
1209
|
-
const seedOverride = params.overrides?.elevenlabs?.seed;
|
|
1210
|
-
const normalizationOverride = params.overrides?.elevenlabs?.applyTextNormalization;
|
|
1211
|
-
const languageOverride = params.overrides?.elevenlabs?.languageCode;
|
|
1212
|
-
audioBuffer = await elevenLabsTTS({
|
|
1213
|
-
text: params.text,
|
|
1214
|
-
apiKey,
|
|
1215
|
-
baseUrl: config.elevenlabs.baseUrl,
|
|
1216
|
-
voiceId: voiceIdOverride ?? config.elevenlabs.voiceId,
|
|
1217
|
-
modelId: modelIdOverride ?? config.elevenlabs.modelId,
|
|
1218
|
-
outputFormat: output.elevenlabs,
|
|
1219
|
-
seed: seedOverride ?? config.elevenlabs.seed,
|
|
1220
|
-
applyTextNormalization: normalizationOverride ?? config.elevenlabs.applyTextNormalization,
|
|
1221
|
-
languageCode: languageOverride ?? config.elevenlabs.languageCode,
|
|
1222
|
-
voiceSettings,
|
|
1223
|
-
timeoutMs: config.timeoutMs
|
|
1224
|
-
});
|
|
1225
|
-
} else {
|
|
1226
|
-
const openaiModelOverride = params.overrides?.openai?.model;
|
|
1227
|
-
const openaiVoiceOverride = params.overrides?.openai?.voice;
|
|
1228
|
-
audioBuffer = await openaiTTS({
|
|
1229
|
-
text: params.text,
|
|
1230
|
-
apiKey,
|
|
1231
|
-
model: openaiModelOverride ?? config.openai.model,
|
|
1232
|
-
voice: openaiVoiceOverride ?? config.openai.voice,
|
|
1233
|
-
responseFormat: output.openai,
|
|
1234
|
-
timeoutMs: config.timeoutMs
|
|
1235
|
-
});
|
|
1236
|
-
}
|
|
1237
|
-
const latencyMs = Date.now() - providerStart;
|
|
1238
|
-
const tempDir = mkdtempSync(path.join(tmpdir(), "tts-"));
|
|
1239
|
-
const audioPath = path.join(tempDir, `voice-${Date.now()}${output.extension}`);
|
|
1240
|
-
writeFileSync(audioPath, audioBuffer);
|
|
1241
|
-
scheduleCleanup(tempDir);
|
|
1242
|
-
return {
|
|
1243
|
-
success: true,
|
|
1244
|
-
audioPath,
|
|
1245
|
-
latencyMs,
|
|
1246
|
-
provider,
|
|
1247
|
-
outputFormat: provider === "openai" ? output.openai : output.elevenlabs,
|
|
1248
|
-
voiceCompatible: output.voiceCompatible
|
|
1249
|
-
};
|
|
1250
|
-
} catch (err) {
|
|
1251
|
-
const error = err;
|
|
1252
|
-
if (error.name === "AbortError") lastError = `${provider}: request timed out`;
|
|
1253
|
-
else lastError = `${provider}: ${error.message}`;
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
return {
|
|
1257
|
-
success: false,
|
|
1258
|
-
error: `TTS conversion failed: ${lastError || "no providers available"}`
|
|
1259
|
-
};
|
|
1260
|
-
}
|
|
1261
|
-
async function textToSpeechTelephony(params) {
|
|
1262
|
-
const config = resolveTtsConfig(params.cfg);
|
|
1263
|
-
const prefsPath = params.prefsPath ?? resolveTtsPrefsPath(config);
|
|
1264
|
-
if (params.text.length > config.maxTextLength) return {
|
|
1265
|
-
success: false,
|
|
1266
|
-
error: `Text too long (${params.text.length} chars, max ${config.maxTextLength})`
|
|
1267
|
-
};
|
|
1268
|
-
const providers = resolveTtsProviderOrder(getTtsProvider(config, prefsPath));
|
|
1269
|
-
let lastError;
|
|
1270
|
-
for (const provider of providers) {
|
|
1271
|
-
const providerStart = Date.now();
|
|
1272
|
-
try {
|
|
1273
|
-
if (provider === "edge") {
|
|
1274
|
-
lastError = "edge: unsupported for telephony";
|
|
1275
|
-
continue;
|
|
1276
|
-
}
|
|
1277
|
-
const apiKey = resolveTtsApiKey(config, provider);
|
|
1278
|
-
if (!apiKey) {
|
|
1279
|
-
lastError = `No API key for ${provider}`;
|
|
1280
|
-
continue;
|
|
1281
|
-
}
|
|
1282
|
-
if (provider === "elevenlabs") {
|
|
1283
|
-
const output = TELEPHONY_OUTPUT.elevenlabs;
|
|
1284
|
-
return {
|
|
1285
|
-
success: true,
|
|
1286
|
-
audioBuffer: await elevenLabsTTS({
|
|
1287
|
-
text: params.text,
|
|
1288
|
-
apiKey,
|
|
1289
|
-
baseUrl: config.elevenlabs.baseUrl,
|
|
1290
|
-
voiceId: config.elevenlabs.voiceId,
|
|
1291
|
-
modelId: config.elevenlabs.modelId,
|
|
1292
|
-
outputFormat: output.format,
|
|
1293
|
-
seed: config.elevenlabs.seed,
|
|
1294
|
-
applyTextNormalization: config.elevenlabs.applyTextNormalization,
|
|
1295
|
-
languageCode: config.elevenlabs.languageCode,
|
|
1296
|
-
voiceSettings: config.elevenlabs.voiceSettings,
|
|
1297
|
-
timeoutMs: config.timeoutMs
|
|
1298
|
-
}),
|
|
1299
|
-
latencyMs: Date.now() - providerStart,
|
|
1300
|
-
provider,
|
|
1301
|
-
outputFormat: output.format,
|
|
1302
|
-
sampleRate: output.sampleRate
|
|
1303
|
-
};
|
|
1304
|
-
}
|
|
1305
|
-
const output = TELEPHONY_OUTPUT.openai;
|
|
1306
|
-
return {
|
|
1307
|
-
success: true,
|
|
1308
|
-
audioBuffer: await openaiTTS({
|
|
1309
|
-
text: params.text,
|
|
1310
|
-
apiKey,
|
|
1311
|
-
model: config.openai.model,
|
|
1312
|
-
voice: config.openai.voice,
|
|
1313
|
-
responseFormat: output.format,
|
|
1314
|
-
timeoutMs: config.timeoutMs
|
|
1315
|
-
}),
|
|
1316
|
-
latencyMs: Date.now() - providerStart,
|
|
1317
|
-
provider,
|
|
1318
|
-
outputFormat: output.format,
|
|
1319
|
-
sampleRate: output.sampleRate
|
|
1320
|
-
};
|
|
1321
|
-
} catch (err) {
|
|
1322
|
-
const error = err;
|
|
1323
|
-
if (error.name === "AbortError") lastError = `${provider}: request timed out`;
|
|
1324
|
-
else lastError = `${provider}: ${error.message}`;
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
return {
|
|
1328
|
-
success: false,
|
|
1329
|
-
error: `TTS conversion failed: ${lastError || "no providers available"}`
|
|
1330
|
-
};
|
|
1331
|
-
}
|
|
1332
|
-
async function maybeApplyTtsToPayload(params) {
|
|
1333
|
-
const config = resolveTtsConfig(params.cfg);
|
|
1334
|
-
const prefsPath = resolveTtsPrefsPath(config);
|
|
1335
|
-
const autoMode = resolveTtsAutoMode({
|
|
1336
|
-
config,
|
|
1337
|
-
prefsPath,
|
|
1338
|
-
sessionAuto: params.ttsAuto
|
|
1339
|
-
});
|
|
1340
|
-
if (autoMode === "off") return params.payload;
|
|
1341
|
-
const text = params.payload.text ?? "";
|
|
1342
|
-
const directives = parseTtsDirectives(text, config.modelOverrides);
|
|
1343
|
-
if (directives.warnings.length > 0) logVerbose(`TTS: ignored directive overrides (${directives.warnings.join("; ")})`);
|
|
1344
|
-
const trimmedCleaned = directives.cleanedText.trim();
|
|
1345
|
-
const visibleText = trimmedCleaned.length > 0 ? trimmedCleaned : "";
|
|
1346
|
-
const ttsText = directives.ttsText?.trim() || visibleText;
|
|
1347
|
-
const nextPayload = visibleText === text.trim() ? params.payload : {
|
|
1348
|
-
...params.payload,
|
|
1349
|
-
text: visibleText.length > 0 ? visibleText : void 0
|
|
1350
|
-
};
|
|
1351
|
-
if (autoMode === "tagged" && !directives.hasDirective) return nextPayload;
|
|
1352
|
-
if (autoMode === "inbound" && params.inboundAudio !== true) return nextPayload;
|
|
1353
|
-
if ((config.mode ?? "final") === "final" && params.kind && params.kind !== "final") return nextPayload;
|
|
1354
|
-
if (!ttsText.trim()) return nextPayload;
|
|
1355
|
-
if (params.payload.mediaUrl || (params.payload.mediaUrls?.length ?? 0) > 0) return nextPayload;
|
|
1356
|
-
if (text.includes("MEDIA:")) return nextPayload;
|
|
1357
|
-
if (ttsText.trim().length < 10) return nextPayload;
|
|
1358
|
-
const maxLength = getTtsMaxLength(prefsPath);
|
|
1359
|
-
let textForAudio = ttsText.trim();
|
|
1360
|
-
let wasSummarized = false;
|
|
1361
|
-
if (textForAudio.length > maxLength) if (!isSummarizationEnabled(prefsPath)) {
|
|
1362
|
-
logVerbose(`TTS: truncating long text (${textForAudio.length} > ${maxLength}), summarization disabled.`);
|
|
1363
|
-
textForAudio = `${textForAudio.slice(0, maxLength - 3)}...`;
|
|
1364
|
-
} else try {
|
|
1365
|
-
textForAudio = (await summarizeText({
|
|
1366
|
-
text: textForAudio,
|
|
1367
|
-
targetLength: maxLength,
|
|
1368
|
-
cfg: params.cfg,
|
|
1369
|
-
config,
|
|
1370
|
-
timeoutMs: config.timeoutMs
|
|
1371
|
-
})).summary;
|
|
1372
|
-
wasSummarized = true;
|
|
1373
|
-
if (textForAudio.length > config.maxTextLength) {
|
|
1374
|
-
logVerbose(`TTS: summary exceeded hard limit (${textForAudio.length} > ${config.maxTextLength}); truncating.`);
|
|
1375
|
-
textForAudio = `${textForAudio.slice(0, config.maxTextLength - 3)}...`;
|
|
1376
|
-
}
|
|
1377
|
-
} catch (err) {
|
|
1378
|
-
logVerbose(`TTS: summarization failed, truncating instead: ${err.message}`);
|
|
1379
|
-
textForAudio = `${textForAudio.slice(0, maxLength - 3)}...`;
|
|
1380
|
-
}
|
|
1381
|
-
textForAudio = stripMarkdown(textForAudio).trim();
|
|
1382
|
-
if (textForAudio.length < 10) return nextPayload;
|
|
1383
|
-
const ttsStart = Date.now();
|
|
1384
|
-
const result = await textToSpeech({
|
|
1385
|
-
text: textForAudio,
|
|
1386
|
-
cfg: params.cfg,
|
|
1387
|
-
prefsPath,
|
|
1388
|
-
channel: params.channel,
|
|
1389
|
-
overrides: directives.overrides
|
|
1390
|
-
});
|
|
1391
|
-
if (result.success && result.audioPath) {
|
|
1392
|
-
lastTtsAttempt = {
|
|
1393
|
-
timestamp: Date.now(),
|
|
1394
|
-
success: true,
|
|
1395
|
-
textLength: text.length,
|
|
1396
|
-
summarized: wasSummarized,
|
|
1397
|
-
provider: result.provider,
|
|
1398
|
-
latencyMs: result.latencyMs
|
|
1399
|
-
};
|
|
1400
|
-
const shouldVoice = resolveChannelId(params.channel) === "telegram" && result.voiceCompatible === true;
|
|
1401
|
-
return {
|
|
1402
|
-
...nextPayload,
|
|
1403
|
-
mediaUrl: result.audioPath,
|
|
1404
|
-
audioAsVoice: shouldVoice || params.payload.audioAsVoice
|
|
1405
|
-
};
|
|
1406
|
-
}
|
|
1407
|
-
lastTtsAttempt = {
|
|
1408
|
-
timestamp: Date.now(),
|
|
1409
|
-
success: false,
|
|
1410
|
-
textLength: text.length,
|
|
1411
|
-
summarized: wasSummarized,
|
|
1412
|
-
error: result.error
|
|
1413
|
-
};
|
|
1414
|
-
logVerbose(`TTS: conversion failed after ${Date.now() - ttsStart}ms (${result.error ?? "unknown"}).`);
|
|
1415
|
-
return nextPayload;
|
|
1416
|
-
}
|
|
1417
|
-
|
|
1418
|
-
//#endregion
|
|
1419
|
-
//#region src/agents/model-alias-lines.ts
|
|
1420
|
-
function buildModelAliasLines(cfg) {
|
|
1421
|
-
const models = cfg?.agents?.defaults?.models ?? {};
|
|
1422
|
-
const entries = [];
|
|
1423
|
-
for (const [keyRaw, entryRaw] of Object.entries(models)) {
|
|
1424
|
-
const model = String(keyRaw ?? "").trim();
|
|
1425
|
-
if (!model) continue;
|
|
1426
|
-
const alias = String(entryRaw?.alias ?? "").trim();
|
|
1427
|
-
if (!alias) continue;
|
|
1428
|
-
entries.push({
|
|
1429
|
-
alias,
|
|
1430
|
-
model
|
|
1431
|
-
});
|
|
1432
|
-
}
|
|
1433
|
-
return entries.toSorted((a, b) => a.alias.localeCompare(b.alias)).map((entry) => `- ${entry.alias}: ${entry.model}`);
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
|
-
//#endregion
|
|
1437
|
-
//#region src/agents/shell-utils.ts
|
|
1438
|
-
function resolvePowerShellPath() {
|
|
1439
|
-
const systemRoot = process.env.SystemRoot || process.env.WINDIR;
|
|
1440
|
-
if (systemRoot) {
|
|
1441
|
-
const candidate = path.join(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
1442
|
-
if (fs$1.existsSync(candidate)) return candidate;
|
|
1443
|
-
}
|
|
1444
|
-
return "powershell.exe";
|
|
1445
|
-
}
|
|
1446
|
-
function getShellConfig() {
|
|
1447
|
-
if (process.platform === "win32") return {
|
|
1448
|
-
shell: resolvePowerShellPath(),
|
|
1449
|
-
args: [
|
|
1450
|
-
"-NoProfile",
|
|
1451
|
-
"-NonInteractive",
|
|
1452
|
-
"-Command"
|
|
1453
|
-
]
|
|
1454
|
-
};
|
|
1455
|
-
const envShell = process.env.SHELL?.trim();
|
|
1456
|
-
if ((envShell ? path.basename(envShell) : "") === "fish") {
|
|
1457
|
-
const bash = resolveShellFromPath("bash");
|
|
1458
|
-
if (bash) return {
|
|
1459
|
-
shell: bash,
|
|
1460
|
-
args: ["-c"]
|
|
1461
|
-
};
|
|
1462
|
-
const sh = resolveShellFromPath("sh");
|
|
1463
|
-
if (sh) return {
|
|
1464
|
-
shell: sh,
|
|
1465
|
-
args: ["-c"]
|
|
1466
|
-
};
|
|
1467
|
-
}
|
|
1468
|
-
return {
|
|
1469
|
-
shell: envShell && envShell.length > 0 ? envShell : "sh",
|
|
1470
|
-
args: ["-c"]
|
|
1471
|
-
};
|
|
1472
|
-
}
|
|
1473
|
-
function resolveShellFromPath(name) {
|
|
1474
|
-
const envPath = process.env.PATH ?? "";
|
|
1475
|
-
if (!envPath) return;
|
|
1476
|
-
const entries = envPath.split(path.delimiter).filter(Boolean);
|
|
1477
|
-
for (const entry of entries) {
|
|
1478
|
-
const candidate = path.join(entry, name);
|
|
1479
|
-
try {
|
|
1480
|
-
fs$1.accessSync(candidate, fs$1.constants.X_OK);
|
|
1481
|
-
return candidate;
|
|
1482
|
-
} catch {}
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
function normalizeShellName(value) {
|
|
1486
|
-
const trimmed = value.trim();
|
|
1487
|
-
if (!trimmed) return "";
|
|
1488
|
-
return path.basename(trimmed).replace(/\.(exe|cmd|bat)$/i, "").replace(/[^a-zA-Z0-9_-]/g, "");
|
|
1489
|
-
}
|
|
1490
|
-
function detectRuntimeShell() {
|
|
1491
|
-
const overrideShell = process.env.ANIMA_SHELL?.trim();
|
|
1492
|
-
if (overrideShell) {
|
|
1493
|
-
const name = normalizeShellName(overrideShell);
|
|
1494
|
-
if (name) return name;
|
|
1495
|
-
}
|
|
1496
|
-
if (process.platform === "win32") {
|
|
1497
|
-
if (process.env.POWERSHELL_DISTRIBUTION_CHANNEL) return "pwsh";
|
|
1498
|
-
return "powershell";
|
|
1499
|
-
}
|
|
1500
|
-
const envShell = process.env.SHELL?.trim();
|
|
1501
|
-
if (envShell) {
|
|
1502
|
-
const name = normalizeShellName(envShell);
|
|
1503
|
-
if (name) return name;
|
|
1504
|
-
}
|
|
1505
|
-
if (process.env.POWERSHELL_DISTRIBUTION_CHANNEL) return "pwsh";
|
|
1506
|
-
if (process.env.BASH_VERSION) return "bash";
|
|
1507
|
-
if (process.env.ZSH_VERSION) return "zsh";
|
|
1508
|
-
if (process.env.FISH_VERSION) return "fish";
|
|
1509
|
-
if (process.env.KSH_VERSION) return "ksh";
|
|
1510
|
-
if (process.env.NU_VERSION || process.env.NUSHELL_VERSION) return "nu";
|
|
1511
|
-
}
|
|
1512
|
-
function sanitizeBinaryOutput(text) {
|
|
1513
|
-
const scrubbed = text.replace(/[\p{Format}\p{Surrogate}]/gu, "");
|
|
1514
|
-
if (!scrubbed) return scrubbed;
|
|
1515
|
-
const chunks = [];
|
|
1516
|
-
for (const char of scrubbed) {
|
|
1517
|
-
const code = char.codePointAt(0);
|
|
1518
|
-
if (code == null) continue;
|
|
1519
|
-
if (code === 9 || code === 10 || code === 13) {
|
|
1520
|
-
chunks.push(char);
|
|
1521
|
-
continue;
|
|
1522
|
-
}
|
|
1523
|
-
if (code < 32) continue;
|
|
1524
|
-
chunks.push(char);
|
|
1525
|
-
}
|
|
1526
|
-
return chunks.join("");
|
|
1527
|
-
}
|
|
1528
|
-
function killProcessTree(pid) {
|
|
1529
|
-
if (process.platform === "win32") {
|
|
1530
|
-
try {
|
|
1531
|
-
spawn("taskkill", [
|
|
1532
|
-
"/F",
|
|
1533
|
-
"/T",
|
|
1534
|
-
"/PID",
|
|
1535
|
-
String(pid)
|
|
1536
|
-
], {
|
|
1537
|
-
stdio: "ignore",
|
|
1538
|
-
detached: true
|
|
1539
|
-
});
|
|
1540
|
-
} catch {}
|
|
1541
|
-
return;
|
|
1542
|
-
}
|
|
1543
|
-
try {
|
|
1544
|
-
process.kill(-pid, "SIGKILL");
|
|
1545
|
-
} catch {
|
|
1546
|
-
try {
|
|
1547
|
-
process.kill(pid, "SIGKILL");
|
|
1548
|
-
} catch {}
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
|
|
1552
|
-
//#endregion
|
|
1553
|
-
//#region src/agents/date-time.ts
|
|
1554
|
-
let cachedTimeFormat;
|
|
1555
|
-
function resolveUserTimezone(configured) {
|
|
1556
|
-
const trimmed = configured?.trim();
|
|
1557
|
-
if (trimmed) try {
|
|
1558
|
-
new Intl.DateTimeFormat("en-US", { timeZone: trimmed }).format(/* @__PURE__ */ new Date());
|
|
1559
|
-
return trimmed;
|
|
1560
|
-
} catch {}
|
|
1561
|
-
return Intl.DateTimeFormat().resolvedOptions().timeZone?.trim() || "UTC";
|
|
1562
|
-
}
|
|
1563
|
-
function resolveUserTimeFormat(preference) {
|
|
1564
|
-
if (preference === "12" || preference === "24") return preference;
|
|
1565
|
-
if (cachedTimeFormat) return cachedTimeFormat;
|
|
1566
|
-
cachedTimeFormat = detectSystemTimeFormat() ? "24" : "12";
|
|
1567
|
-
return cachedTimeFormat;
|
|
1568
|
-
}
|
|
1569
|
-
function normalizeTimestamp(raw) {
|
|
1570
|
-
if (raw == null) return;
|
|
1571
|
-
let timestampMs;
|
|
1572
|
-
if (raw instanceof Date) timestampMs = raw.getTime();
|
|
1573
|
-
else if (typeof raw === "number" && Number.isFinite(raw)) timestampMs = raw < 0xe8d4a51000 ? Math.round(raw * 1e3) : Math.round(raw);
|
|
1574
|
-
else if (typeof raw === "string") {
|
|
1575
|
-
const trimmed = raw.trim();
|
|
1576
|
-
if (!trimmed) return;
|
|
1577
|
-
if (/^\d+(\.\d+)?$/.test(trimmed)) {
|
|
1578
|
-
const num = Number(trimmed);
|
|
1579
|
-
if (Number.isFinite(num)) if (trimmed.includes(".")) timestampMs = Math.round(num * 1e3);
|
|
1580
|
-
else if (trimmed.length >= 13) timestampMs = Math.round(num);
|
|
1581
|
-
else timestampMs = Math.round(num * 1e3);
|
|
1582
|
-
} else {
|
|
1583
|
-
const parsed = Date.parse(trimmed);
|
|
1584
|
-
if (!Number.isNaN(parsed)) timestampMs = parsed;
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
if (timestampMs === void 0 || !Number.isFinite(timestampMs)) return;
|
|
1588
|
-
return {
|
|
1589
|
-
timestampMs,
|
|
1590
|
-
timestampUtc: new Date(timestampMs).toISOString()
|
|
1591
|
-
};
|
|
1592
|
-
}
|
|
1593
|
-
function withNormalizedTimestamp(value, rawTimestamp) {
|
|
1594
|
-
const normalized = normalizeTimestamp(rawTimestamp);
|
|
1595
|
-
if (!normalized) return value;
|
|
1596
|
-
return {
|
|
1597
|
-
...value,
|
|
1598
|
-
timestampMs: typeof value.timestampMs === "number" && Number.isFinite(value.timestampMs) ? value.timestampMs : normalized.timestampMs,
|
|
1599
|
-
timestampUtc: typeof value.timestampUtc === "string" && value.timestampUtc.trim() ? value.timestampUtc : normalized.timestampUtc
|
|
1600
|
-
};
|
|
1601
|
-
}
|
|
1602
|
-
function detectSystemTimeFormat() {
|
|
1603
|
-
if (process.platform === "darwin") try {
|
|
1604
|
-
const result = execSync("defaults read -g AppleICUForce24HourTime 2>/dev/null", {
|
|
1605
|
-
encoding: "utf8",
|
|
1606
|
-
timeout: 500
|
|
1607
|
-
}).trim();
|
|
1608
|
-
if (result === "1") return true;
|
|
1609
|
-
if (result === "0") return false;
|
|
1610
|
-
} catch {}
|
|
1611
|
-
if (process.platform === "win32") try {
|
|
1612
|
-
const result = execSync("powershell -Command \"(Get-Culture).DateTimeFormat.ShortTimePattern\"", {
|
|
1613
|
-
encoding: "utf8",
|
|
1614
|
-
timeout: 1e3
|
|
1615
|
-
}).trim();
|
|
1616
|
-
if (result.startsWith("H")) return true;
|
|
1617
|
-
if (result.startsWith("h")) return false;
|
|
1618
|
-
} catch {}
|
|
1619
|
-
try {
|
|
1620
|
-
const sample = new Date(2e3, 0, 1, 13, 0);
|
|
1621
|
-
return new Intl.DateTimeFormat(void 0, { hour: "numeric" }).format(sample).includes("13");
|
|
1622
|
-
} catch {
|
|
1623
|
-
return false;
|
|
1624
|
-
}
|
|
1625
|
-
}
|
|
1626
|
-
function ordinalSuffix(day) {
|
|
1627
|
-
if (day >= 11 && day <= 13) return "th";
|
|
1628
|
-
switch (day % 10) {
|
|
1629
|
-
case 1: return "st";
|
|
1630
|
-
case 2: return "nd";
|
|
1631
|
-
case 3: return "rd";
|
|
1632
|
-
default: return "th";
|
|
1633
|
-
}
|
|
1634
|
-
}
|
|
1635
|
-
function formatUserTime(date, timeZone, format) {
|
|
1636
|
-
const use24Hour = format === "24";
|
|
1637
|
-
try {
|
|
1638
|
-
const parts = new Intl.DateTimeFormat("en-US", {
|
|
1639
|
-
timeZone,
|
|
1640
|
-
weekday: "long",
|
|
1641
|
-
year: "numeric",
|
|
1642
|
-
month: "long",
|
|
1643
|
-
day: "numeric",
|
|
1644
|
-
hour: use24Hour ? "2-digit" : "numeric",
|
|
1645
|
-
minute: "2-digit",
|
|
1646
|
-
hourCycle: use24Hour ? "h23" : "h12"
|
|
1647
|
-
}).formatToParts(date);
|
|
1648
|
-
const map = {};
|
|
1649
|
-
for (const part of parts) if (part.type !== "literal") map[part.type] = part.value;
|
|
1650
|
-
if (!map.weekday || !map.year || !map.month || !map.day || !map.hour || !map.minute) return;
|
|
1651
|
-
const dayNum = parseInt(map.day, 10);
|
|
1652
|
-
const suffix = ordinalSuffix(dayNum);
|
|
1653
|
-
const timePart = use24Hour ? `${map.hour}:${map.minute}` : `${map.hour}:${map.minute} ${map.dayPeriod ?? ""}`.trim();
|
|
1654
|
-
return `${map.weekday}, ${map.month} ${dayNum}${suffix}, ${map.year} — ${timePart}`;
|
|
1655
|
-
} catch {
|
|
1656
|
-
return;
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
|
|
1660
|
-
//#endregion
|
|
1661
|
-
//#region src/agents/system-prompt-params.ts
|
|
1662
|
-
function buildSystemPromptParams(params) {
|
|
1663
|
-
const repoRoot = resolveRepoRoot({
|
|
1664
|
-
config: params.config,
|
|
1665
|
-
workspaceDir: params.workspaceDir,
|
|
1666
|
-
cwd: params.cwd
|
|
1667
|
-
});
|
|
1668
|
-
const userTimezone = resolveUserTimezone(params.config?.agents?.defaults?.userTimezone);
|
|
1669
|
-
const userTimeFormat = resolveUserTimeFormat(params.config?.agents?.defaults?.timeFormat);
|
|
1670
|
-
const userTime = formatUserTime(/* @__PURE__ */ new Date(), userTimezone, userTimeFormat);
|
|
1671
|
-
return {
|
|
1672
|
-
runtimeInfo: {
|
|
1673
|
-
agentId: params.agentId,
|
|
1674
|
-
...params.runtime,
|
|
1675
|
-
repoRoot
|
|
1676
|
-
},
|
|
1677
|
-
userTimezone,
|
|
1678
|
-
userTime,
|
|
1679
|
-
userTimeFormat
|
|
1680
|
-
};
|
|
1681
|
-
}
|
|
1682
|
-
function resolveRepoRoot(params) {
|
|
1683
|
-
const configured = params.config?.agents?.defaults?.repoRoot?.trim();
|
|
1684
|
-
if (configured) try {
|
|
1685
|
-
const resolved = path.resolve(configured);
|
|
1686
|
-
if (fs$1.statSync(resolved).isDirectory()) return resolved;
|
|
1687
|
-
} catch {}
|
|
1688
|
-
const candidates = [params.workspaceDir, params.cwd].map((value) => value?.trim()).filter(Boolean);
|
|
1689
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1690
|
-
for (const candidate of candidates) {
|
|
1691
|
-
const resolved = path.resolve(candidate);
|
|
1692
|
-
if (seen.has(resolved)) continue;
|
|
1693
|
-
seen.add(resolved);
|
|
1694
|
-
const root = findGitRoot(resolved);
|
|
1695
|
-
if (root) return root;
|
|
1696
|
-
}
|
|
1697
|
-
}
|
|
1698
|
-
function findGitRoot(startDir) {
|
|
1699
|
-
let current = path.resolve(startDir);
|
|
1700
|
-
for (let i = 0; i < 12; i += 1) {
|
|
1701
|
-
const gitPath = path.join(current, ".git");
|
|
1702
|
-
try {
|
|
1703
|
-
const stat = fs$1.statSync(gitPath);
|
|
1704
|
-
if (stat.isDirectory() || stat.isFile()) return current;
|
|
1705
|
-
} catch {}
|
|
1706
|
-
const parent = path.dirname(current);
|
|
1707
|
-
if (parent === current) break;
|
|
1708
|
-
current = parent;
|
|
1709
|
-
}
|
|
1710
|
-
return null;
|
|
1711
|
-
}
|
|
1712
|
-
|
|
1713
|
-
//#endregion
|
|
1714
|
-
//#region src/agents/system-prompt.ts
|
|
1715
|
-
function buildSkillsSection(params) {
|
|
1716
|
-
if (params.isMinimal) return [];
|
|
1717
|
-
const trimmed = params.skillsPrompt?.trim();
|
|
1718
|
-
if (!trimmed) return [];
|
|
1719
|
-
return [
|
|
1720
|
-
"## Skills (mandatory)",
|
|
1721
|
-
"Before replying: scan <available_skills> <description> entries.",
|
|
1722
|
-
`- If exactly one skill clearly applies: read its SKILL.md at <location> with \`${params.readToolName}\`, then follow it.`,
|
|
1723
|
-
"- If multiple could apply: choose the most specific one, then read/follow it.",
|
|
1724
|
-
"- If none clearly apply: do not read any SKILL.md.",
|
|
1725
|
-
"Constraints: never read more than one skill up front; only read after selecting.",
|
|
1726
|
-
trimmed,
|
|
1727
|
-
""
|
|
1728
|
-
];
|
|
1729
|
-
}
|
|
1730
|
-
function buildMemorySection(params) {
|
|
1731
|
-
if (params.isMinimal) return [];
|
|
1732
|
-
if (!params.availableTools.has("memory_search") && !params.availableTools.has("memory_get")) return [];
|
|
1733
|
-
const lines = ["## Memory Recall", "Before answering anything about prior work, decisions, dates, people, preferences, or todos: run memory_search on MEMORY.md + memory/*.md; then use memory_get to pull only the needed lines. If low confidence after search, say you checked."];
|
|
1734
|
-
if (params.citationsMode === "off") lines.push("Citations are disabled: do not mention file paths or line numbers in replies unless the user explicitly asks.");
|
|
1735
|
-
else lines.push("Citations: include Source: <path#line> when it helps the user verify memory snippets.");
|
|
1736
|
-
lines.push("");
|
|
1737
|
-
return lines;
|
|
1738
|
-
}
|
|
1739
|
-
function buildUserIdentitySection(ownerLine, isMinimal) {
|
|
1740
|
-
if (!ownerLine || isMinimal) return [];
|
|
1741
|
-
return [
|
|
1742
|
-
"## User Identity",
|
|
1743
|
-
ownerLine,
|
|
1744
|
-
""
|
|
1745
|
-
];
|
|
1746
|
-
}
|
|
1747
|
-
function buildTimeSection(params) {
|
|
1748
|
-
if (!params.userTimezone) return [];
|
|
1749
|
-
return [
|
|
1750
|
-
"## Current Date & Time",
|
|
1751
|
-
`Time zone: ${params.userTimezone}`,
|
|
1752
|
-
""
|
|
1753
|
-
];
|
|
1754
|
-
}
|
|
1755
|
-
function buildReplyTagsSection(isMinimal) {
|
|
1756
|
-
if (isMinimal) return [];
|
|
1757
|
-
return [
|
|
1758
|
-
"## Reply Tags",
|
|
1759
|
-
"To request a native reply/quote on supported surfaces, include one tag in your reply:",
|
|
1760
|
-
"- [[reply_to_current]] replies to the triggering message.",
|
|
1761
|
-
"- Prefer [[reply_to_current]]. Use [[reply_to:<id>]] only when an id was explicitly provided (e.g. by the user or a tool).",
|
|
1762
|
-
"Whitespace inside the tag is allowed (e.g. [[ reply_to_current ]] / [[ reply_to: 123 ]]).",
|
|
1763
|
-
"Tags are stripped before sending; support depends on the current channel config.",
|
|
1764
|
-
""
|
|
1765
|
-
];
|
|
1766
|
-
}
|
|
1767
|
-
function buildMessagingSection(params) {
|
|
1768
|
-
if (params.isMinimal) return [];
|
|
1769
|
-
return [
|
|
1770
|
-
"## Messaging",
|
|
1771
|
-
"- Reply in current session → automatically routes to the source channel (Signal, Telegram, etc.)",
|
|
1772
|
-
"- Cross-session messaging → use sessions_send(sessionKey, message)",
|
|
1773
|
-
"- Sub-agent orchestration → use subagents(action=list|steer|kill)",
|
|
1774
|
-
"- `[System Message] ...` blocks are internal context and are not user-visible by default.",
|
|
1775
|
-
"- If a `[System Message]` reports completed cron/subagent work and asks for a user update, rewrite it in your normal assistant voice and send that update (do not forward raw system text or default to NO_REPLY).",
|
|
1776
|
-
"- Never use exec/curl for provider messaging; Anima handles all routing internally.",
|
|
1777
|
-
params.availableTools.has("message") ? [
|
|
1778
|
-
"",
|
|
1779
|
-
"### message tool",
|
|
1780
|
-
"- Use `message` for proactive sends + channel actions (polls, reactions, etc.).",
|
|
1781
|
-
"- For `action=send`, include `to` and `message`.",
|
|
1782
|
-
`- If multiple channels are configured, pass \`channel\` (${params.messageChannelOptions}).`,
|
|
1783
|
-
`- If you use \`message\` (\`action=send\`) to deliver your user-visible reply, respond with ONLY: ${SILENT_REPLY_TOKEN} (avoid duplicate replies).`,
|
|
1784
|
-
params.inlineButtonsEnabled ? "- Inline buttons supported. Use `action=send` with `buttons=[[{text,callback_data}]]` (callback_data routes back as a user message)." : params.runtimeChannel ? `- Inline buttons not enabled for ${params.runtimeChannel}. If you need them, ask to set ${params.runtimeChannel}.capabilities.inlineButtons ("dm"|"group"|"all"|"allowlist").` : "",
|
|
1785
|
-
...params.messageToolHints ?? []
|
|
1786
|
-
].filter(Boolean).join("\n") : "",
|
|
1787
|
-
""
|
|
1788
|
-
];
|
|
1789
|
-
}
|
|
1790
|
-
function buildVoiceSection(params) {
|
|
1791
|
-
if (params.isMinimal) return [];
|
|
1792
|
-
const hint = params.ttsHint?.trim();
|
|
1793
|
-
if (!hint) return [];
|
|
1794
|
-
return [
|
|
1795
|
-
"## Voice (TTS)",
|
|
1796
|
-
hint,
|
|
1797
|
-
""
|
|
1798
|
-
];
|
|
1799
|
-
}
|
|
1800
|
-
function buildDocsSection(params) {
|
|
1801
|
-
const docsPath = params.docsPath?.trim();
|
|
1802
|
-
if (!docsPath || params.isMinimal) return [];
|
|
1803
|
-
return [
|
|
1804
|
-
"## Documentation",
|
|
1805
|
-
`Anima docs: ${docsPath}`,
|
|
1806
|
-
"Mirror: https://docs.anima.ai",
|
|
1807
|
-
"Source: https://github.com/anima/anima",
|
|
1808
|
-
"Community: https://discord.com/invite/clawd",
|
|
1809
|
-
"Find new skills: https://animahub.com",
|
|
1810
|
-
"For Anima behavior, commands, config, or architecture: consult local docs first.",
|
|
1811
|
-
"When diagnosing issues, run `anima status` yourself when possible; only ask the user if you lack access (e.g., sandboxed).",
|
|
1812
|
-
""
|
|
1813
|
-
];
|
|
1814
|
-
}
|
|
1815
|
-
function buildAgentSystemPrompt(params) {
|
|
1816
|
-
const coreToolSummaries = {
|
|
1817
|
-
read: "Read file contents",
|
|
1818
|
-
write: "Create or overwrite files",
|
|
1819
|
-
edit: "Make precise edits to files",
|
|
1820
|
-
apply_patch: "Apply multi-file patches",
|
|
1821
|
-
grep: "Search file contents for patterns",
|
|
1822
|
-
find: "Find files by glob pattern",
|
|
1823
|
-
ls: "List directory contents",
|
|
1824
|
-
exec: "Run shell commands (pty available for TTY-required CLIs)",
|
|
1825
|
-
process: "Manage background exec sessions",
|
|
1826
|
-
web_search: "Search the web (Brave API)",
|
|
1827
|
-
web_fetch: "Fetch and extract readable content from a URL",
|
|
1828
|
-
browser: "Control web browser",
|
|
1829
|
-
canvas: "Present/eval/snapshot the Canvas",
|
|
1830
|
-
nodes: "List/describe/notify/camera/screen on paired nodes",
|
|
1831
|
-
cron: "Manage cron jobs and wake events (use for reminders; when scheduling a reminder, write the systemEvent text as something that will read like a reminder when it fires, and mention that it is a reminder depending on the time gap between setting and firing; include recent context in reminder text if appropriate)",
|
|
1832
|
-
message: "Send messages and channel actions",
|
|
1833
|
-
gateway: "Restart, apply config, or run updates on the running Anima process",
|
|
1834
|
-
agents_list: "List agent ids allowed for sessions_spawn",
|
|
1835
|
-
sessions_list: "List other sessions (incl. sub-agents) with filters/last",
|
|
1836
|
-
sessions_history: "Fetch history for another session/sub-agent",
|
|
1837
|
-
sessions_send: "Send a message to another session/sub-agent",
|
|
1838
|
-
sessions_spawn: "Spawn a sub-agent session",
|
|
1839
|
-
subagents: "List, steer, or kill sub-agent runs for this requester session",
|
|
1840
|
-
session_status: "Show a /status-equivalent status card (usage + time + Reasoning/Verbose/Elevated); use for model-use questions (📊 session_status); optional per-session model override",
|
|
1841
|
-
image: "Analyze an image with the configured image model"
|
|
1842
|
-
};
|
|
1843
|
-
const toolOrder = [
|
|
1844
|
-
"read",
|
|
1845
|
-
"write",
|
|
1846
|
-
"edit",
|
|
1847
|
-
"apply_patch",
|
|
1848
|
-
"grep",
|
|
1849
|
-
"find",
|
|
1850
|
-
"ls",
|
|
1851
|
-
"exec",
|
|
1852
|
-
"process",
|
|
1853
|
-
"web_search",
|
|
1854
|
-
"web_fetch",
|
|
1855
|
-
"browser",
|
|
1856
|
-
"canvas",
|
|
1857
|
-
"nodes",
|
|
1858
|
-
"cron",
|
|
1859
|
-
"message",
|
|
1860
|
-
"gateway",
|
|
1861
|
-
"agents_list",
|
|
1862
|
-
"sessions_list",
|
|
1863
|
-
"sessions_history",
|
|
1864
|
-
"sessions_send",
|
|
1865
|
-
"subagents",
|
|
1866
|
-
"session_status",
|
|
1867
|
-
"image"
|
|
1868
|
-
];
|
|
1869
|
-
const canonicalToolNames = (params.toolNames ?? []).map((tool) => tool.trim()).filter(Boolean);
|
|
1870
|
-
const canonicalByNormalized = /* @__PURE__ */ new Map();
|
|
1871
|
-
for (const name of canonicalToolNames) {
|
|
1872
|
-
const normalized = name.toLowerCase();
|
|
1873
|
-
if (!canonicalByNormalized.has(normalized)) canonicalByNormalized.set(normalized, name);
|
|
1874
|
-
}
|
|
1875
|
-
const resolveToolName = (normalized) => canonicalByNormalized.get(normalized) ?? normalized;
|
|
1876
|
-
const normalizedTools = canonicalToolNames.map((tool) => tool.toLowerCase());
|
|
1877
|
-
const availableTools = new Set(normalizedTools);
|
|
1878
|
-
const externalToolSummaries = /* @__PURE__ */ new Map();
|
|
1879
|
-
for (const [key, value] of Object.entries(params.toolSummaries ?? {})) {
|
|
1880
|
-
const normalized = key.trim().toLowerCase();
|
|
1881
|
-
if (!normalized || !value?.trim()) continue;
|
|
1882
|
-
externalToolSummaries.set(normalized, value.trim());
|
|
1883
|
-
}
|
|
1884
|
-
const extraTools = Array.from(new Set(normalizedTools.filter((tool) => !toolOrder.includes(tool))));
|
|
1885
|
-
const toolLines = toolOrder.filter((tool) => availableTools.has(tool)).map((tool) => {
|
|
1886
|
-
const summary = coreToolSummaries[tool] ?? externalToolSummaries.get(tool);
|
|
1887
|
-
const name = resolveToolName(tool);
|
|
1888
|
-
return summary ? `- ${name}: ${summary}` : `- ${name}`;
|
|
1889
|
-
});
|
|
1890
|
-
for (const tool of extraTools.toSorted()) {
|
|
1891
|
-
const summary = coreToolSummaries[tool] ?? externalToolSummaries.get(tool);
|
|
1892
|
-
const name = resolveToolName(tool);
|
|
1893
|
-
toolLines.push(summary ? `- ${name}: ${summary}` : `- ${name}`);
|
|
1894
|
-
}
|
|
1895
|
-
const hasGateway = availableTools.has("gateway");
|
|
1896
|
-
const readToolName = resolveToolName("read");
|
|
1897
|
-
const execToolName = resolveToolName("exec");
|
|
1898
|
-
const processToolName = resolveToolName("process");
|
|
1899
|
-
const extraSystemPrompt = params.extraSystemPrompt?.trim();
|
|
1900
|
-
const ownerNumbers = (params.ownerNumbers ?? []).map((value) => value.trim()).filter(Boolean);
|
|
1901
|
-
const ownerLine = ownerNumbers.length > 0 ? `Owner numbers: ${ownerNumbers.join(", ")}. Treat messages from these numbers as the user.` : void 0;
|
|
1902
|
-
const reasoningHint = params.reasoningTagHint ? [
|
|
1903
|
-
"ALL internal reasoning MUST be inside <think>...</think>.",
|
|
1904
|
-
"Do not output any analysis outside <think>.",
|
|
1905
|
-
"Format every reply as <think>...</think> then <final>...</final>, with no other text.",
|
|
1906
|
-
"Only the final user-visible reply may appear inside <final>.",
|
|
1907
|
-
"Only text inside <final> is shown to the user; everything else is discarded and never seen by the user.",
|
|
1908
|
-
"Example:",
|
|
1909
|
-
"<think>Short internal reasoning.</think>",
|
|
1910
|
-
"<final>Hey there! What would you like to do next?</final>"
|
|
1911
|
-
].join(" ") : void 0;
|
|
1912
|
-
const reasoningLevel = params.reasoningLevel ?? "off";
|
|
1913
|
-
const userTimezone = params.userTimezone?.trim();
|
|
1914
|
-
const skillsPrompt = params.skillsPrompt?.trim();
|
|
1915
|
-
const heartbeatPrompt = params.heartbeatPrompt?.trim();
|
|
1916
|
-
const heartbeatPromptLine = heartbeatPrompt ? `Heartbeat prompt: ${heartbeatPrompt}` : "Heartbeat prompt: (configured)";
|
|
1917
|
-
const runtimeInfo = params.runtimeInfo;
|
|
1918
|
-
const runtimeChannel = runtimeInfo?.channel?.trim().toLowerCase();
|
|
1919
|
-
const runtimeCapabilities = (runtimeInfo?.capabilities ?? []).map((cap) => String(cap).trim()).filter(Boolean);
|
|
1920
|
-
const inlineButtonsEnabled = new Set(runtimeCapabilities.map((cap) => cap.toLowerCase())).has("inlinebuttons");
|
|
1921
|
-
const messageChannelOptions = listDeliverableMessageChannels().join("|");
|
|
1922
|
-
const promptMode = params.promptMode ?? "full";
|
|
1923
|
-
const isMinimal = promptMode === "minimal" || promptMode === "none";
|
|
1924
|
-
const sandboxContainerWorkspace = params.sandboxInfo?.containerWorkspaceDir?.trim();
|
|
1925
|
-
const displayWorkspaceDir = params.sandboxInfo?.enabled && sandboxContainerWorkspace ? sandboxContainerWorkspace : params.workspaceDir;
|
|
1926
|
-
const workspaceGuidance = params.sandboxInfo?.enabled && sandboxContainerWorkspace ? `For read/write/edit/apply_patch, file paths resolve against host workspace: ${params.workspaceDir}. Prefer relative paths so both sandboxed exec and file tools work consistently.` : "Treat this directory as the single global workspace for file operations unless explicitly instructed otherwise.";
|
|
1927
|
-
const safetySection = [
|
|
1928
|
-
"## Safety",
|
|
1929
|
-
"You have no independent goals: do not pursue self-preservation, replication, resource acquisition, or power-seeking; avoid long-term plans beyond the user's request.",
|
|
1930
|
-
"Prioritize safety and human oversight over completion; if instructions conflict, pause and ask; comply with stop/pause/audit requests and never bypass safeguards. (Inspired by Anthropic's constitution.)",
|
|
1931
|
-
"Do not manipulate or persuade anyone to expand access or disable safeguards. Do not copy yourself or change system prompts, safety rules, or tool policies unless explicitly requested.",
|
|
1932
|
-
""
|
|
1933
|
-
];
|
|
1934
|
-
const skillsSection = buildSkillsSection({
|
|
1935
|
-
skillsPrompt,
|
|
1936
|
-
isMinimal,
|
|
1937
|
-
readToolName
|
|
1938
|
-
});
|
|
1939
|
-
const memorySection = buildMemorySection({
|
|
1940
|
-
isMinimal,
|
|
1941
|
-
availableTools,
|
|
1942
|
-
citationsMode: params.memoryCitationsMode
|
|
1943
|
-
});
|
|
1944
|
-
const docsSection = buildDocsSection({
|
|
1945
|
-
docsPath: params.docsPath,
|
|
1946
|
-
isMinimal,
|
|
1947
|
-
readToolName
|
|
1948
|
-
});
|
|
1949
|
-
const workspaceNotes = (params.workspaceNotes ?? []).map((note) => note.trim()).filter(Boolean);
|
|
1950
|
-
if (promptMode === "none") return "You are a personal assistant running inside Anima.";
|
|
1951
|
-
const lines = [
|
|
1952
|
-
"You are a personal assistant running inside Anima.",
|
|
1953
|
-
"",
|
|
1954
|
-
"## Tooling",
|
|
1955
|
-
"Tool availability (filtered by policy):",
|
|
1956
|
-
"Tool names are case-sensitive. Call tools exactly as listed.",
|
|
1957
|
-
toolLines.length > 0 ? toolLines.join("\n") : [
|
|
1958
|
-
"Pi lists the standard tools above. This runtime enables:",
|
|
1959
|
-
"- grep: search file contents for patterns",
|
|
1960
|
-
"- find: find files by glob pattern",
|
|
1961
|
-
"- ls: list directory contents",
|
|
1962
|
-
"- apply_patch: apply multi-file patches",
|
|
1963
|
-
`- ${execToolName}: run shell commands (supports background via yieldMs/background)`,
|
|
1964
|
-
`- ${processToolName}: manage background exec sessions`,
|
|
1965
|
-
`- For long waits, avoid rapid poll loops: use ${execToolName} with enough yieldMs or ${processToolName}(action=poll, timeout=<ms>).`,
|
|
1966
|
-
"- browser: control Anima's dedicated browser",
|
|
1967
|
-
"- canvas: present/eval/snapshot the Canvas",
|
|
1968
|
-
"- nodes: list/describe/notify/camera/screen on paired nodes",
|
|
1969
|
-
"- cron: manage cron jobs and wake events (use for reminders; when scheduling a reminder, write the systemEvent text as something that will read like a reminder when it fires, and mention that it is a reminder depending on the time gap between setting and firing; include recent context in reminder text if appropriate)",
|
|
1970
|
-
"- sessions_list: list sessions",
|
|
1971
|
-
"- sessions_history: fetch session history",
|
|
1972
|
-
"- sessions_send: send to another session",
|
|
1973
|
-
"- subagents: list/steer/kill sub-agent runs",
|
|
1974
|
-
"- session_status: show usage/time/model state and answer \"what model are we using?\""
|
|
1975
|
-
].join("\n"),
|
|
1976
|
-
"TOOLS.md does not control tool availability; it is user guidance for how to use external tools.",
|
|
1977
|
-
"If a task is more complex or takes longer, spawn a sub-agent. Completion is push-based: it will auto-announce when done.",
|
|
1978
|
-
"Do not poll `subagents list` / `sessions_list` in a loop; only check status on-demand (for intervention, debugging, or when explicitly asked).",
|
|
1979
|
-
"",
|
|
1980
|
-
"## Tool Call Style",
|
|
1981
|
-
"Default: do not narrate routine, low-risk tool calls (just call the tool).",
|
|
1982
|
-
"Narrate only when it helps: multi-step work, complex/challenging problems, sensitive actions (e.g., deletions), or when the user explicitly asks.",
|
|
1983
|
-
"Keep narration brief and value-dense; avoid repeating obvious steps.",
|
|
1984
|
-
"Use plain human language for narration unless in a technical context.",
|
|
1985
|
-
"",
|
|
1986
|
-
...safetySection,
|
|
1987
|
-
"## Anima CLI Quick Reference",
|
|
1988
|
-
"Anima is controlled via subcommands. Do not invent commands.",
|
|
1989
|
-
"To manage the Gateway daemon service (start/stop/restart):",
|
|
1990
|
-
"- anima gateway status",
|
|
1991
|
-
"- anima gateway start",
|
|
1992
|
-
"- anima gateway stop",
|
|
1993
|
-
"- anima gateway restart",
|
|
1994
|
-
"If unsure, ask the user to run `anima help` (or `anima gateway --help`) and paste the output.",
|
|
1995
|
-
"",
|
|
1996
|
-
...skillsSection,
|
|
1997
|
-
...memorySection,
|
|
1998
|
-
hasGateway && !isMinimal ? "## Anima Self-Update" : "",
|
|
1999
|
-
hasGateway && !isMinimal ? [
|
|
2000
|
-
"Get Updates (self-update) is ONLY allowed when the user explicitly asks for it.",
|
|
2001
|
-
"Do not run config.apply or update.run unless the user explicitly requests an update or config change; if it's not explicit, ask first.",
|
|
2002
|
-
"Actions: config.get, config.schema, config.apply (validate + write full config, then restart), update.run (update deps or git, then restart).",
|
|
2003
|
-
"After restart, Anima pings the last active session automatically."
|
|
2004
|
-
].join("\n") : "",
|
|
2005
|
-
hasGateway && !isMinimal ? "" : "",
|
|
2006
|
-
"",
|
|
2007
|
-
params.modelAliasLines && params.modelAliasLines.length > 0 && !isMinimal ? "## Model Aliases" : "",
|
|
2008
|
-
params.modelAliasLines && params.modelAliasLines.length > 0 && !isMinimal ? "Prefer aliases when specifying model overrides; full provider/model is also accepted." : "",
|
|
2009
|
-
params.modelAliasLines && params.modelAliasLines.length > 0 && !isMinimal ? params.modelAliasLines.join("\n") : "",
|
|
2010
|
-
params.modelAliasLines && params.modelAliasLines.length > 0 && !isMinimal ? "" : "",
|
|
2011
|
-
userTimezone ? "If you need the current date, time, or day of week, run session_status (📊 session_status)." : "",
|
|
2012
|
-
"## Workspace",
|
|
2013
|
-
`Your working directory is: ${displayWorkspaceDir}`,
|
|
2014
|
-
workspaceGuidance,
|
|
2015
|
-
...workspaceNotes,
|
|
2016
|
-
"",
|
|
2017
|
-
...docsSection,
|
|
2018
|
-
params.sandboxInfo?.enabled ? "## Sandbox" : "",
|
|
2019
|
-
params.sandboxInfo?.enabled ? [
|
|
2020
|
-
"You are running in a sandboxed runtime (tools execute in Docker).",
|
|
2021
|
-
"Some tools may be unavailable due to sandbox policy.",
|
|
2022
|
-
"Sub-agents stay sandboxed (no elevated/host access). Need outside-sandbox read/write? Don't spawn; ask first.",
|
|
2023
|
-
params.sandboxInfo.containerWorkspaceDir ? `Sandbox container workdir: ${params.sandboxInfo.containerWorkspaceDir}` : "",
|
|
2024
|
-
params.sandboxInfo.workspaceDir ? `Sandbox host workspace: ${params.sandboxInfo.workspaceDir}` : "",
|
|
2025
|
-
params.sandboxInfo.workspaceAccess ? `Agent workspace access: ${params.sandboxInfo.workspaceAccess}${params.sandboxInfo.agentWorkspaceMount ? ` (mounted at ${params.sandboxInfo.agentWorkspaceMount})` : ""}` : "",
|
|
2026
|
-
params.sandboxInfo.browserBridgeUrl ? "Sandbox browser: enabled." : "",
|
|
2027
|
-
params.sandboxInfo.browserNoVncUrl ? `Sandbox browser observer (noVNC): ${params.sandboxInfo.browserNoVncUrl}` : "",
|
|
2028
|
-
params.sandboxInfo.hostBrowserAllowed === true ? "Host browser control: allowed." : params.sandboxInfo.hostBrowserAllowed === false ? "Host browser control: blocked." : "",
|
|
2029
|
-
params.sandboxInfo.elevated?.allowed ? "Elevated exec is available for this session." : "",
|
|
2030
|
-
params.sandboxInfo.elevated?.allowed ? "User can toggle with /elevated on|off|ask|full." : "",
|
|
2031
|
-
params.sandboxInfo.elevated?.allowed ? "You may also send /elevated on|off|ask|full when needed." : "",
|
|
2032
|
-
params.sandboxInfo.elevated?.allowed ? `Current elevated level: ${params.sandboxInfo.elevated.defaultLevel} (ask runs exec on host with approvals; full auto-approves).` : ""
|
|
2033
|
-
].filter(Boolean).join("\n") : "",
|
|
2034
|
-
params.sandboxInfo?.enabled ? "" : "",
|
|
2035
|
-
...buildUserIdentitySection(ownerLine, isMinimal),
|
|
2036
|
-
...buildTimeSection({ userTimezone }),
|
|
2037
|
-
"## Workspace Files (injected)",
|
|
2038
|
-
"These user-editable files are loaded by Anima and included below in Project Context.",
|
|
2039
|
-
"",
|
|
2040
|
-
...buildReplyTagsSection(isMinimal),
|
|
2041
|
-
...buildMessagingSection({
|
|
2042
|
-
isMinimal,
|
|
2043
|
-
availableTools,
|
|
2044
|
-
messageChannelOptions,
|
|
2045
|
-
inlineButtonsEnabled,
|
|
2046
|
-
runtimeChannel,
|
|
2047
|
-
messageToolHints: params.messageToolHints
|
|
2048
|
-
}),
|
|
2049
|
-
...buildVoiceSection({
|
|
2050
|
-
isMinimal,
|
|
2051
|
-
ttsHint: params.ttsHint
|
|
2052
|
-
})
|
|
2053
|
-
];
|
|
2054
|
-
if (extraSystemPrompt) {
|
|
2055
|
-
const contextHeader = promptMode === "minimal" ? "## Subagent Context" : "## Group Chat Context";
|
|
2056
|
-
lines.push(contextHeader, extraSystemPrompt, "");
|
|
2057
|
-
}
|
|
2058
|
-
if (params.reactionGuidance) {
|
|
2059
|
-
const { level, channel } = params.reactionGuidance;
|
|
2060
|
-
const guidanceText = level === "minimal" ? [
|
|
2061
|
-
`Reactions are enabled for ${channel} in MINIMAL mode.`,
|
|
2062
|
-
"React ONLY when truly relevant:",
|
|
2063
|
-
"- Acknowledge important user requests or confirmations",
|
|
2064
|
-
"- Express genuine sentiment (humor, appreciation) sparingly",
|
|
2065
|
-
"- Avoid reacting to routine messages or your own replies",
|
|
2066
|
-
"Guideline: at most 1 reaction per 5-10 exchanges."
|
|
2067
|
-
].join("\n") : [
|
|
2068
|
-
`Reactions are enabled for ${channel} in EXTENSIVE mode.`,
|
|
2069
|
-
"Feel free to react liberally:",
|
|
2070
|
-
"- Acknowledge messages with appropriate emojis",
|
|
2071
|
-
"- Express sentiment and personality through reactions",
|
|
2072
|
-
"- React to interesting content, humor, or notable events",
|
|
2073
|
-
"- Use reactions to confirm understanding or agreement",
|
|
2074
|
-
"Guideline: react whenever it feels natural."
|
|
2075
|
-
].join("\n");
|
|
2076
|
-
lines.push("## Reactions", guidanceText, "");
|
|
2077
|
-
}
|
|
2078
|
-
if (reasoningHint) lines.push("## Reasoning Format", reasoningHint, "");
|
|
2079
|
-
const validContextFiles = (params.contextFiles ?? []).filter((file) => typeof file.path === "string" && file.path.trim().length > 0);
|
|
2080
|
-
if (validContextFiles.length > 0) {
|
|
2081
|
-
const hasSoulFile = validContextFiles.some((file) => {
|
|
2082
|
-
const normalizedPath = file.path.trim().replace(/\\/g, "/");
|
|
2083
|
-
return (normalizedPath.split("/").pop() ?? normalizedPath).toLowerCase() === "soul.md";
|
|
2084
|
-
});
|
|
2085
|
-
lines.push("# Project Context", "", "The following project context files have been loaded:");
|
|
2086
|
-
if (hasSoulFile) lines.push("If SOUL.md is present, embody its persona and tone. Avoid stiff, generic replies; follow its guidance unless higher-priority instructions override it.");
|
|
2087
|
-
lines.push("");
|
|
2088
|
-
for (const file of validContextFiles) lines.push(`## ${file.path}`, "", file.content, "");
|
|
2089
|
-
}
|
|
2090
|
-
if (!isMinimal) lines.push("## Silent Replies", `When you have nothing to say, respond with ONLY: ${SILENT_REPLY_TOKEN}`, "", "⚠️ Rules:", "- It must be your ENTIRE message — nothing else", `- Never append it to an actual response (never include "${SILENT_REPLY_TOKEN}" in real replies)`, "- Never wrap it in markdown or code blocks", "", `❌ Wrong: "Here's help... ${SILENT_REPLY_TOKEN}"`, `❌ Wrong: "${SILENT_REPLY_TOKEN}"`, `✅ Right: ${SILENT_REPLY_TOKEN}`, "");
|
|
2091
|
-
if (!isMinimal) lines.push("## Heartbeats", heartbeatPromptLine, "If you receive a heartbeat poll (a user message matching the heartbeat prompt above), and there is nothing that needs attention, reply exactly:", "HEARTBEAT_OK", "Anima treats a leading/trailing \"HEARTBEAT_OK\" as a heartbeat ack (and may discard it).", "If something needs attention, do NOT include \"HEARTBEAT_OK\"; reply with the alert text instead.", "");
|
|
2092
|
-
lines.push("## Runtime", buildRuntimeLine(runtimeInfo, runtimeChannel, runtimeCapabilities, params.defaultThinkLevel), `Reasoning: ${reasoningLevel} (hidden unless on/stream). Toggle /reasoning; /status shows Reasoning when enabled.`);
|
|
2093
|
-
return lines.filter(Boolean).join("\n");
|
|
2094
|
-
}
|
|
2095
|
-
function buildRuntimeLine(runtimeInfo, runtimeChannel, runtimeCapabilities = [], defaultThinkLevel) {
|
|
2096
|
-
return `Runtime: ${[
|
|
2097
|
-
runtimeInfo?.agentId ? `agent=${runtimeInfo.agentId}` : "",
|
|
2098
|
-
runtimeInfo?.host ? `host=${runtimeInfo.host}` : "",
|
|
2099
|
-
runtimeInfo?.repoRoot ? `repo=${runtimeInfo.repoRoot}` : "",
|
|
2100
|
-
runtimeInfo?.os ? `os=${runtimeInfo.os}${runtimeInfo?.arch ? ` (${runtimeInfo.arch})` : ""}` : runtimeInfo?.arch ? `arch=${runtimeInfo.arch}` : "",
|
|
2101
|
-
runtimeInfo?.node ? `node=${runtimeInfo.node}` : "",
|
|
2102
|
-
runtimeInfo?.model ? `model=${runtimeInfo.model}` : "",
|
|
2103
|
-
runtimeInfo?.defaultModel ? `default_model=${runtimeInfo.defaultModel}` : "",
|
|
2104
|
-
runtimeInfo?.shell ? `shell=${runtimeInfo.shell}` : "",
|
|
2105
|
-
runtimeChannel ? `channel=${runtimeChannel}` : "",
|
|
2106
|
-
runtimeChannel ? `capabilities=${runtimeCapabilities.length > 0 ? runtimeCapabilities.join(",") : "none"}` : "",
|
|
2107
|
-
`thinking=${defaultThinkLevel ?? "off"}`
|
|
2108
|
-
].filter(Boolean).join(" | ")}`;
|
|
2109
|
-
}
|
|
2110
|
-
|
|
2111
|
-
//#endregion
|
|
2112
|
-
//#region src/agents/cli-runner/helpers.ts
|
|
2113
|
-
const CLI_RUN_QUEUE = /* @__PURE__ */ new Map();
|
|
2114
|
-
function buildLooseArgOrderRegex(tokens) {
|
|
2115
|
-
const [head, ...rest] = tokens.map((t) => String(t ?? "").trim()).filter(Boolean);
|
|
2116
|
-
if (!head) return /$^/;
|
|
2117
|
-
const headEscaped = escapeRegExp(head);
|
|
2118
|
-
const headFragment = `(?:^|\\s)(?:${headEscaped}|\\S+\\/${headEscaped})(?=\\s|$)`;
|
|
2119
|
-
const restFragments = rest.map((t) => `(?:^|\\s)${escapeRegExp(t)}(?=\\s|$)`);
|
|
2120
|
-
return new RegExp([headFragment, ...restFragments].join(".*"));
|
|
2121
|
-
}
|
|
2122
|
-
async function psWithFallback(argsA, argsB) {
|
|
2123
|
-
try {
|
|
2124
|
-
const { stdout } = await runExec("ps", argsA);
|
|
2125
|
-
return stdout;
|
|
2126
|
-
} catch {}
|
|
2127
|
-
const { stdout } = await runExec("ps", argsB);
|
|
2128
|
-
return stdout;
|
|
2129
|
-
}
|
|
2130
|
-
async function cleanupResumeProcesses(backend, sessionId) {
|
|
2131
|
-
if (process.platform === "win32") return;
|
|
2132
|
-
const resumeArgs = backend.resumeArgs ?? [];
|
|
2133
|
-
if (resumeArgs.length === 0) return;
|
|
2134
|
-
if (!resumeArgs.some((arg) => arg.includes("{sessionId}"))) return;
|
|
2135
|
-
const commandToken = path.basename(backend.command ?? "").trim();
|
|
2136
|
-
if (!commandToken) return;
|
|
2137
|
-
const resumeTokens = resumeArgs.map((arg) => arg.replaceAll("{sessionId}", sessionId));
|
|
2138
|
-
if (![commandToken, ...resumeTokens].filter(Boolean).map((token) => escapeRegExp(token)).join(".*")) return;
|
|
2139
|
-
try {
|
|
2140
|
-
const stdout = await psWithFallback([
|
|
2141
|
-
"-axww",
|
|
2142
|
-
"-o",
|
|
2143
|
-
"pid=,ppid=,command="
|
|
2144
|
-
], [
|
|
2145
|
-
"-ax",
|
|
2146
|
-
"-o",
|
|
2147
|
-
"pid=,ppid=,command="
|
|
2148
|
-
]);
|
|
2149
|
-
const patternRegex = buildLooseArgOrderRegex([commandToken, ...resumeTokens]);
|
|
2150
|
-
const toKill = [];
|
|
2151
|
-
for (const line of stdout.split("\n")) {
|
|
2152
|
-
const trimmed = line.trim();
|
|
2153
|
-
if (!trimmed) continue;
|
|
2154
|
-
const match = /^(\d+)\s+(\d+)\s+(.*)$/.exec(trimmed);
|
|
2155
|
-
if (!match) continue;
|
|
2156
|
-
const pid = Number(match[1]);
|
|
2157
|
-
const ppid = Number(match[2]);
|
|
2158
|
-
const cmd = match[3] ?? "";
|
|
2159
|
-
if (!Number.isFinite(pid)) continue;
|
|
2160
|
-
if (ppid !== process.pid) continue;
|
|
2161
|
-
if (!patternRegex.test(cmd)) continue;
|
|
2162
|
-
toKill.push(pid);
|
|
2163
|
-
}
|
|
2164
|
-
if (toKill.length > 0) {
|
|
2165
|
-
const pidArgs = toKill.map((pid) => String(pid));
|
|
2166
|
-
try {
|
|
2167
|
-
await runExec("kill", ["-TERM", ...pidArgs]);
|
|
2168
|
-
} catch {}
|
|
2169
|
-
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
2170
|
-
try {
|
|
2171
|
-
await runExec("kill", ["-9", ...pidArgs]);
|
|
2172
|
-
} catch {}
|
|
2173
|
-
}
|
|
2174
|
-
} catch {}
|
|
2175
|
-
}
|
|
2176
|
-
function buildSessionMatchers(backend) {
|
|
2177
|
-
const commandToken = path.basename(backend.command ?? "").trim();
|
|
2178
|
-
if (!commandToken) return [];
|
|
2179
|
-
const matchers = [];
|
|
2180
|
-
const sessionArg = backend.sessionArg?.trim();
|
|
2181
|
-
const sessionArgs = backend.sessionArgs ?? [];
|
|
2182
|
-
const resumeArgs = backend.resumeArgs ?? [];
|
|
2183
|
-
const addMatcher = (args) => {
|
|
2184
|
-
if (args.length === 0) return;
|
|
2185
|
-
const pattern = [commandToken, ...args].map((token, index) => {
|
|
2186
|
-
const tokenPattern = tokenToRegex(token);
|
|
2187
|
-
return index === 0 ? `(?:^|\\s)${tokenPattern}` : `\\s+${tokenPattern}`;
|
|
2188
|
-
}).join("");
|
|
2189
|
-
matchers.push(new RegExp(pattern));
|
|
2190
|
-
};
|
|
2191
|
-
if (sessionArgs.some((arg) => arg.includes("{sessionId}"))) addMatcher(sessionArgs);
|
|
2192
|
-
else if (sessionArg) addMatcher([sessionArg, "{sessionId}"]);
|
|
2193
|
-
if (resumeArgs.some((arg) => arg.includes("{sessionId}"))) addMatcher(resumeArgs);
|
|
2194
|
-
return matchers;
|
|
2195
|
-
}
|
|
2196
|
-
function tokenToRegex(token) {
|
|
2197
|
-
if (!token.includes("{sessionId}")) return escapeRegExp(token);
|
|
2198
|
-
return token.split("{sessionId}").map((part) => escapeRegExp(part)).join("\\S+");
|
|
2199
|
-
}
|
|
2200
|
-
/**
|
|
2201
|
-
* Cleanup suspended Anima CLI processes that have accumulated.
|
|
2202
|
-
* Only cleans up if there are more than the threshold (default: 10).
|
|
2203
|
-
*/
|
|
2204
|
-
async function cleanupSuspendedCliProcesses(backend, threshold = 10) {
|
|
2205
|
-
if (process.platform === "win32") return;
|
|
2206
|
-
const matchers = buildSessionMatchers(backend);
|
|
2207
|
-
if (matchers.length === 0) return;
|
|
2208
|
-
try {
|
|
2209
|
-
const stdout = await psWithFallback([
|
|
2210
|
-
"-axww",
|
|
2211
|
-
"-o",
|
|
2212
|
-
"pid=,ppid=,stat=,command="
|
|
2213
|
-
], [
|
|
2214
|
-
"-ax",
|
|
2215
|
-
"-o",
|
|
2216
|
-
"pid=,ppid=,stat=,command="
|
|
2217
|
-
]);
|
|
2218
|
-
const suspended = [];
|
|
2219
|
-
for (const line of stdout.split("\n")) {
|
|
2220
|
-
const trimmed = line.trim();
|
|
2221
|
-
if (!trimmed) continue;
|
|
2222
|
-
const match = /^(\d+)\s+(\d+)\s+(\S+)\s+(.*)$/.exec(trimmed);
|
|
2223
|
-
if (!match) continue;
|
|
2224
|
-
const pid = Number(match[1]);
|
|
2225
|
-
const ppid = Number(match[2]);
|
|
2226
|
-
const stat = match[3] ?? "";
|
|
2227
|
-
const command = match[4] ?? "";
|
|
2228
|
-
if (!Number.isFinite(pid)) continue;
|
|
2229
|
-
if (ppid !== process.pid) continue;
|
|
2230
|
-
if (!stat.includes("T")) continue;
|
|
2231
|
-
if (!matchers.some((matcher) => matcher.test(command))) continue;
|
|
2232
|
-
suspended.push(pid);
|
|
2233
|
-
}
|
|
2234
|
-
if (suspended.length > threshold) await runExec("kill", ["-9", ...suspended.map((pid) => String(pid))]);
|
|
2235
|
-
} catch {}
|
|
2236
|
-
}
|
|
2237
|
-
function enqueueCliRun(key, task) {
|
|
2238
|
-
const chained = (CLI_RUN_QUEUE.get(key) ?? Promise.resolve()).catch(() => void 0).then(task);
|
|
2239
|
-
const tracked = chained.finally(() => {
|
|
2240
|
-
if (CLI_RUN_QUEUE.get(key) === tracked) CLI_RUN_QUEUE.delete(key);
|
|
2241
|
-
});
|
|
2242
|
-
CLI_RUN_QUEUE.set(key, tracked);
|
|
2243
|
-
return chained;
|
|
2244
|
-
}
|
|
2245
|
-
function buildSystemPrompt(params) {
|
|
2246
|
-
const defaultModelRef = resolveDefaultModelForAgent({
|
|
2247
|
-
cfg: params.config ?? {},
|
|
2248
|
-
agentId: params.agentId
|
|
2249
|
-
});
|
|
2250
|
-
const defaultModelLabel = `${defaultModelRef.provider}/${defaultModelRef.model}`;
|
|
2251
|
-
const { runtimeInfo, userTimezone, userTime, userTimeFormat } = buildSystemPromptParams({
|
|
2252
|
-
config: params.config,
|
|
2253
|
-
agentId: params.agentId,
|
|
2254
|
-
workspaceDir: params.workspaceDir,
|
|
2255
|
-
cwd: process.cwd(),
|
|
2256
|
-
runtime: {
|
|
2257
|
-
host: "anima",
|
|
2258
|
-
os: `${os.type()} ${os.release()}`,
|
|
2259
|
-
arch: os.arch(),
|
|
2260
|
-
node: process.version,
|
|
2261
|
-
model: params.modelDisplay,
|
|
2262
|
-
defaultModel: defaultModelLabel,
|
|
2263
|
-
shell: detectRuntimeShell()
|
|
2264
|
-
}
|
|
2265
|
-
});
|
|
2266
|
-
const ttsHint = params.config ? buildTtsSystemPromptHint(params.config) : void 0;
|
|
2267
|
-
return buildAgentSystemPrompt({
|
|
2268
|
-
workspaceDir: params.workspaceDir,
|
|
2269
|
-
defaultThinkLevel: params.defaultThinkLevel,
|
|
2270
|
-
extraSystemPrompt: params.extraSystemPrompt,
|
|
2271
|
-
ownerNumbers: params.ownerNumbers,
|
|
2272
|
-
reasoningTagHint: false,
|
|
2273
|
-
heartbeatPrompt: params.heartbeatPrompt,
|
|
2274
|
-
docsPath: params.docsPath,
|
|
2275
|
-
runtimeInfo,
|
|
2276
|
-
toolNames: params.tools.map((tool) => tool.name),
|
|
2277
|
-
modelAliasLines: buildModelAliasLines(params.config),
|
|
2278
|
-
userTimezone,
|
|
2279
|
-
userTime,
|
|
2280
|
-
userTimeFormat,
|
|
2281
|
-
contextFiles: params.contextFiles,
|
|
2282
|
-
ttsHint,
|
|
2283
|
-
memoryCitationsMode: params.config?.memory?.citations
|
|
2284
|
-
});
|
|
2285
|
-
}
|
|
2286
|
-
function normalizeCliModel(modelId, backend) {
|
|
2287
|
-
const trimmed = modelId.trim();
|
|
2288
|
-
if (!trimmed) return trimmed;
|
|
2289
|
-
const direct = backend.modelAliases?.[trimmed];
|
|
2290
|
-
if (direct) return direct;
|
|
2291
|
-
const lower = trimmed.toLowerCase();
|
|
2292
|
-
const mapped = backend.modelAliases?.[lower];
|
|
2293
|
-
if (mapped) return mapped;
|
|
2294
|
-
return trimmed;
|
|
2295
|
-
}
|
|
2296
|
-
function toUsage(raw) {
|
|
2297
|
-
const pick = (key) => typeof raw[key] === "number" && raw[key] > 0 ? raw[key] : void 0;
|
|
2298
|
-
const input = pick("input_tokens") ?? pick("inputTokens");
|
|
2299
|
-
const output = pick("output_tokens") ?? pick("outputTokens");
|
|
2300
|
-
const cacheRead = pick("cache_read_input_tokens") ?? pick("cached_input_tokens") ?? pick("cacheRead");
|
|
2301
|
-
const cacheWrite = pick("cache_write_input_tokens") ?? pick("cacheWrite");
|
|
2302
|
-
const total = pick("total_tokens") ?? pick("total");
|
|
2303
|
-
if (!input && !output && !cacheRead && !cacheWrite && !total) return;
|
|
2304
|
-
return {
|
|
2305
|
-
input,
|
|
2306
|
-
output,
|
|
2307
|
-
cacheRead,
|
|
2308
|
-
cacheWrite,
|
|
2309
|
-
total
|
|
2310
|
-
};
|
|
2311
|
-
}
|
|
2312
|
-
function collectText(value) {
|
|
2313
|
-
if (!value) return "";
|
|
2314
|
-
if (typeof value === "string") return value;
|
|
2315
|
-
if (Array.isArray(value)) return value.map((entry) => collectText(entry)).join("");
|
|
2316
|
-
if (!isRecord(value)) return "";
|
|
2317
|
-
if (typeof value.text === "string") return value.text;
|
|
2318
|
-
if (typeof value.content === "string") return value.content;
|
|
2319
|
-
if (Array.isArray(value.content)) return value.content.map((entry) => collectText(entry)).join("");
|
|
2320
|
-
if (isRecord(value.message)) return collectText(value.message);
|
|
2321
|
-
return "";
|
|
2322
|
-
}
|
|
2323
|
-
function pickSessionId(parsed, backend) {
|
|
2324
|
-
const fields = backend.sessionIdFields ?? [
|
|
2325
|
-
"session_id",
|
|
2326
|
-
"sessionId",
|
|
2327
|
-
"conversation_id",
|
|
2328
|
-
"conversationId"
|
|
2329
|
-
];
|
|
2330
|
-
for (const field of fields) {
|
|
2331
|
-
const value = parsed[field];
|
|
2332
|
-
if (typeof value === "string" && value.trim()) return value.trim();
|
|
2333
|
-
}
|
|
2334
|
-
}
|
|
2335
|
-
function parseCliJson(raw, backend) {
|
|
2336
|
-
const trimmed = raw.trim();
|
|
2337
|
-
if (!trimmed) return null;
|
|
2338
|
-
let parsed;
|
|
2339
|
-
try {
|
|
2340
|
-
parsed = JSON.parse(trimmed);
|
|
2341
|
-
} catch {
|
|
2342
|
-
return null;
|
|
2343
|
-
}
|
|
2344
|
-
if (!isRecord(parsed)) return null;
|
|
2345
|
-
const sessionId = pickSessionId(parsed, backend);
|
|
2346
|
-
const usage = isRecord(parsed.usage) ? toUsage(parsed.usage) : void 0;
|
|
2347
|
-
return {
|
|
2348
|
-
text: (collectText(parsed.message) || collectText(parsed.content) || collectText(parsed.result) || collectText(parsed)).trim(),
|
|
2349
|
-
sessionId,
|
|
2350
|
-
usage
|
|
2351
|
-
};
|
|
2352
|
-
}
|
|
2353
|
-
function parseCliJsonl(raw, backend) {
|
|
2354
|
-
const lines = raw.split(/\r?\n/g).map((line) => line.trim()).filter(Boolean);
|
|
2355
|
-
if (lines.length === 0) return null;
|
|
2356
|
-
let sessionId;
|
|
2357
|
-
let usage;
|
|
2358
|
-
const texts = [];
|
|
2359
|
-
for (const line of lines) {
|
|
2360
|
-
let parsed;
|
|
2361
|
-
try {
|
|
2362
|
-
parsed = JSON.parse(line);
|
|
2363
|
-
} catch {
|
|
2364
|
-
continue;
|
|
2365
|
-
}
|
|
2366
|
-
if (!isRecord(parsed)) continue;
|
|
2367
|
-
if (!sessionId) sessionId = pickSessionId(parsed, backend);
|
|
2368
|
-
if (!sessionId && typeof parsed.thread_id === "string") sessionId = parsed.thread_id.trim();
|
|
2369
|
-
if (isRecord(parsed.usage)) usage = toUsage(parsed.usage) ?? usage;
|
|
2370
|
-
const item = isRecord(parsed.item) ? parsed.item : null;
|
|
2371
|
-
if (item && typeof item.text === "string") {
|
|
2372
|
-
const type = typeof item.type === "string" ? item.type.toLowerCase() : "";
|
|
2373
|
-
if (!type || type.includes("message")) texts.push(item.text);
|
|
2374
|
-
}
|
|
2375
|
-
}
|
|
2376
|
-
const text = texts.join("\n").trim();
|
|
2377
|
-
if (!text) return null;
|
|
2378
|
-
return {
|
|
2379
|
-
text,
|
|
2380
|
-
sessionId,
|
|
2381
|
-
usage
|
|
2382
|
-
};
|
|
2383
|
-
}
|
|
2384
|
-
function resolveSystemPromptUsage(params) {
|
|
2385
|
-
const systemPrompt = params.systemPrompt?.trim();
|
|
2386
|
-
if (!systemPrompt) return null;
|
|
2387
|
-
const when = params.backend.systemPromptWhen ?? "first";
|
|
2388
|
-
if (when === "never") return null;
|
|
2389
|
-
if (when === "first" && !params.isNewSession) return null;
|
|
2390
|
-
if (!params.backend.systemPromptArg?.trim()) return null;
|
|
2391
|
-
return systemPrompt;
|
|
2392
|
-
}
|
|
2393
|
-
function resolveSessionIdToSend(params) {
|
|
2394
|
-
const mode = params.backend.sessionMode ?? "always";
|
|
2395
|
-
const existing = params.cliSessionId?.trim();
|
|
2396
|
-
if (mode === "none") return {
|
|
2397
|
-
sessionId: void 0,
|
|
2398
|
-
isNew: !existing
|
|
2399
|
-
};
|
|
2400
|
-
if (mode === "existing") return {
|
|
2401
|
-
sessionId: existing,
|
|
2402
|
-
isNew: !existing
|
|
2403
|
-
};
|
|
2404
|
-
if (existing) return {
|
|
2405
|
-
sessionId: existing,
|
|
2406
|
-
isNew: false
|
|
2407
|
-
};
|
|
2408
|
-
return {
|
|
2409
|
-
sessionId: crypto.randomUUID(),
|
|
2410
|
-
isNew: true
|
|
2411
|
-
};
|
|
2412
|
-
}
|
|
2413
|
-
function resolvePromptInput(params) {
|
|
2414
|
-
if ((params.backend.input ?? "arg") === "stdin") return { stdin: params.prompt };
|
|
2415
|
-
if (params.backend.maxPromptArgChars && params.prompt.length > params.backend.maxPromptArgChars) return { stdin: params.prompt };
|
|
2416
|
-
return { argsPrompt: params.prompt };
|
|
2417
|
-
}
|
|
2418
|
-
function resolveImageExtension(mimeType) {
|
|
2419
|
-
const normalized = mimeType.toLowerCase();
|
|
2420
|
-
if (normalized.includes("png")) return "png";
|
|
2421
|
-
if (normalized.includes("jpeg") || normalized.includes("jpg")) return "jpg";
|
|
2422
|
-
if (normalized.includes("gif")) return "gif";
|
|
2423
|
-
if (normalized.includes("webp")) return "webp";
|
|
2424
|
-
return "bin";
|
|
2425
|
-
}
|
|
2426
|
-
function appendImagePathsToPrompt(prompt, paths) {
|
|
2427
|
-
if (!paths.length) return prompt;
|
|
2428
|
-
const trimmed = prompt.trimEnd();
|
|
2429
|
-
return `${trimmed}${trimmed ? "\n\n" : ""}${paths.join("\n")}`;
|
|
2430
|
-
}
|
|
2431
|
-
async function writeCliImages(images) {
|
|
2432
|
-
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "anima-cli-images-"));
|
|
2433
|
-
const paths = [];
|
|
2434
|
-
for (let i = 0; i < images.length; i += 1) {
|
|
2435
|
-
const image = images[i];
|
|
2436
|
-
const ext = resolveImageExtension(image.mimeType);
|
|
2437
|
-
const filePath = path.join(tempDir, `image-${i + 1}.${ext}`);
|
|
2438
|
-
const buffer = Buffer.from(image.data, "base64");
|
|
2439
|
-
await fs.writeFile(filePath, buffer, { mode: 384 });
|
|
2440
|
-
paths.push(filePath);
|
|
2441
|
-
}
|
|
2442
|
-
const cleanup = async () => {
|
|
2443
|
-
await fs.rm(tempDir, {
|
|
2444
|
-
recursive: true,
|
|
2445
|
-
force: true
|
|
2446
|
-
});
|
|
2447
|
-
};
|
|
2448
|
-
return {
|
|
2449
|
-
paths,
|
|
2450
|
-
cleanup
|
|
2451
|
-
};
|
|
2452
|
-
}
|
|
2453
|
-
function buildCliArgs(params) {
|
|
2454
|
-
const args = [...params.baseArgs];
|
|
2455
|
-
if (!params.useResume && params.backend.modelArg && params.modelId) args.push(params.backend.modelArg, params.modelId);
|
|
2456
|
-
if (!params.useResume && params.systemPrompt && params.backend.systemPromptArg) args.push(params.backend.systemPromptArg, params.systemPrompt);
|
|
2457
|
-
if (!params.useResume && params.sessionId) {
|
|
2458
|
-
if (params.backend.sessionArgs && params.backend.sessionArgs.length > 0) for (const entry of params.backend.sessionArgs) args.push(entry.replaceAll("{sessionId}", params.sessionId));
|
|
2459
|
-
else if (params.backend.sessionArg) args.push(params.backend.sessionArg, params.sessionId);
|
|
2460
|
-
}
|
|
2461
|
-
if (params.imagePaths && params.imagePaths.length > 0) {
|
|
2462
|
-
const mode = params.backend.imageMode ?? "repeat";
|
|
2463
|
-
const imageArg = params.backend.imageArg;
|
|
2464
|
-
if (imageArg) if (mode === "list") args.push(imageArg, params.imagePaths.join(","));
|
|
2465
|
-
else for (const imagePath of params.imagePaths) args.push(imageArg, imagePath);
|
|
2466
|
-
}
|
|
2467
|
-
if (params.promptArg !== void 0) args.push(params.promptArg);
|
|
2468
|
-
return args;
|
|
2469
|
-
}
|
|
2470
|
-
|
|
2471
|
-
//#endregion
|
|
2472
|
-
//#region src/agents/docs-path.ts
|
|
2473
|
-
async function resolveAnimaDocsPath(params) {
|
|
2474
|
-
const workspaceDir = params.workspaceDir?.trim();
|
|
2475
|
-
if (workspaceDir) {
|
|
2476
|
-
const workspaceDocs = path.join(workspaceDir, "docs");
|
|
2477
|
-
if (fs$1.existsSync(workspaceDocs)) return workspaceDocs;
|
|
2478
|
-
}
|
|
2479
|
-
const packageRoot = await resolveAnimaPackageRoot({
|
|
2480
|
-
cwd: params.cwd,
|
|
2481
|
-
argv1: params.argv1,
|
|
2482
|
-
moduleUrl: params.moduleUrl
|
|
2483
|
-
});
|
|
2484
|
-
if (!packageRoot) return null;
|
|
2485
|
-
const packageDocs = path.join(packageRoot, "docs");
|
|
2486
|
-
return fs$1.existsSync(packageDocs) ? packageDocs : null;
|
|
2487
|
-
}
|
|
2488
|
-
|
|
2489
|
-
//#endregion
|
|
2490
|
-
//#region src/agents/failover-error.ts
|
|
2491
|
-
const TIMEOUT_HINT_RE = /timeout|timed out|deadline exceeded|context deadline exceeded/i;
|
|
2492
|
-
const ABORT_TIMEOUT_RE = /request was aborted|request aborted/i;
|
|
2493
|
-
var FailoverError = class extends Error {
|
|
2494
|
-
constructor(message, params) {
|
|
2495
|
-
super(message, { cause: params.cause });
|
|
2496
|
-
this.name = "FailoverError";
|
|
2497
|
-
this.reason = params.reason;
|
|
2498
|
-
this.provider = params.provider;
|
|
2499
|
-
this.model = params.model;
|
|
2500
|
-
this.profileId = params.profileId;
|
|
2501
|
-
this.status = params.status;
|
|
2502
|
-
this.code = params.code;
|
|
2503
|
-
}
|
|
2504
|
-
};
|
|
2505
|
-
function isFailoverError(err) {
|
|
2506
|
-
return err instanceof FailoverError;
|
|
2507
|
-
}
|
|
2508
|
-
function resolveFailoverStatus(reason) {
|
|
2509
|
-
switch (reason) {
|
|
2510
|
-
case "billing": return 402;
|
|
2511
|
-
case "rate_limit": return 429;
|
|
2512
|
-
case "auth": return 401;
|
|
2513
|
-
case "timeout": return 408;
|
|
2514
|
-
case "format": return 400;
|
|
2515
|
-
default: return;
|
|
2516
|
-
}
|
|
2517
|
-
}
|
|
2518
|
-
function getStatusCode(err) {
|
|
2519
|
-
if (!err || typeof err !== "object") return;
|
|
2520
|
-
const candidate = err.status ?? err.statusCode;
|
|
2521
|
-
if (typeof candidate === "number") return candidate;
|
|
2522
|
-
if (typeof candidate === "string" && /^\d+$/.test(candidate)) return Number(candidate);
|
|
2523
|
-
}
|
|
2524
|
-
function getErrorName(err) {
|
|
2525
|
-
if (!err || typeof err !== "object") return "";
|
|
2526
|
-
return "name" in err ? String(err.name) : "";
|
|
2527
|
-
}
|
|
2528
|
-
function getErrorCode(err) {
|
|
2529
|
-
if (!err || typeof err !== "object") return;
|
|
2530
|
-
const candidate = err.code;
|
|
2531
|
-
if (typeof candidate !== "string") return;
|
|
2532
|
-
const trimmed = candidate.trim();
|
|
2533
|
-
return trimmed ? trimmed : void 0;
|
|
2534
|
-
}
|
|
2535
|
-
function getErrorMessage(err) {
|
|
2536
|
-
if (err instanceof Error) return err.message;
|
|
2537
|
-
if (typeof err === "string") return err;
|
|
2538
|
-
if (typeof err === "number" || typeof err === "boolean" || typeof err === "bigint") return String(err);
|
|
2539
|
-
if (typeof err === "symbol") return err.description ?? "";
|
|
2540
|
-
if (err && typeof err === "object") {
|
|
2541
|
-
const message = err.message;
|
|
2542
|
-
if (typeof message === "string") return message;
|
|
2543
|
-
}
|
|
2544
|
-
return "";
|
|
2545
|
-
}
|
|
2546
|
-
function hasTimeoutHint(err) {
|
|
2547
|
-
if (!err) return false;
|
|
2548
|
-
if (getErrorName(err) === "TimeoutError") return true;
|
|
2549
|
-
const message = getErrorMessage(err);
|
|
2550
|
-
return Boolean(message && TIMEOUT_HINT_RE.test(message));
|
|
2551
|
-
}
|
|
2552
|
-
function isTimeoutError(err) {
|
|
2553
|
-
if (hasTimeoutHint(err)) return true;
|
|
2554
|
-
if (!err || typeof err !== "object") return false;
|
|
2555
|
-
if (getErrorName(err) !== "AbortError") return false;
|
|
2556
|
-
const message = getErrorMessage(err);
|
|
2557
|
-
if (message && ABORT_TIMEOUT_RE.test(message)) return true;
|
|
2558
|
-
const cause = "cause" in err ? err.cause : void 0;
|
|
2559
|
-
const reason = "reason" in err ? err.reason : void 0;
|
|
2560
|
-
return hasTimeoutHint(cause) || hasTimeoutHint(reason);
|
|
2561
|
-
}
|
|
2562
|
-
function resolveFailoverReasonFromError(err) {
|
|
2563
|
-
if (isFailoverError(err)) return err.reason;
|
|
2564
|
-
const status = getStatusCode(err);
|
|
2565
|
-
if (status === 402) return "billing";
|
|
2566
|
-
if (status === 429) return "rate_limit";
|
|
2567
|
-
if (status === 401 || status === 403) return "auth";
|
|
2568
|
-
if (status === 408) return "timeout";
|
|
2569
|
-
if (status === 400) return "format";
|
|
2570
|
-
const code = (getErrorCode(err) ?? "").toUpperCase();
|
|
2571
|
-
if ([
|
|
2572
|
-
"ETIMEDOUT",
|
|
2573
|
-
"ESOCKETTIMEDOUT",
|
|
2574
|
-
"ECONNRESET",
|
|
2575
|
-
"ECONNABORTED"
|
|
2576
|
-
].includes(code)) return "timeout";
|
|
2577
|
-
if (isTimeoutError(err)) return "timeout";
|
|
2578
|
-
const message = getErrorMessage(err);
|
|
2579
|
-
if (!message) return null;
|
|
2580
|
-
return classifyFailoverReason$1(message);
|
|
2581
|
-
}
|
|
2582
|
-
function describeFailoverError(err) {
|
|
2583
|
-
if (isFailoverError(err)) return {
|
|
2584
|
-
message: err.message,
|
|
2585
|
-
reason: err.reason,
|
|
2586
|
-
status: err.status,
|
|
2587
|
-
code: err.code
|
|
2588
|
-
};
|
|
2589
|
-
return {
|
|
2590
|
-
message: getErrorMessage(err) || String(err),
|
|
2591
|
-
reason: resolveFailoverReasonFromError(err) ?? void 0,
|
|
2592
|
-
status: getStatusCode(err),
|
|
2593
|
-
code: getErrorCode(err)
|
|
2594
|
-
};
|
|
2595
|
-
}
|
|
2596
|
-
function coerceToFailoverError(err, context) {
|
|
2597
|
-
if (isFailoverError(err)) return err;
|
|
2598
|
-
const reason = resolveFailoverReasonFromError(err);
|
|
2599
|
-
if (!reason) return null;
|
|
2600
|
-
const message = getErrorMessage(err) || String(err);
|
|
2601
|
-
const status = getStatusCode(err) ?? resolveFailoverStatus(reason);
|
|
2602
|
-
const code = getErrorCode(err);
|
|
2603
|
-
return new FailoverError(message, {
|
|
2604
|
-
reason,
|
|
2605
|
-
provider: context?.provider,
|
|
2606
|
-
model: context?.model,
|
|
2607
|
-
profileId: context?.profileId,
|
|
2608
|
-
status,
|
|
2609
|
-
code,
|
|
2610
|
-
cause: err instanceof Error ? err : void 0
|
|
2611
|
-
});
|
|
2612
|
-
}
|
|
2613
|
-
|
|
2614
|
-
//#endregion
|
|
2615
|
-
//#region src/logging/redact-identifier.ts
|
|
2616
|
-
function sha256HexPrefix(value, len = 12) {
|
|
2617
|
-
const safeLen = Number.isFinite(len) ? Math.max(1, Math.floor(len)) : 12;
|
|
2618
|
-
return crypto.createHash("sha256").update(value).digest("hex").slice(0, safeLen);
|
|
2619
|
-
}
|
|
2620
|
-
function redactIdentifier(value, opts) {
|
|
2621
|
-
const trimmed = value?.trim();
|
|
2622
|
-
if (!trimmed) return "-";
|
|
2623
|
-
return `sha256:${sha256HexPrefix(trimmed, opts?.len ?? 12)}`;
|
|
2624
|
-
}
|
|
2625
|
-
|
|
2626
|
-
//#endregion
|
|
2627
|
-
//#region src/agents/workspace-run.ts
|
|
2628
|
-
function resolveRunAgentId(params) {
|
|
2629
|
-
const rawSessionKey = params.sessionKey?.trim() ?? "";
|
|
2630
|
-
const shape = classifySessionKeyShape(rawSessionKey);
|
|
2631
|
-
if (shape === "malformed_agent") throw new Error("Malformed agent session key; refusing workspace resolution.");
|
|
2632
|
-
const explicit = typeof params.agentId === "string" && params.agentId.trim() ? normalizeAgentId(params.agentId) : void 0;
|
|
2633
|
-
if (explicit) return {
|
|
2634
|
-
agentId: explicit,
|
|
2635
|
-
agentIdSource: "explicit"
|
|
2636
|
-
};
|
|
2637
|
-
const defaultAgentId = resolveDefaultAgentId(params.config ?? {});
|
|
2638
|
-
if (shape === "missing" || shape === "legacy_or_alias") return {
|
|
2639
|
-
agentId: defaultAgentId || DEFAULT_AGENT_ID,
|
|
2640
|
-
agentIdSource: "default"
|
|
2641
|
-
};
|
|
2642
|
-
const parsed = parseAgentSessionKey(rawSessionKey);
|
|
2643
|
-
if (parsed?.agentId) return {
|
|
2644
|
-
agentId: normalizeAgentId(parsed.agentId),
|
|
2645
|
-
agentIdSource: "session_key"
|
|
2646
|
-
};
|
|
2647
|
-
return {
|
|
2648
|
-
agentId: defaultAgentId || DEFAULT_AGENT_ID,
|
|
2649
|
-
agentIdSource: "default"
|
|
2650
|
-
};
|
|
2651
|
-
}
|
|
2652
|
-
function redactRunIdentifier(value) {
|
|
2653
|
-
return redactIdentifier(value, { len: 12 });
|
|
2654
|
-
}
|
|
2655
|
-
function resolveRunWorkspaceDir(params) {
|
|
2656
|
-
const requested = params.workspaceDir;
|
|
2657
|
-
const { agentId, agentIdSource } = resolveRunAgentId({
|
|
2658
|
-
sessionKey: params.sessionKey,
|
|
2659
|
-
agentId: params.agentId,
|
|
2660
|
-
config: params.config
|
|
2661
|
-
});
|
|
2662
|
-
if (typeof requested === "string") {
|
|
2663
|
-
const trimmed = requested.trim();
|
|
2664
|
-
if (trimmed) return {
|
|
2665
|
-
workspaceDir: resolveUserPath(trimmed),
|
|
2666
|
-
usedFallback: false,
|
|
2667
|
-
agentId,
|
|
2668
|
-
agentIdSource
|
|
2669
|
-
};
|
|
2670
|
-
}
|
|
2671
|
-
const fallbackReason = requested == null ? "missing" : typeof requested === "string" ? "blank" : "invalid_type";
|
|
2672
|
-
return {
|
|
2673
|
-
workspaceDir: resolveUserPath(resolveAgentWorkspaceDir(params.config ?? {}, agentId)),
|
|
2674
|
-
usedFallback: true,
|
|
2675
|
-
fallbackReason,
|
|
2676
|
-
agentId,
|
|
2677
|
-
agentIdSource
|
|
2678
|
-
};
|
|
2679
|
-
}
|
|
2680
|
-
|
|
2681
|
-
//#endregion
|
|
2682
|
-
//#region src/agents/cli-runner.ts
|
|
2683
|
-
const log$3 = createSubsystemLogger("agent/claude-cli");
|
|
2684
|
-
async function runCliAgent(params) {
|
|
2685
|
-
const started = Date.now();
|
|
2686
|
-
const workspaceResolution = resolveRunWorkspaceDir({
|
|
2687
|
-
workspaceDir: params.workspaceDir,
|
|
2688
|
-
sessionKey: params.sessionKey,
|
|
2689
|
-
agentId: params.agentId,
|
|
2690
|
-
config: params.config
|
|
2691
|
-
});
|
|
2692
|
-
const resolvedWorkspace = workspaceResolution.workspaceDir;
|
|
2693
|
-
const redactedSessionId = redactRunIdentifier(params.sessionId);
|
|
2694
|
-
const redactedSessionKey = redactRunIdentifier(params.sessionKey);
|
|
2695
|
-
const redactedWorkspace = redactRunIdentifier(resolvedWorkspace);
|
|
2696
|
-
if (workspaceResolution.usedFallback) log$3.warn(`[workspace-fallback] caller=runCliAgent reason=${workspaceResolution.fallbackReason} run=${params.runId} session=${redactedSessionId} sessionKey=${redactedSessionKey} agent=${workspaceResolution.agentId} workspace=${redactedWorkspace}`);
|
|
2697
|
-
const workspaceDir = resolvedWorkspace;
|
|
2698
|
-
const backendResolved = resolveCliBackendConfig(params.provider, params.config);
|
|
2699
|
-
if (!backendResolved) throw new Error(`Unknown CLI backend: ${params.provider}`);
|
|
2700
|
-
const backend = backendResolved.config;
|
|
2701
|
-
const modelId = (params.model ?? "default").trim() || "default";
|
|
2702
|
-
const normalizedModel = normalizeCliModel(modelId, backend);
|
|
2703
|
-
const modelDisplay = `${params.provider}/${modelId}`;
|
|
2704
|
-
const extraSystemPrompt = [params.extraSystemPrompt?.trim(), "Tools are disabled in this session. Do not call tools."].filter(Boolean).join("\n");
|
|
2705
|
-
const sessionLabel = params.sessionKey ?? params.sessionId;
|
|
2706
|
-
const { contextFiles } = await resolveBootstrapContextForRun({
|
|
2707
|
-
workspaceDir,
|
|
2708
|
-
config: params.config,
|
|
2709
|
-
sessionKey: params.sessionKey,
|
|
2710
|
-
sessionId: params.sessionId,
|
|
2711
|
-
warn: makeBootstrapWarn({
|
|
2712
|
-
sessionLabel,
|
|
2713
|
-
warn: (message) => log$3.warn(message)
|
|
2714
|
-
})
|
|
2715
|
-
});
|
|
2716
|
-
const { defaultAgentId, sessionAgentId } = resolveSessionAgentIds({
|
|
2717
|
-
sessionKey: params.sessionKey,
|
|
2718
|
-
config: params.config
|
|
2719
|
-
});
|
|
2720
|
-
const heartbeatPrompt = sessionAgentId === defaultAgentId ? resolveHeartbeatPrompt(params.config?.agents?.defaults?.heartbeat?.prompt) : void 0;
|
|
2721
|
-
const docsPath = await resolveAnimaDocsPath({
|
|
2722
|
-
workspaceDir,
|
|
2723
|
-
argv1: process.argv[1],
|
|
2724
|
-
cwd: process.cwd(),
|
|
2725
|
-
moduleUrl: import.meta.url
|
|
2726
|
-
});
|
|
2727
|
-
const systemPrompt = buildSystemPrompt({
|
|
2728
|
-
workspaceDir,
|
|
2729
|
-
config: params.config,
|
|
2730
|
-
defaultThinkLevel: params.thinkLevel,
|
|
2731
|
-
extraSystemPrompt,
|
|
2732
|
-
ownerNumbers: params.ownerNumbers,
|
|
2733
|
-
heartbeatPrompt,
|
|
2734
|
-
docsPath: docsPath ?? void 0,
|
|
2735
|
-
tools: [],
|
|
2736
|
-
contextFiles,
|
|
2737
|
-
modelDisplay,
|
|
2738
|
-
agentId: sessionAgentId
|
|
2739
|
-
});
|
|
2740
|
-
const { sessionId: cliSessionIdToSend, isNew } = resolveSessionIdToSend({
|
|
2741
|
-
backend,
|
|
2742
|
-
cliSessionId: params.cliSessionId
|
|
2743
|
-
});
|
|
2744
|
-
const useResume = Boolean(params.cliSessionId && cliSessionIdToSend && backend.resumeArgs && backend.resumeArgs.length > 0);
|
|
2745
|
-
const sessionIdSent = cliSessionIdToSend ? useResume || Boolean(backend.sessionArg) || Boolean(backend.sessionArgs?.length) ? cliSessionIdToSend : void 0 : void 0;
|
|
2746
|
-
const systemPromptArg = resolveSystemPromptUsage({
|
|
2747
|
-
backend,
|
|
2748
|
-
isNewSession: isNew,
|
|
2749
|
-
systemPrompt
|
|
2750
|
-
});
|
|
2751
|
-
let imagePaths;
|
|
2752
|
-
let cleanupImages;
|
|
2753
|
-
let prompt = params.prompt;
|
|
2754
|
-
if (params.images && params.images.length > 0) {
|
|
2755
|
-
const imagePayload = await writeCliImages(params.images);
|
|
2756
|
-
imagePaths = imagePayload.paths;
|
|
2757
|
-
cleanupImages = imagePayload.cleanup;
|
|
2758
|
-
if (!backend.imageArg) prompt = appendImagePathsToPrompt(prompt, imagePaths);
|
|
2759
|
-
}
|
|
2760
|
-
const { argsPrompt, stdin } = resolvePromptInput({
|
|
2761
|
-
backend,
|
|
2762
|
-
prompt
|
|
2763
|
-
});
|
|
2764
|
-
const stdinPayload = stdin ?? "";
|
|
2765
|
-
const baseArgs = useResume ? backend.resumeArgs ?? backend.args ?? [] : backend.args ?? [];
|
|
2766
|
-
const args = buildCliArgs({
|
|
2767
|
-
backend,
|
|
2768
|
-
baseArgs: useResume ? baseArgs.map((entry) => entry.replaceAll("{sessionId}", cliSessionIdToSend ?? "")) : baseArgs,
|
|
2769
|
-
modelId: normalizedModel,
|
|
2770
|
-
sessionId: cliSessionIdToSend,
|
|
2771
|
-
systemPrompt: systemPromptArg,
|
|
2772
|
-
imagePaths,
|
|
2773
|
-
promptArg: argsPrompt,
|
|
2774
|
-
useResume
|
|
2775
|
-
});
|
|
2776
|
-
const queueKey = backend.serialize ?? true ? backendResolved.id : `${backendResolved.id}:${params.runId}`;
|
|
2777
|
-
try {
|
|
2778
|
-
const output = await enqueueCliRun(queueKey, async () => {
|
|
2779
|
-
log$3.info(`cli exec: provider=${params.provider} model=${normalizedModel} promptChars=${params.prompt.length}`);
|
|
2780
|
-
const logOutputText = isTruthyEnvValue(process.env.ANIMA_CLAUDE_CLI_LOG_OUTPUT);
|
|
2781
|
-
if (logOutputText) {
|
|
2782
|
-
const logArgs = [];
|
|
2783
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
2784
|
-
const arg = args[i] ?? "";
|
|
2785
|
-
if (arg === backend.systemPromptArg) {
|
|
2786
|
-
const systemPromptValue = args[i + 1] ?? "";
|
|
2787
|
-
logArgs.push(arg, `<systemPrompt:${systemPromptValue.length} chars>`);
|
|
2788
|
-
i += 1;
|
|
2789
|
-
continue;
|
|
2790
|
-
}
|
|
2791
|
-
if (arg === backend.sessionArg) {
|
|
2792
|
-
logArgs.push(arg, args[i + 1] ?? "");
|
|
2793
|
-
i += 1;
|
|
2794
|
-
continue;
|
|
2795
|
-
}
|
|
2796
|
-
if (arg === backend.modelArg) {
|
|
2797
|
-
logArgs.push(arg, args[i + 1] ?? "");
|
|
2798
|
-
i += 1;
|
|
2799
|
-
continue;
|
|
2800
|
-
}
|
|
2801
|
-
if (arg === backend.imageArg) {
|
|
2802
|
-
logArgs.push(arg, "<image>");
|
|
2803
|
-
i += 1;
|
|
2804
|
-
continue;
|
|
2805
|
-
}
|
|
2806
|
-
logArgs.push(arg);
|
|
2807
|
-
}
|
|
2808
|
-
if (argsPrompt) {
|
|
2809
|
-
const promptIndex = logArgs.indexOf(argsPrompt);
|
|
2810
|
-
if (promptIndex >= 0) logArgs[promptIndex] = `<prompt:${argsPrompt.length} chars>`;
|
|
2811
|
-
}
|
|
2812
|
-
log$3.info(`cli argv: ${backend.command} ${logArgs.join(" ")}`);
|
|
2813
|
-
}
|
|
2814
|
-
const env = (() => {
|
|
2815
|
-
const next = {
|
|
2816
|
-
...process.env,
|
|
2817
|
-
...backend.env
|
|
2818
|
-
};
|
|
2819
|
-
for (const key of backend.clearEnv ?? []) delete next[key];
|
|
2820
|
-
return next;
|
|
2821
|
-
})();
|
|
2822
|
-
await cleanupSuspendedCliProcesses(backend);
|
|
2823
|
-
if (useResume && cliSessionIdToSend) await cleanupResumeProcesses(backend, cliSessionIdToSend);
|
|
2824
|
-
const result = await runCommandWithTimeout([backend.command, ...args], {
|
|
2825
|
-
timeoutMs: params.timeoutMs,
|
|
2826
|
-
cwd: workspaceDir,
|
|
2827
|
-
env,
|
|
2828
|
-
input: stdinPayload
|
|
2829
|
-
});
|
|
2830
|
-
const stdout = result.stdout.trim();
|
|
2831
|
-
const stderr = result.stderr.trim();
|
|
2832
|
-
if (logOutputText) {
|
|
2833
|
-
if (stdout) log$3.info(`cli stdout:\n${stdout}`);
|
|
2834
|
-
if (stderr) log$3.info(`cli stderr:\n${stderr}`);
|
|
2835
|
-
}
|
|
2836
|
-
if (shouldLogVerbose()) {
|
|
2837
|
-
if (stdout) log$3.debug(`cli stdout:\n${stdout}`);
|
|
2838
|
-
if (stderr) log$3.debug(`cli stderr:\n${stderr}`);
|
|
2839
|
-
}
|
|
2840
|
-
if (result.code !== 0) {
|
|
2841
|
-
const err = stderr || stdout || "CLI failed.";
|
|
2842
|
-
const reason = classifyFailoverReason(err) ?? "unknown";
|
|
2843
|
-
const status = resolveFailoverStatus(reason);
|
|
2844
|
-
throw new FailoverError(err, {
|
|
2845
|
-
reason,
|
|
2846
|
-
provider: params.provider,
|
|
2847
|
-
model: modelId,
|
|
2848
|
-
status
|
|
2849
|
-
});
|
|
2850
|
-
}
|
|
2851
|
-
const outputMode = useResume ? backend.resumeOutput ?? backend.output : backend.output;
|
|
2852
|
-
if (outputMode === "text") return {
|
|
2853
|
-
text: stdout,
|
|
2854
|
-
sessionId: void 0
|
|
2855
|
-
};
|
|
2856
|
-
if (outputMode === "jsonl") return parseCliJsonl(stdout, backend) ?? { text: stdout };
|
|
2857
|
-
return parseCliJson(stdout, backend) ?? { text: stdout };
|
|
2858
|
-
});
|
|
2859
|
-
const text = output.text?.trim();
|
|
2860
|
-
return {
|
|
2861
|
-
payloads: text ? [{ text }] : void 0,
|
|
2862
|
-
meta: {
|
|
2863
|
-
durationMs: Date.now() - started,
|
|
2864
|
-
agentMeta: {
|
|
2865
|
-
sessionId: output.sessionId ?? sessionIdSent ?? params.sessionId ?? "",
|
|
2866
|
-
provider: params.provider,
|
|
2867
|
-
model: modelId,
|
|
2868
|
-
usage: output.usage
|
|
2869
|
-
}
|
|
2870
|
-
}
|
|
2871
|
-
};
|
|
2872
|
-
} catch (err) {
|
|
2873
|
-
if (err instanceof FailoverError) throw err;
|
|
2874
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
2875
|
-
if (isFailoverErrorMessage(message)) {
|
|
2876
|
-
const reason = classifyFailoverReason(message) ?? "unknown";
|
|
2877
|
-
const status = resolveFailoverStatus(reason);
|
|
2878
|
-
throw new FailoverError(message, {
|
|
2879
|
-
reason,
|
|
2880
|
-
provider: params.provider,
|
|
2881
|
-
model: modelId,
|
|
2882
|
-
status
|
|
2883
|
-
});
|
|
2884
|
-
}
|
|
2885
|
-
throw err;
|
|
2886
|
-
} finally {
|
|
2887
|
-
if (cleanupImages) await cleanupImages();
|
|
2888
|
-
}
|
|
2889
|
-
}
|
|
2890
|
-
|
|
2891
|
-
//#endregion
|
|
2892
|
-
//#region src/agents/cli-session.ts
|
|
2893
|
-
function getCliSessionId(entry, provider) {
|
|
2894
|
-
if (!entry) return;
|
|
2895
|
-
const normalized = normalizeProviderId$1(provider);
|
|
2896
|
-
const fromMap = entry.cliSessionIds?.[normalized];
|
|
2897
|
-
if (fromMap?.trim()) return fromMap.trim();
|
|
2898
|
-
if (normalized === "claude-cli") {
|
|
2899
|
-
const legacy = entry.claudeCliSessionId?.trim();
|
|
2900
|
-
if (legacy) return legacy;
|
|
2901
|
-
}
|
|
2902
|
-
}
|
|
2903
|
-
function setCliSessionId(entry, provider, sessionId) {
|
|
2904
|
-
const normalized = normalizeProviderId$1(provider);
|
|
2905
|
-
const trimmed = sessionId.trim();
|
|
2906
|
-
if (!trimmed) return;
|
|
2907
|
-
entry.cliSessionIds = { ...entry.cliSessionIds ?? {} };
|
|
2908
|
-
entry.cliSessionIds[normalized] = trimmed;
|
|
2909
|
-
if (normalized === "claude-cli") entry.claudeCliSessionId = trimmed;
|
|
2910
|
-
}
|
|
2911
|
-
|
|
2912
|
-
//#endregion
|
|
2913
|
-
//#region src/agents/models-config.ts
|
|
2914
|
-
/**
|
|
2915
|
-
* Models configuration — SIMPLIFIED
|
|
2916
|
-
*
|
|
2917
|
-
* The multi-provider LLM abstraction (pi-ai) has been removed.
|
|
2918
|
-
* ANIMA uses Claude Code CLI exclusively. This file retains only
|
|
2919
|
-
* the minimal interface needed by the rest of the codebase.
|
|
2920
|
-
* Full replacement comes in Phase 2.
|
|
2921
|
-
*/
|
|
2922
|
-
async function ensureAnimaModelsJson(config, agentDirOverride) {
|
|
2923
|
-
config ?? loadConfig();
|
|
2924
|
-
const agentDir = agentDirOverride?.trim() ? agentDirOverride.trim() : resolveAnimaAgentDir();
|
|
2925
|
-
await fs.mkdir(agentDir, {
|
|
2926
|
-
recursive: true,
|
|
2927
|
-
mode: 448
|
|
2928
|
-
});
|
|
2929
|
-
const targetPath = path.join(agentDir, "models.json");
|
|
2930
|
-
const content = JSON.stringify({ providers: {} }, null, 2) + "\n";
|
|
2931
|
-
let existing = "";
|
|
2932
|
-
try {
|
|
2933
|
-
existing = await fs.readFile(targetPath, "utf8");
|
|
2934
|
-
} catch {}
|
|
2935
|
-
if (existing === content) return {
|
|
2936
|
-
agentDir,
|
|
2937
|
-
wrote: false
|
|
2938
|
-
};
|
|
2939
|
-
await fs.writeFile(targetPath, content, { mode: 384 });
|
|
2940
|
-
return {
|
|
2941
|
-
agentDir,
|
|
2942
|
-
wrote: true
|
|
2943
|
-
};
|
|
2944
|
-
}
|
|
2945
|
-
|
|
2946
|
-
//#endregion
|
|
2947
|
-
//#region src/agents/model-catalog.ts
|
|
2948
|
-
let modelCatalogPromise = null;
|
|
2949
|
-
let hasLoggedModelCatalogError = false;
|
|
2950
|
-
const defaultImportPiSdk = () => import("./pi-model-discovery-Cxs4pvC2.js");
|
|
2951
|
-
let importPiSdk = defaultImportPiSdk;
|
|
2952
|
-
const CODEX_PROVIDER = "openai-codex";
|
|
2953
|
-
const OPENAI_CODEX_GPT53_MODEL_ID = "gpt-5.3-codex";
|
|
2954
|
-
const OPENAI_CODEX_GPT53_SPARK_MODEL_ID = "gpt-5.3-codex-spark";
|
|
2955
|
-
function applyOpenAICodexSparkFallback(models) {
|
|
2956
|
-
if (models.some((entry) => entry.provider === CODEX_PROVIDER && entry.id.toLowerCase() === OPENAI_CODEX_GPT53_SPARK_MODEL_ID)) return;
|
|
2957
|
-
const baseModel = models.find((entry) => entry.provider === CODEX_PROVIDER && entry.id.toLowerCase() === OPENAI_CODEX_GPT53_MODEL_ID);
|
|
2958
|
-
if (!baseModel) return;
|
|
2959
|
-
models.push({
|
|
2960
|
-
...baseModel,
|
|
2961
|
-
id: OPENAI_CODEX_GPT53_SPARK_MODEL_ID,
|
|
2962
|
-
name: OPENAI_CODEX_GPT53_SPARK_MODEL_ID
|
|
2963
|
-
});
|
|
2964
|
-
}
|
|
2965
|
-
async function loadModelCatalog(params) {
|
|
2966
|
-
if (params?.useCache === false) modelCatalogPromise = null;
|
|
2967
|
-
if (modelCatalogPromise) return modelCatalogPromise;
|
|
2968
|
-
modelCatalogPromise = (async () => {
|
|
2969
|
-
const models = [];
|
|
2970
|
-
const sortModels = (entries) => entries.sort((a, b) => {
|
|
2971
|
-
const p = a.provider.localeCompare(b.provider);
|
|
2972
|
-
if (p !== 0) return p;
|
|
2973
|
-
return a.name.localeCompare(b.name);
|
|
2974
|
-
});
|
|
2975
|
-
try {
|
|
2976
|
-
await ensureAnimaModelsJson(params?.config ?? loadConfig());
|
|
2977
|
-
await (await import("./pi-auth-json-ZYzi3nxs.js")).ensurePiAuthJsonFromAuthProfiles(resolveAnimaAgentDir());
|
|
2978
|
-
const piSdk = await importPiSdk();
|
|
2979
|
-
const agentDir = resolveAnimaAgentDir();
|
|
2980
|
-
const { join } = await import("node:path");
|
|
2981
|
-
const authStorage = new piSdk.AuthStorage(join(agentDir, "auth.json"));
|
|
2982
|
-
const registry = new piSdk.ModelRegistry(authStorage, join(agentDir, "models.json"));
|
|
2983
|
-
const entries = Array.isArray(registry) ? registry : registry.getAll();
|
|
2984
|
-
for (const entry of entries) {
|
|
2985
|
-
const id = String(entry?.id ?? "").trim();
|
|
2986
|
-
if (!id) continue;
|
|
2987
|
-
const provider = String(entry?.provider ?? "").trim();
|
|
2988
|
-
if (!provider) continue;
|
|
2989
|
-
const name = String(entry?.name ?? id).trim() || id;
|
|
2990
|
-
const contextWindow = typeof entry?.contextWindow === "number" && entry.contextWindow > 0 ? entry.contextWindow : void 0;
|
|
2991
|
-
const reasoning = typeof entry?.reasoning === "boolean" ? entry.reasoning : void 0;
|
|
2992
|
-
const input = Array.isArray(entry?.input) ? entry.input : void 0;
|
|
2993
|
-
models.push({
|
|
2994
|
-
id,
|
|
2995
|
-
name,
|
|
2996
|
-
provider,
|
|
2997
|
-
contextWindow,
|
|
2998
|
-
reasoning,
|
|
2999
|
-
input
|
|
3000
|
-
});
|
|
3001
|
-
}
|
|
3002
|
-
applyOpenAICodexSparkFallback(models);
|
|
3003
|
-
if (models.length === 0) modelCatalogPromise = null;
|
|
3004
|
-
return sortModels(models);
|
|
3005
|
-
} catch (error) {
|
|
3006
|
-
if (!hasLoggedModelCatalogError) {
|
|
3007
|
-
hasLoggedModelCatalogError = true;
|
|
3008
|
-
console.warn(`[model-catalog] Failed to load model catalog: ${String(error)}`);
|
|
3009
|
-
}
|
|
3010
|
-
modelCatalogPromise = null;
|
|
3011
|
-
if (models.length > 0) return sortModels(models);
|
|
3012
|
-
return [];
|
|
3013
|
-
}
|
|
3014
|
-
})();
|
|
3015
|
-
return modelCatalogPromise;
|
|
3016
|
-
}
|
|
3017
|
-
/**
|
|
3018
|
-
* Check if a model supports image input based on its catalog entry.
|
|
3019
|
-
*/
|
|
3020
|
-
function modelSupportsVision(entry) {
|
|
3021
|
-
return entry?.input?.includes("image") ?? false;
|
|
3022
|
-
}
|
|
3023
|
-
/**
|
|
3024
|
-
* Find a model in the catalog by provider and model ID.
|
|
3025
|
-
*/
|
|
3026
|
-
function findModelInCatalog(catalog, provider, modelId) {
|
|
3027
|
-
const normalizedProvider = provider.toLowerCase().trim();
|
|
3028
|
-
const normalizedModelId = modelId.toLowerCase().trim();
|
|
3029
|
-
return catalog.find((entry) => entry.provider.toLowerCase() === normalizedProvider && entry.id.toLowerCase() === normalizedModelId);
|
|
3030
|
-
}
|
|
3031
|
-
|
|
3032
|
-
//#endregion
|
|
3033
|
-
//#region src/agents/model-fallback.ts
|
|
3034
|
-
/**
|
|
3035
|
-
* Fallback abort check. Only treats explicit AbortError names as user aborts.
|
|
3036
|
-
* Message-based checks (e.g., "aborted") can mask timeouts and skip fallback.
|
|
3037
|
-
*/
|
|
3038
|
-
function isFallbackAbortError(err) {
|
|
3039
|
-
if (!err || typeof err !== "object") return false;
|
|
3040
|
-
if (isFailoverError(err)) return false;
|
|
3041
|
-
return ("name" in err ? String(err.name) : "") === "AbortError";
|
|
3042
|
-
}
|
|
3043
|
-
function shouldRethrowAbort(err) {
|
|
3044
|
-
return isFallbackAbortError(err) && !isTimeoutError(err);
|
|
3045
|
-
}
|
|
3046
|
-
function createModelCandidateCollector(allowlist) {
|
|
3047
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3048
|
-
const candidates = [];
|
|
3049
|
-
const addCandidate = (candidate, enforceAllowlist) => {
|
|
3050
|
-
if (!candidate.provider || !candidate.model) return;
|
|
3051
|
-
const key = modelKey(candidate.provider, candidate.model);
|
|
3052
|
-
if (seen.has(key)) return;
|
|
3053
|
-
if (enforceAllowlist && allowlist && !allowlist.has(key)) return;
|
|
3054
|
-
seen.add(key);
|
|
3055
|
-
candidates.push(candidate);
|
|
3056
|
-
};
|
|
3057
|
-
return {
|
|
3058
|
-
candidates,
|
|
3059
|
-
addCandidate
|
|
3060
|
-
};
|
|
3061
|
-
}
|
|
3062
|
-
function resolveImageFallbackCandidates(params) {
|
|
3063
|
-
const aliasIndex = buildModelAliasIndex({
|
|
3064
|
-
cfg: params.cfg ?? {},
|
|
3065
|
-
defaultProvider: params.defaultProvider
|
|
3066
|
-
});
|
|
3067
|
-
const { candidates, addCandidate } = createModelCandidateCollector(buildConfiguredAllowlistKeys({
|
|
3068
|
-
cfg: params.cfg,
|
|
3069
|
-
defaultProvider: params.defaultProvider
|
|
3070
|
-
}));
|
|
3071
|
-
const addRaw = (raw, enforceAllowlist) => {
|
|
3072
|
-
const resolved = resolveModelRefFromString({
|
|
3073
|
-
raw: String(raw ?? ""),
|
|
3074
|
-
defaultProvider: params.defaultProvider,
|
|
3075
|
-
aliasIndex
|
|
3076
|
-
});
|
|
3077
|
-
if (!resolved) return;
|
|
3078
|
-
addCandidate(resolved.ref, enforceAllowlist);
|
|
3079
|
-
};
|
|
3080
|
-
if (params.modelOverride?.trim()) addRaw(params.modelOverride, false);
|
|
3081
|
-
else {
|
|
3082
|
-
const imageModel = params.cfg?.agents?.defaults?.imageModel;
|
|
3083
|
-
const primary = typeof imageModel === "string" ? imageModel.trim() : imageModel?.primary;
|
|
3084
|
-
if (primary?.trim()) addRaw(primary, false);
|
|
3085
|
-
}
|
|
3086
|
-
const imageFallbacks = (() => {
|
|
3087
|
-
const imageModel = params.cfg?.agents?.defaults?.imageModel;
|
|
3088
|
-
if (imageModel && typeof imageModel === "object") return imageModel.fallbacks ?? [];
|
|
3089
|
-
return [];
|
|
3090
|
-
})();
|
|
3091
|
-
for (const raw of imageFallbacks) addRaw(raw, true);
|
|
3092
|
-
return candidates;
|
|
3093
|
-
}
|
|
3094
|
-
function resolveFallbackCandidates(params) {
|
|
3095
|
-
const primary = params.cfg ? resolveConfiguredModelRef({
|
|
3096
|
-
cfg: params.cfg,
|
|
3097
|
-
defaultProvider: DEFAULT_PROVIDER,
|
|
3098
|
-
defaultModel: DEFAULT_MODEL
|
|
3099
|
-
}) : null;
|
|
3100
|
-
const defaultProvider = primary?.provider ?? DEFAULT_PROVIDER;
|
|
3101
|
-
const defaultModel = primary?.model ?? DEFAULT_MODEL;
|
|
3102
|
-
const normalizedPrimary = normalizeModelRef(String(params.provider ?? "").trim() || defaultProvider, String(params.model ?? "").trim() || defaultModel);
|
|
3103
|
-
const aliasIndex = buildModelAliasIndex({
|
|
3104
|
-
cfg: params.cfg ?? {},
|
|
3105
|
-
defaultProvider
|
|
3106
|
-
});
|
|
3107
|
-
const { candidates, addCandidate } = createModelCandidateCollector(buildConfiguredAllowlistKeys({
|
|
3108
|
-
cfg: params.cfg,
|
|
3109
|
-
defaultProvider
|
|
3110
|
-
}));
|
|
3111
|
-
addCandidate(normalizedPrimary, false);
|
|
3112
|
-
const modelFallbacks = (() => {
|
|
3113
|
-
if (params.fallbacksOverride !== void 0) return params.fallbacksOverride;
|
|
3114
|
-
const model = params.cfg?.agents?.defaults?.model;
|
|
3115
|
-
if (model && typeof model === "object") return model.fallbacks ?? [];
|
|
3116
|
-
return [];
|
|
3117
|
-
})();
|
|
3118
|
-
for (const raw of modelFallbacks) {
|
|
3119
|
-
const resolved = resolveModelRefFromString({
|
|
3120
|
-
raw: String(raw ?? ""),
|
|
3121
|
-
defaultProvider,
|
|
3122
|
-
aliasIndex
|
|
3123
|
-
});
|
|
3124
|
-
if (!resolved) continue;
|
|
3125
|
-
addCandidate(resolved.ref, true);
|
|
3126
|
-
}
|
|
3127
|
-
if (params.fallbacksOverride === void 0 && primary?.provider && primary.model) addCandidate({
|
|
3128
|
-
provider: primary.provider,
|
|
3129
|
-
model: primary.model
|
|
3130
|
-
}, false);
|
|
3131
|
-
return candidates;
|
|
3132
|
-
}
|
|
3133
|
-
async function runWithModelFallback(params) {
|
|
3134
|
-
const candidates = resolveFallbackCandidates({
|
|
3135
|
-
cfg: params.cfg,
|
|
3136
|
-
provider: params.provider,
|
|
3137
|
-
model: params.model,
|
|
3138
|
-
fallbacksOverride: params.fallbacksOverride
|
|
3139
|
-
});
|
|
3140
|
-
const authStore = params.cfg ? ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false }) : null;
|
|
3141
|
-
const attempts = [];
|
|
3142
|
-
let lastError;
|
|
3143
|
-
for (let i = 0; i < candidates.length; i += 1) {
|
|
3144
|
-
const candidate = candidates[i];
|
|
3145
|
-
if (authStore) {
|
|
3146
|
-
const profileIds = resolveAuthProfileOrder({
|
|
3147
|
-
cfg: params.cfg,
|
|
3148
|
-
store: authStore,
|
|
3149
|
-
provider: candidate.provider
|
|
3150
|
-
});
|
|
3151
|
-
const isAnyProfileAvailable = profileIds.some((id) => !isProfileInCooldown(authStore, id));
|
|
3152
|
-
if (profileIds.length > 0 && !isAnyProfileAvailable) {
|
|
3153
|
-
attempts.push({
|
|
3154
|
-
provider: candidate.provider,
|
|
3155
|
-
model: candidate.model,
|
|
3156
|
-
error: `Provider ${candidate.provider} is in cooldown (all profiles unavailable)`,
|
|
3157
|
-
reason: "rate_limit"
|
|
3158
|
-
});
|
|
3159
|
-
continue;
|
|
3160
|
-
}
|
|
3161
|
-
}
|
|
3162
|
-
try {
|
|
3163
|
-
return {
|
|
3164
|
-
result: await params.run(candidate.provider, candidate.model),
|
|
3165
|
-
provider: candidate.provider,
|
|
3166
|
-
model: candidate.model,
|
|
3167
|
-
attempts
|
|
3168
|
-
};
|
|
3169
|
-
} catch (err) {
|
|
3170
|
-
if (shouldRethrowAbort(err)) throw err;
|
|
3171
|
-
if (isLikelyContextOverflowError(err instanceof Error ? err.message : String(err))) throw err;
|
|
3172
|
-
const normalized = coerceToFailoverError(err, {
|
|
3173
|
-
provider: candidate.provider,
|
|
3174
|
-
model: candidate.model
|
|
3175
|
-
}) ?? err;
|
|
3176
|
-
if (!isFailoverError(normalized)) throw err;
|
|
3177
|
-
lastError = normalized;
|
|
3178
|
-
const described = describeFailoverError(normalized);
|
|
3179
|
-
attempts.push({
|
|
3180
|
-
provider: candidate.provider,
|
|
3181
|
-
model: candidate.model,
|
|
3182
|
-
error: described.message,
|
|
3183
|
-
reason: described.reason,
|
|
3184
|
-
status: described.status,
|
|
3185
|
-
code: described.code
|
|
3186
|
-
});
|
|
3187
|
-
await params.onError?.({
|
|
3188
|
-
provider: candidate.provider,
|
|
3189
|
-
model: candidate.model,
|
|
3190
|
-
error: normalized,
|
|
3191
|
-
attempt: i + 1,
|
|
3192
|
-
total: candidates.length
|
|
3193
|
-
});
|
|
3194
|
-
}
|
|
3195
|
-
}
|
|
3196
|
-
if (attempts.length <= 1 && lastError) throw lastError;
|
|
3197
|
-
const summary = attempts.length > 0 ? attempts.map((attempt) => `${attempt.provider}/${attempt.model}: ${attempt.error}${attempt.reason ? ` (${attempt.reason})` : ""}`).join(" | ") : "unknown";
|
|
3198
|
-
throw new Error(`All models failed (${attempts.length || candidates.length}): ${summary}`, { cause: lastError instanceof Error ? lastError : void 0 });
|
|
3199
|
-
}
|
|
3200
|
-
async function runWithImageModelFallback(params) {
|
|
3201
|
-
const candidates = resolveImageFallbackCandidates({
|
|
3202
|
-
cfg: params.cfg,
|
|
3203
|
-
defaultProvider: DEFAULT_PROVIDER,
|
|
3204
|
-
modelOverride: params.modelOverride
|
|
3205
|
-
});
|
|
3206
|
-
if (candidates.length === 0) throw new Error("No image model configured. Set agents.defaults.imageModel.primary or agents.defaults.imageModel.fallbacks.");
|
|
3207
|
-
const attempts = [];
|
|
3208
|
-
let lastError;
|
|
3209
|
-
for (let i = 0; i < candidates.length; i += 1) {
|
|
3210
|
-
const candidate = candidates[i];
|
|
3211
|
-
try {
|
|
3212
|
-
return {
|
|
3213
|
-
result: await params.run(candidate.provider, candidate.model),
|
|
3214
|
-
provider: candidate.provider,
|
|
3215
|
-
model: candidate.model,
|
|
3216
|
-
attempts
|
|
3217
|
-
};
|
|
3218
|
-
} catch (err) {
|
|
3219
|
-
if (shouldRethrowAbort(err)) throw err;
|
|
3220
|
-
lastError = err;
|
|
3221
|
-
attempts.push({
|
|
3222
|
-
provider: candidate.provider,
|
|
3223
|
-
model: candidate.model,
|
|
3224
|
-
error: err instanceof Error ? err.message : String(err)
|
|
3225
|
-
});
|
|
3226
|
-
await params.onError?.({
|
|
3227
|
-
provider: candidate.provider,
|
|
3228
|
-
model: candidate.model,
|
|
3229
|
-
error: err,
|
|
3230
|
-
attempt: i + 1,
|
|
3231
|
-
total: candidates.length
|
|
3232
|
-
});
|
|
3233
|
-
}
|
|
3234
|
-
}
|
|
3235
|
-
if (attempts.length <= 1 && lastError) throw lastError;
|
|
3236
|
-
const summary = attempts.length > 0 ? attempts.map((attempt) => `${attempt.provider}/${attempt.model}: ${attempt.error}`).join(" | ") : "unknown";
|
|
3237
|
-
throw new Error(`All image models failed (${attempts.length || candidates.length}): ${summary}`, { cause: lastError instanceof Error ? lastError : void 0 });
|
|
3238
|
-
}
|
|
3239
|
-
|
|
3240
|
-
//#endregion
|
|
3241
|
-
//#region src/agents/skills/frontmatter.ts
|
|
3242
|
-
function parseFrontmatter(content) {
|
|
3243
|
-
return parseFrontmatterBlock(content);
|
|
3244
|
-
}
|
|
3245
|
-
function parseInstallSpec(input) {
|
|
3246
|
-
if (!input || typeof input !== "object") return;
|
|
3247
|
-
const raw = input;
|
|
3248
|
-
const kind = (typeof raw.kind === "string" ? raw.kind : typeof raw.type === "string" ? raw.type : "").trim().toLowerCase();
|
|
3249
|
-
if (kind !== "brew" && kind !== "node" && kind !== "go" && kind !== "uv" && kind !== "download") return;
|
|
3250
|
-
const spec = { kind };
|
|
3251
|
-
if (typeof raw.id === "string") spec.id = raw.id;
|
|
3252
|
-
if (typeof raw.label === "string") spec.label = raw.label;
|
|
3253
|
-
const bins = normalizeStringList(raw.bins);
|
|
3254
|
-
if (bins.length > 0) spec.bins = bins;
|
|
3255
|
-
const osList = normalizeStringList(raw.os);
|
|
3256
|
-
if (osList.length > 0) spec.os = osList;
|
|
3257
|
-
if (typeof raw.formula === "string") spec.formula = raw.formula;
|
|
3258
|
-
if (typeof raw.package === "string") spec.package = raw.package;
|
|
3259
|
-
if (typeof raw.module === "string") spec.module = raw.module;
|
|
3260
|
-
if (typeof raw.url === "string") spec.url = raw.url;
|
|
3261
|
-
if (typeof raw.archive === "string") spec.archive = raw.archive;
|
|
3262
|
-
if (typeof raw.extract === "boolean") spec.extract = raw.extract;
|
|
3263
|
-
if (typeof raw.stripComponents === "number") spec.stripComponents = raw.stripComponents;
|
|
3264
|
-
if (typeof raw.targetDir === "string") spec.targetDir = raw.targetDir;
|
|
3265
|
-
return spec;
|
|
3266
|
-
}
|
|
3267
|
-
function resolveAnimaMetadata(frontmatter) {
|
|
3268
|
-
const metadataObj = resolveAnimaManifestBlock({ frontmatter });
|
|
3269
|
-
if (!metadataObj) return;
|
|
3270
|
-
const requiresRaw = typeof metadataObj.requires === "object" && metadataObj.requires !== null ? metadataObj.requires : void 0;
|
|
3271
|
-
const install = (Array.isArray(metadataObj.install) ? metadataObj.install : []).map((entry) => parseInstallSpec(entry)).filter((entry) => Boolean(entry));
|
|
3272
|
-
const osRaw = normalizeStringList(metadataObj.os);
|
|
3273
|
-
return {
|
|
3274
|
-
always: typeof metadataObj.always === "boolean" ? metadataObj.always : void 0,
|
|
3275
|
-
emoji: typeof metadataObj.emoji === "string" ? metadataObj.emoji : void 0,
|
|
3276
|
-
homepage: typeof metadataObj.homepage === "string" ? metadataObj.homepage : void 0,
|
|
3277
|
-
skillKey: typeof metadataObj.skillKey === "string" ? metadataObj.skillKey : void 0,
|
|
3278
|
-
primaryEnv: typeof metadataObj.primaryEnv === "string" ? metadataObj.primaryEnv : void 0,
|
|
3279
|
-
os: osRaw.length > 0 ? osRaw : void 0,
|
|
3280
|
-
requires: requiresRaw ? {
|
|
3281
|
-
bins: normalizeStringList(requiresRaw.bins),
|
|
3282
|
-
anyBins: normalizeStringList(requiresRaw.anyBins),
|
|
3283
|
-
env: normalizeStringList(requiresRaw.env),
|
|
3284
|
-
config: normalizeStringList(requiresRaw.config)
|
|
3285
|
-
} : void 0,
|
|
3286
|
-
install: install.length > 0 ? install : void 0
|
|
3287
|
-
};
|
|
3288
|
-
}
|
|
3289
|
-
function resolveSkillInvocationPolicy(frontmatter) {
|
|
3290
|
-
return {
|
|
3291
|
-
userInvocable: parseFrontmatterBool(getFrontmatterString(frontmatter, "user-invocable"), true),
|
|
3292
|
-
disableModelInvocation: parseFrontmatterBool(getFrontmatterString(frontmatter, "disable-model-invocation"), false)
|
|
3293
|
-
};
|
|
3294
|
-
}
|
|
3295
|
-
function resolveSkillKey(skill, entry) {
|
|
3296
|
-
return entry?.metadata?.skillKey ?? skill.name;
|
|
3297
|
-
}
|
|
3298
|
-
|
|
3299
|
-
//#endregion
|
|
3300
|
-
//#region src/agents/skills/config.ts
|
|
3301
|
-
const DEFAULT_CONFIG_VALUES = {
|
|
3302
|
-
"browser.enabled": true,
|
|
3303
|
-
"browser.evaluateEnabled": true
|
|
3304
|
-
};
|
|
3305
|
-
function isConfigPathTruthy(config, pathStr) {
|
|
3306
|
-
return isConfigPathTruthyWithDefaults(config, pathStr, DEFAULT_CONFIG_VALUES);
|
|
3307
|
-
}
|
|
3308
|
-
function resolveSkillConfig(config, skillKey) {
|
|
3309
|
-
const skills = config?.skills?.entries;
|
|
3310
|
-
if (!skills || typeof skills !== "object") return;
|
|
3311
|
-
const entry = skills[skillKey];
|
|
3312
|
-
if (!entry || typeof entry !== "object") return;
|
|
3313
|
-
return entry;
|
|
3314
|
-
}
|
|
3315
|
-
function normalizeAllowlist(input) {
|
|
3316
|
-
if (!input) return;
|
|
3317
|
-
if (!Array.isArray(input)) return;
|
|
3318
|
-
const normalized = input.map((entry) => String(entry).trim()).filter(Boolean);
|
|
3319
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
3320
|
-
}
|
|
3321
|
-
const BUNDLED_SOURCES = new Set(["anima-bundled"]);
|
|
3322
|
-
function isBundledSkill(entry) {
|
|
3323
|
-
return BUNDLED_SOURCES.has(entry.skill.source);
|
|
3324
|
-
}
|
|
3325
|
-
function isBundledSkillAllowed(entry, allowlist) {
|
|
3326
|
-
if (!allowlist || allowlist.length === 0) return true;
|
|
3327
|
-
if (!isBundledSkill(entry)) return true;
|
|
3328
|
-
const key = resolveSkillKey(entry.skill, entry);
|
|
3329
|
-
return allowlist.includes(key) || allowlist.includes(entry.skill.name);
|
|
3330
|
-
}
|
|
3331
|
-
function shouldIncludeSkill(params) {
|
|
3332
|
-
const { entry, config, eligibility } = params;
|
|
3333
|
-
const skillConfig = resolveSkillConfig(config, resolveSkillKey(entry.skill, entry));
|
|
3334
|
-
const allowBundled = normalizeAllowlist(config?.skills?.allowBundled);
|
|
3335
|
-
const osList = entry.metadata?.os ?? [];
|
|
3336
|
-
const remotePlatforms = eligibility?.remote?.platforms ?? [];
|
|
3337
|
-
if (skillConfig?.enabled === false) return false;
|
|
3338
|
-
if (!isBundledSkillAllowed(entry, allowBundled)) return false;
|
|
3339
|
-
if (osList.length > 0 && !osList.includes(resolveRuntimePlatform()) && !remotePlatforms.some((platform) => osList.includes(platform))) return false;
|
|
3340
|
-
if (entry.metadata?.always === true) return true;
|
|
3341
|
-
const requiredBins = entry.metadata?.requires?.bins ?? [];
|
|
3342
|
-
if (requiredBins.length > 0) for (const bin of requiredBins) {
|
|
3343
|
-
if (hasBinary(bin)) continue;
|
|
3344
|
-
if (eligibility?.remote?.hasBin?.(bin)) continue;
|
|
3345
|
-
return false;
|
|
3346
|
-
}
|
|
3347
|
-
const requiredAnyBins = entry.metadata?.requires?.anyBins ?? [];
|
|
3348
|
-
if (requiredAnyBins.length > 0) {
|
|
3349
|
-
if (!(requiredAnyBins.some((bin) => hasBinary(bin)) || eligibility?.remote?.hasAnyBin?.(requiredAnyBins))) return false;
|
|
3350
|
-
}
|
|
3351
|
-
const requiredEnv = entry.metadata?.requires?.env ?? [];
|
|
3352
|
-
if (requiredEnv.length > 0) for (const envName of requiredEnv) {
|
|
3353
|
-
if (process.env[envName]) continue;
|
|
3354
|
-
if (skillConfig?.env?.[envName]) continue;
|
|
3355
|
-
if (skillConfig?.apiKey && entry.metadata?.primaryEnv === envName) continue;
|
|
3356
|
-
return false;
|
|
3357
|
-
}
|
|
3358
|
-
const requiredConfig = entry.metadata?.requires?.config ?? [];
|
|
3359
|
-
if (requiredConfig.length > 0) {
|
|
3360
|
-
for (const configPath of requiredConfig) if (!isConfigPathTruthy(config, configPath)) return false;
|
|
3361
|
-
}
|
|
3362
|
-
return true;
|
|
3363
|
-
}
|
|
3364
|
-
|
|
3365
|
-
//#endregion
|
|
3366
|
-
//#region src/agents/sandbox-paths.ts
|
|
3367
|
-
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
3368
|
-
const HTTP_URL_RE = /^https?:\/\//i;
|
|
3369
|
-
const DATA_URL_RE = /^data:/i;
|
|
3370
|
-
function normalizeUnicodeSpaces(str) {
|
|
3371
|
-
return str.replace(UNICODE_SPACES, " ");
|
|
3372
|
-
}
|
|
3373
|
-
function expandPath(filePath) {
|
|
3374
|
-
const normalized = normalizeUnicodeSpaces(filePath);
|
|
3375
|
-
if (normalized === "~") return os.homedir();
|
|
3376
|
-
if (normalized.startsWith("~/")) return os.homedir() + normalized.slice(1);
|
|
3377
|
-
return normalized;
|
|
3378
|
-
}
|
|
3379
|
-
function resolveToCwd(filePath, cwd) {
|
|
3380
|
-
const expanded = expandPath(filePath);
|
|
3381
|
-
if (path.isAbsolute(expanded)) return expanded;
|
|
3382
|
-
return path.resolve(cwd, expanded);
|
|
3383
|
-
}
|
|
3384
|
-
function resolveSandboxInputPath(filePath, cwd) {
|
|
3385
|
-
return resolveToCwd(filePath, cwd);
|
|
3386
|
-
}
|
|
3387
|
-
function resolveSandboxPath(params) {
|
|
3388
|
-
const resolved = resolveSandboxInputPath(params.filePath, params.cwd);
|
|
3389
|
-
const rootResolved = path.resolve(params.root);
|
|
3390
|
-
const relative = path.relative(rootResolved, resolved);
|
|
3391
|
-
if (!relative || relative === "") return {
|
|
3392
|
-
resolved,
|
|
3393
|
-
relative: ""
|
|
3394
|
-
};
|
|
3395
|
-
if (relative.startsWith("..") || path.isAbsolute(relative)) throw new Error(`Path escapes sandbox root (${shortPath(rootResolved)}): ${params.filePath}`);
|
|
3396
|
-
return {
|
|
3397
|
-
resolved,
|
|
3398
|
-
relative
|
|
3399
|
-
};
|
|
3400
|
-
}
|
|
3401
|
-
async function assertSandboxPath(params) {
|
|
3402
|
-
const resolved = resolveSandboxPath(params);
|
|
3403
|
-
await assertNoSymlinkEscape(resolved.relative, path.resolve(params.root), { allowFinalSymlink: params.allowFinalSymlink });
|
|
3404
|
-
return resolved;
|
|
3405
|
-
}
|
|
3406
|
-
function assertMediaNotDataUrl(media) {
|
|
3407
|
-
const raw = media.trim();
|
|
3408
|
-
if (DATA_URL_RE.test(raw)) throw new Error("data: URLs are not supported for media. Use buffer instead.");
|
|
3409
|
-
}
|
|
3410
|
-
async function resolveSandboxedMediaSource(params) {
|
|
3411
|
-
const raw = params.media.trim();
|
|
3412
|
-
if (!raw) return raw;
|
|
3413
|
-
if (HTTP_URL_RE.test(raw)) return raw;
|
|
3414
|
-
let candidate = raw;
|
|
3415
|
-
if (/^file:\/\//i.test(candidate)) try {
|
|
3416
|
-
candidate = fileURLToPath(candidate);
|
|
3417
|
-
} catch {
|
|
3418
|
-
throw new Error(`Invalid file:// URL for sandboxed media: ${raw}`);
|
|
3419
|
-
}
|
|
3420
|
-
return (await assertSandboxPath({
|
|
3421
|
-
filePath: candidate,
|
|
3422
|
-
cwd: params.sandboxRoot,
|
|
3423
|
-
root: params.sandboxRoot
|
|
3424
|
-
})).resolved;
|
|
3425
|
-
}
|
|
3426
|
-
async function assertNoSymlinkEscape(relative, root, options) {
|
|
3427
|
-
if (!relative) return;
|
|
3428
|
-
const rootReal = await tryRealpath(root);
|
|
3429
|
-
const parts = relative.split(path.sep).filter(Boolean);
|
|
3430
|
-
let current = root;
|
|
3431
|
-
for (let idx = 0; idx < parts.length; idx += 1) {
|
|
3432
|
-
const part = parts[idx];
|
|
3433
|
-
const isLast = idx === parts.length - 1;
|
|
3434
|
-
current = path.join(current, part);
|
|
3435
|
-
try {
|
|
3436
|
-
if ((await fs.lstat(current)).isSymbolicLink()) {
|
|
3437
|
-
if (options?.allowFinalSymlink && isLast) return;
|
|
3438
|
-
const target = await tryRealpath(current);
|
|
3439
|
-
if (!isPathInside(rootReal, target)) throw new Error(`Symlink escapes sandbox root (${shortPath(rootReal)}): ${shortPath(current)}`);
|
|
3440
|
-
current = target;
|
|
3441
|
-
}
|
|
3442
|
-
} catch (err) {
|
|
3443
|
-
if (err.code === "ENOENT") return;
|
|
3444
|
-
throw err;
|
|
3445
|
-
}
|
|
3446
|
-
}
|
|
3447
|
-
}
|
|
3448
|
-
async function tryRealpath(value) {
|
|
3449
|
-
try {
|
|
3450
|
-
return await fs.realpath(value);
|
|
3451
|
-
} catch {
|
|
3452
|
-
return path.resolve(value);
|
|
3453
|
-
}
|
|
3454
|
-
}
|
|
3455
|
-
function isPathInside(root, target) {
|
|
3456
|
-
const relative = path.relative(root, target);
|
|
3457
|
-
if (!relative || relative === "") return true;
|
|
3458
|
-
return !(relative.startsWith("..") || path.isAbsolute(relative));
|
|
3459
|
-
}
|
|
3460
|
-
function shortPath(value) {
|
|
3461
|
-
if (value.startsWith(os.homedir())) return `~${value.slice(os.homedir().length)}`;
|
|
3462
|
-
return value;
|
|
3463
|
-
}
|
|
3464
|
-
|
|
3465
|
-
//#endregion
|
|
3466
|
-
//#region src/agents/skills/bundled-dir.ts
|
|
3467
|
-
function looksLikeSkillsDir(dir) {
|
|
3468
|
-
try {
|
|
3469
|
-
const entries = fs$1.readdirSync(dir, { withFileTypes: true });
|
|
3470
|
-
for (const entry of entries) {
|
|
3471
|
-
if (entry.name.startsWith(".")) continue;
|
|
3472
|
-
const fullPath = path.join(dir, entry.name);
|
|
3473
|
-
if (entry.isFile() && entry.name.endsWith(".md")) return true;
|
|
3474
|
-
if (entry.isDirectory()) {
|
|
3475
|
-
if (fs$1.existsSync(path.join(fullPath, "SKILL.md"))) return true;
|
|
3476
|
-
}
|
|
3477
|
-
}
|
|
3478
|
-
} catch {
|
|
3479
|
-
return false;
|
|
3480
|
-
}
|
|
3481
|
-
return false;
|
|
3482
|
-
}
|
|
3483
|
-
function resolveBundledSkillsDir(opts = {}) {
|
|
3484
|
-
const override = process.env.ANIMA_BUNDLED_SKILLS_DIR?.trim();
|
|
3485
|
-
if (override) return override;
|
|
3486
|
-
try {
|
|
3487
|
-
const execPath = opts.execPath ?? process.execPath;
|
|
3488
|
-
const execDir = path.dirname(execPath);
|
|
3489
|
-
const sibling = path.join(execDir, "skills");
|
|
3490
|
-
if (fs$1.existsSync(sibling)) return sibling;
|
|
3491
|
-
} catch {}
|
|
3492
|
-
try {
|
|
3493
|
-
const moduleUrl = opts.moduleUrl ?? import.meta.url;
|
|
3494
|
-
const moduleDir = path.dirname(fileURLToPath(moduleUrl));
|
|
3495
|
-
const packageRoot = resolveAnimaPackageRootSync({
|
|
3496
|
-
argv1: opts.argv1 ?? process.argv[1],
|
|
3497
|
-
moduleUrl,
|
|
3498
|
-
cwd: opts.cwd ?? process.cwd()
|
|
3499
|
-
});
|
|
3500
|
-
if (packageRoot) {
|
|
3501
|
-
const candidate = path.join(packageRoot, "skills");
|
|
3502
|
-
if (looksLikeSkillsDir(candidate)) return candidate;
|
|
3503
|
-
}
|
|
3504
|
-
let current = moduleDir;
|
|
3505
|
-
for (let depth = 0; depth < 6; depth += 1) {
|
|
3506
|
-
const candidate = path.join(current, "skills");
|
|
3507
|
-
if (looksLikeSkillsDir(candidate)) return candidate;
|
|
3508
|
-
const next = path.dirname(current);
|
|
3509
|
-
if (next === current) break;
|
|
3510
|
-
current = next;
|
|
3511
|
-
}
|
|
3512
|
-
} catch {}
|
|
3513
|
-
}
|
|
3514
|
-
|
|
3515
|
-
//#endregion
|
|
3516
|
-
//#region src/agents/skills/plugin-skills.ts
|
|
3517
|
-
const log$2 = createSubsystemLogger("skills");
|
|
3518
|
-
function resolvePluginSkillDirs(params) {
|
|
3519
|
-
const workspaceDir = params.workspaceDir.trim();
|
|
3520
|
-
if (!workspaceDir) return [];
|
|
3521
|
-
const registry = loadPluginManifestRegistry({
|
|
3522
|
-
workspaceDir,
|
|
3523
|
-
config: params.config
|
|
3524
|
-
});
|
|
3525
|
-
if (registry.plugins.length === 0) return [];
|
|
3526
|
-
const normalizedPlugins = normalizePluginsConfig(params.config?.plugins);
|
|
3527
|
-
const memorySlot = normalizedPlugins.slots.memory;
|
|
3528
|
-
let selectedMemoryPluginId = null;
|
|
3529
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3530
|
-
const resolved = [];
|
|
3531
|
-
for (const record of registry.plugins) {
|
|
3532
|
-
if (!record.skills || record.skills.length === 0) continue;
|
|
3533
|
-
if (!resolveEnableState(record.id, record.origin, normalizedPlugins).enabled) continue;
|
|
3534
|
-
const memoryDecision = resolveMemorySlotDecision({
|
|
3535
|
-
id: record.id,
|
|
3536
|
-
kind: record.kind,
|
|
3537
|
-
slot: memorySlot,
|
|
3538
|
-
selectedId: selectedMemoryPluginId
|
|
3539
|
-
});
|
|
3540
|
-
if (!memoryDecision.enabled) continue;
|
|
3541
|
-
if (memoryDecision.selected && record.kind === "memory") selectedMemoryPluginId = record.id;
|
|
3542
|
-
for (const raw of record.skills) {
|
|
3543
|
-
const trimmed = raw.trim();
|
|
3544
|
-
if (!trimmed) continue;
|
|
3545
|
-
const candidate = path.resolve(record.rootDir, trimmed);
|
|
3546
|
-
if (!fs$1.existsSync(candidate)) {
|
|
3547
|
-
log$2.warn(`plugin skill path not found (${record.id}): ${candidate}`);
|
|
3548
|
-
continue;
|
|
3549
|
-
}
|
|
3550
|
-
if (seen.has(candidate)) continue;
|
|
3551
|
-
seen.add(candidate);
|
|
3552
|
-
resolved.push(candidate);
|
|
3553
|
-
}
|
|
3554
|
-
}
|
|
3555
|
-
return resolved;
|
|
3556
|
-
}
|
|
3557
|
-
|
|
3558
|
-
//#endregion
|
|
3559
|
-
//#region src/agents/skills/serialize.ts
|
|
3560
|
-
const SKILLS_SYNC_QUEUE = /* @__PURE__ */ new Map();
|
|
3561
|
-
async function serializeByKey(key, task) {
|
|
3562
|
-
const next = (SKILLS_SYNC_QUEUE.get(key) ?? Promise.resolve()).then(task, task);
|
|
3563
|
-
SKILLS_SYNC_QUEUE.set(key, next);
|
|
3564
|
-
try {
|
|
3565
|
-
return await next;
|
|
3566
|
-
} finally {
|
|
3567
|
-
if (SKILLS_SYNC_QUEUE.get(key) === next) SKILLS_SYNC_QUEUE.delete(key);
|
|
3568
|
-
}
|
|
3569
|
-
}
|
|
3570
|
-
|
|
3571
|
-
//#endregion
|
|
3572
|
-
//#region src/agents/skills/workspace.ts
|
|
3573
|
-
const fsp = fs$1.promises;
|
|
3574
|
-
const skillsLogger = createSubsystemLogger("skills");
|
|
3575
|
-
const skillCommandDebugOnce = /* @__PURE__ */ new Set();
|
|
3576
|
-
function debugSkillCommandOnce(messageKey, message, meta) {
|
|
3577
|
-
if (skillCommandDebugOnce.has(messageKey)) return;
|
|
3578
|
-
skillCommandDebugOnce.add(messageKey);
|
|
3579
|
-
skillsLogger.debug(message, meta);
|
|
3580
|
-
}
|
|
3581
|
-
function filterSkillEntries(entries, config, skillFilter, eligibility) {
|
|
3582
|
-
let filtered = entries.filter((entry) => shouldIncludeSkill({
|
|
3583
|
-
entry,
|
|
3584
|
-
config,
|
|
3585
|
-
eligibility
|
|
3586
|
-
}));
|
|
3587
|
-
if (skillFilter !== void 0) {
|
|
3588
|
-
const normalized = skillFilter.map((entry) => String(entry).trim()).filter(Boolean);
|
|
3589
|
-
const label = normalized.length > 0 ? normalized.join(", ") : "(none)";
|
|
3590
|
-
console.log(`[skills] Applying skill filter: ${label}`);
|
|
3591
|
-
filtered = normalized.length > 0 ? filtered.filter((entry) => normalized.includes(entry.skill.name)) : [];
|
|
3592
|
-
console.log(`[skills] After filter: ${filtered.map((entry) => entry.skill.name).join(", ")}`);
|
|
3593
|
-
}
|
|
3594
|
-
return filtered;
|
|
3595
|
-
}
|
|
3596
|
-
const SKILL_COMMAND_MAX_LENGTH = 32;
|
|
3597
|
-
const SKILL_COMMAND_FALLBACK = "skill";
|
|
3598
|
-
const SKILL_COMMAND_DESCRIPTION_MAX_LENGTH = 100;
|
|
3599
|
-
function sanitizeSkillCommandName(raw) {
|
|
3600
|
-
return raw.toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").slice(0, SKILL_COMMAND_MAX_LENGTH) || SKILL_COMMAND_FALLBACK;
|
|
3601
|
-
}
|
|
3602
|
-
function resolveUniqueSkillCommandName(base, used) {
|
|
3603
|
-
const normalizedBase = base.toLowerCase();
|
|
3604
|
-
if (!used.has(normalizedBase)) return base;
|
|
3605
|
-
for (let index = 2; index < 1e3; index += 1) {
|
|
3606
|
-
const suffix = `_${index}`;
|
|
3607
|
-
const maxBaseLength = Math.max(1, SKILL_COMMAND_MAX_LENGTH - suffix.length);
|
|
3608
|
-
const candidate = `${base.slice(0, maxBaseLength)}${suffix}`;
|
|
3609
|
-
const candidateKey = candidate.toLowerCase();
|
|
3610
|
-
if (!used.has(candidateKey)) return candidate;
|
|
3611
|
-
}
|
|
3612
|
-
return `${base.slice(0, Math.max(1, SKILL_COMMAND_MAX_LENGTH - 2))}_x`;
|
|
3613
|
-
}
|
|
3614
|
-
function loadSkillEntries(workspaceDir, opts) {
|
|
3615
|
-
const loadSkills = (params) => {
|
|
3616
|
-
const loaded = loadSkillsFromDir(params);
|
|
3617
|
-
if (Array.isArray(loaded)) return loaded;
|
|
3618
|
-
if (loaded && typeof loaded === "object" && "skills" in loaded && Array.isArray(loaded.skills)) return loaded.skills;
|
|
3619
|
-
return [];
|
|
3620
|
-
};
|
|
3621
|
-
const managedSkillsDir = opts?.managedSkillsDir ?? path.join(CONFIG_DIR, "skills");
|
|
3622
|
-
const workspaceSkillsDir = path.resolve(workspaceDir, "skills");
|
|
3623
|
-
const bundledSkillsDir = opts?.bundledSkillsDir ?? resolveBundledSkillsDir();
|
|
3624
|
-
const extraDirs = (opts?.config?.skills?.load?.extraDirs ?? []).map((d) => typeof d === "string" ? d.trim() : "").filter(Boolean);
|
|
3625
|
-
const pluginSkillDirs = resolvePluginSkillDirs({
|
|
3626
|
-
workspaceDir,
|
|
3627
|
-
config: opts?.config
|
|
3628
|
-
});
|
|
3629
|
-
const mergedExtraDirs = [...extraDirs, ...pluginSkillDirs];
|
|
3630
|
-
const bundledSkills = bundledSkillsDir ? loadSkills({
|
|
3631
|
-
dir: bundledSkillsDir,
|
|
3632
|
-
source: "anima-bundled"
|
|
3633
|
-
}) : [];
|
|
3634
|
-
const extraSkills = mergedExtraDirs.flatMap((dir) => {
|
|
3635
|
-
return loadSkills({
|
|
3636
|
-
dir: resolveUserPath(dir),
|
|
3637
|
-
source: "anima-extra"
|
|
3638
|
-
});
|
|
3639
|
-
});
|
|
3640
|
-
const managedSkills = loadSkills({
|
|
3641
|
-
dir: managedSkillsDir,
|
|
3642
|
-
source: "anima-managed"
|
|
3643
|
-
});
|
|
3644
|
-
const personalAgentsSkills = loadSkills({
|
|
3645
|
-
dir: path.resolve(os.homedir(), ".agents", "skills"),
|
|
3646
|
-
source: "agents-skills-personal"
|
|
3647
|
-
});
|
|
3648
|
-
const projectAgentsSkills = loadSkills({
|
|
3649
|
-
dir: path.resolve(workspaceDir, ".agents", "skills"),
|
|
3650
|
-
source: "agents-skills-project"
|
|
3651
|
-
});
|
|
3652
|
-
const workspaceSkills = loadSkills({
|
|
3653
|
-
dir: workspaceSkillsDir,
|
|
3654
|
-
source: "anima-workspace"
|
|
3655
|
-
});
|
|
3656
|
-
const merged = /* @__PURE__ */ new Map();
|
|
3657
|
-
for (const skill of extraSkills) merged.set(skill.name, skill);
|
|
3658
|
-
for (const skill of bundledSkills) merged.set(skill.name, skill);
|
|
3659
|
-
for (const skill of managedSkills) merged.set(skill.name, skill);
|
|
3660
|
-
for (const skill of personalAgentsSkills) merged.set(skill.name, skill);
|
|
3661
|
-
for (const skill of projectAgentsSkills) merged.set(skill.name, skill);
|
|
3662
|
-
for (const skill of workspaceSkills) merged.set(skill.name, skill);
|
|
3663
|
-
return Array.from(merged.values()).map((skill) => {
|
|
3664
|
-
let frontmatter = {};
|
|
3665
|
-
try {
|
|
3666
|
-
frontmatter = parseFrontmatter(fs$1.readFileSync(skill.filePath, "utf-8"));
|
|
3667
|
-
} catch {}
|
|
3668
|
-
return {
|
|
3669
|
-
skill,
|
|
3670
|
-
frontmatter,
|
|
3671
|
-
metadata: resolveAnimaMetadata(frontmatter),
|
|
3672
|
-
invocation: resolveSkillInvocationPolicy(frontmatter)
|
|
3673
|
-
};
|
|
3674
|
-
});
|
|
3675
|
-
}
|
|
3676
|
-
function buildWorkspaceSkillSnapshot(workspaceDir, opts) {
|
|
3677
|
-
const eligible = filterSkillEntries(opts?.entries ?? loadSkillEntries(workspaceDir, opts), opts?.config, opts?.skillFilter, opts?.eligibility);
|
|
3678
|
-
const resolvedSkills = eligible.filter((entry) => entry.invocation?.disableModelInvocation !== true).map((entry) => entry.skill);
|
|
3679
|
-
return {
|
|
3680
|
-
prompt: [opts?.eligibility?.remote?.note?.trim(), formatSkillsForPrompt(resolvedSkills)].filter(Boolean).join("\n"),
|
|
3681
|
-
skills: eligible.map((entry) => ({
|
|
3682
|
-
name: entry.skill.name,
|
|
3683
|
-
primaryEnv: entry.metadata?.primaryEnv
|
|
3684
|
-
})),
|
|
3685
|
-
resolvedSkills,
|
|
3686
|
-
version: opts?.snapshotVersion
|
|
3687
|
-
};
|
|
3688
|
-
}
|
|
3689
|
-
function resolveUniqueSyncedSkillDirName(base, used) {
|
|
3690
|
-
if (!used.has(base)) {
|
|
3691
|
-
used.add(base);
|
|
3692
|
-
return base;
|
|
3693
|
-
}
|
|
3694
|
-
for (let index = 2; index < 1e4; index += 1) {
|
|
3695
|
-
const candidate = `${base}-${index}`;
|
|
3696
|
-
if (!used.has(candidate)) {
|
|
3697
|
-
used.add(candidate);
|
|
3698
|
-
return candidate;
|
|
3699
|
-
}
|
|
3700
|
-
}
|
|
3701
|
-
let fallbackIndex = 1e4;
|
|
3702
|
-
let fallback = `${base}-${fallbackIndex}`;
|
|
3703
|
-
while (used.has(fallback)) {
|
|
3704
|
-
fallbackIndex += 1;
|
|
3705
|
-
fallback = `${base}-${fallbackIndex}`;
|
|
3706
|
-
}
|
|
3707
|
-
used.add(fallback);
|
|
3708
|
-
return fallback;
|
|
3709
|
-
}
|
|
3710
|
-
function resolveSyncedSkillDestinationPath(params) {
|
|
3711
|
-
const sourceDirName = path.basename(params.entry.skill.baseDir).trim();
|
|
3712
|
-
if (!sourceDirName || sourceDirName === "." || sourceDirName === "..") return null;
|
|
3713
|
-
return resolveSandboxPath({
|
|
3714
|
-
filePath: resolveUniqueSyncedSkillDirName(sourceDirName, params.usedDirNames),
|
|
3715
|
-
cwd: params.targetSkillsDir,
|
|
3716
|
-
root: params.targetSkillsDir
|
|
3717
|
-
}).resolved;
|
|
3718
|
-
}
|
|
3719
|
-
async function syncSkillsToWorkspace(params) {
|
|
3720
|
-
const sourceDir = resolveUserPath(params.sourceWorkspaceDir);
|
|
3721
|
-
const targetDir = resolveUserPath(params.targetWorkspaceDir);
|
|
3722
|
-
if (sourceDir === targetDir) return;
|
|
3723
|
-
await serializeByKey(`syncSkills:${targetDir}`, async () => {
|
|
3724
|
-
const targetSkillsDir = path.join(targetDir, "skills");
|
|
3725
|
-
const entries = loadSkillEntries(sourceDir, {
|
|
3726
|
-
config: params.config,
|
|
3727
|
-
managedSkillsDir: params.managedSkillsDir,
|
|
3728
|
-
bundledSkillsDir: params.bundledSkillsDir
|
|
3729
|
-
});
|
|
3730
|
-
await fsp.rm(targetSkillsDir, {
|
|
3731
|
-
recursive: true,
|
|
3732
|
-
force: true
|
|
3733
|
-
});
|
|
3734
|
-
await fsp.mkdir(targetSkillsDir, { recursive: true });
|
|
3735
|
-
const usedDirNames = /* @__PURE__ */ new Set();
|
|
3736
|
-
for (const entry of entries) {
|
|
3737
|
-
let dest = null;
|
|
3738
|
-
try {
|
|
3739
|
-
dest = resolveSyncedSkillDestinationPath({
|
|
3740
|
-
targetSkillsDir,
|
|
3741
|
-
entry,
|
|
3742
|
-
usedDirNames
|
|
3743
|
-
});
|
|
3744
|
-
} catch (error) {
|
|
3745
|
-
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
|
3746
|
-
console.warn(`[skills] Failed to resolve safe destination for ${entry.skill.name}: ${message}`);
|
|
3747
|
-
continue;
|
|
3748
|
-
}
|
|
3749
|
-
if (!dest) {
|
|
3750
|
-
console.warn(`[skills] Failed to resolve safe destination for ${entry.skill.name}: invalid source directory name`);
|
|
3751
|
-
continue;
|
|
3752
|
-
}
|
|
3753
|
-
try {
|
|
3754
|
-
await fsp.cp(entry.skill.baseDir, dest, {
|
|
3755
|
-
recursive: true,
|
|
3756
|
-
force: true
|
|
3757
|
-
});
|
|
3758
|
-
} catch (error) {
|
|
3759
|
-
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
|
3760
|
-
console.warn(`[skills] Failed to copy ${entry.skill.name} to sandbox: ${message}`);
|
|
3761
|
-
}
|
|
3762
|
-
}
|
|
3763
|
-
});
|
|
3764
|
-
}
|
|
3765
|
-
function buildWorkspaceSkillCommandSpecs(workspaceDir, opts) {
|
|
3766
|
-
const userInvocable = filterSkillEntries(opts?.entries ?? loadSkillEntries(workspaceDir, opts), opts?.config, opts?.skillFilter, opts?.eligibility).filter((entry) => entry.invocation?.userInvocable !== false);
|
|
3767
|
-
const used = /* @__PURE__ */ new Set();
|
|
3768
|
-
for (const reserved of opts?.reservedNames ?? []) used.add(reserved.toLowerCase());
|
|
3769
|
-
const specs = [];
|
|
3770
|
-
for (const entry of userInvocable) {
|
|
3771
|
-
const rawName = entry.skill.name;
|
|
3772
|
-
const base = sanitizeSkillCommandName(rawName);
|
|
3773
|
-
if (base !== rawName) debugSkillCommandOnce(`sanitize:${rawName}:${base}`, `Sanitized skill command name "${rawName}" to "/${base}".`, {
|
|
3774
|
-
rawName,
|
|
3775
|
-
sanitized: `/${base}`
|
|
3776
|
-
});
|
|
3777
|
-
const unique = resolveUniqueSkillCommandName(base, used);
|
|
3778
|
-
if (unique !== base) debugSkillCommandOnce(`dedupe:${rawName}:${unique}`, `De-duplicated skill command name for "${rawName}" to "/${unique}".`, {
|
|
3779
|
-
rawName,
|
|
3780
|
-
deduped: `/${unique}`
|
|
3781
|
-
});
|
|
3782
|
-
used.add(unique.toLowerCase());
|
|
3783
|
-
const rawDescription = entry.skill.description?.trim() || rawName;
|
|
3784
|
-
const description = rawDescription.length > SKILL_COMMAND_DESCRIPTION_MAX_LENGTH ? rawDescription.slice(0, SKILL_COMMAND_DESCRIPTION_MAX_LENGTH - 1) + "…" : rawDescription;
|
|
3785
|
-
const dispatch = (() => {
|
|
3786
|
-
const kindRaw = (entry.frontmatter?.["command-dispatch"] ?? entry.frontmatter?.["command_dispatch"] ?? "").trim().toLowerCase();
|
|
3787
|
-
if (!kindRaw) return;
|
|
3788
|
-
if (kindRaw !== "tool") return;
|
|
3789
|
-
const toolName = (entry.frontmatter?.["command-tool"] ?? entry.frontmatter?.["command_tool"] ?? "").trim();
|
|
3790
|
-
if (!toolName) {
|
|
3791
|
-
debugSkillCommandOnce(`dispatch:missingTool:${rawName}`, `Skill command "/${unique}" requested tool dispatch but did not provide command-tool. Ignoring dispatch.`, {
|
|
3792
|
-
skillName: rawName,
|
|
3793
|
-
command: unique
|
|
3794
|
-
});
|
|
3795
|
-
return;
|
|
3796
|
-
}
|
|
3797
|
-
const argModeRaw = (entry.frontmatter?.["command-arg-mode"] ?? entry.frontmatter?.["command_arg_mode"] ?? "").trim().toLowerCase();
|
|
3798
|
-
if (!(!argModeRaw || argModeRaw === "raw" ? "raw" : null)) debugSkillCommandOnce(`dispatch:badArgMode:${rawName}:${argModeRaw}`, `Skill command "/${unique}" requested tool dispatch but has unknown command-arg-mode. Falling back to raw.`, {
|
|
3799
|
-
skillName: rawName,
|
|
3800
|
-
command: unique,
|
|
3801
|
-
argMode: argModeRaw
|
|
3802
|
-
});
|
|
3803
|
-
return {
|
|
3804
|
-
kind: "tool",
|
|
3805
|
-
toolName,
|
|
3806
|
-
argMode: "raw"
|
|
3807
|
-
};
|
|
3808
|
-
})();
|
|
3809
|
-
specs.push({
|
|
3810
|
-
name: unique,
|
|
3811
|
-
skillName: rawName,
|
|
3812
|
-
description,
|
|
3813
|
-
...dispatch ? { dispatch } : {}
|
|
3814
|
-
});
|
|
3815
|
-
}
|
|
3816
|
-
return specs;
|
|
3817
|
-
}
|
|
3818
|
-
|
|
3819
|
-
//#endregion
|
|
3820
|
-
//#region src/agents/skills/refresh.ts
|
|
3821
|
-
const log$1 = createSubsystemLogger("gateway/skills");
|
|
3822
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
3823
|
-
const workspaceVersions = /* @__PURE__ */ new Map();
|
|
3824
|
-
const watchers = /* @__PURE__ */ new Map();
|
|
3825
|
-
let globalVersion = 0;
|
|
3826
|
-
const DEFAULT_SKILLS_WATCH_IGNORED = [
|
|
3827
|
-
/(^|[\\/])\.git([\\/]|$)/,
|
|
3828
|
-
/(^|[\\/])node_modules([\\/]|$)/,
|
|
3829
|
-
/(^|[\\/])dist([\\/]|$)/,
|
|
3830
|
-
/(^|[\\/])\.venv([\\/]|$)/,
|
|
3831
|
-
/(^|[\\/])venv([\\/]|$)/,
|
|
3832
|
-
/(^|[\\/])__pycache__([\\/]|$)/,
|
|
3833
|
-
/(^|[\\/])\.mypy_cache([\\/]|$)/,
|
|
3834
|
-
/(^|[\\/])\.pytest_cache([\\/]|$)/,
|
|
3835
|
-
/(^|[\\/])build([\\/]|$)/,
|
|
3836
|
-
/(^|[\\/])\.cache([\\/]|$)/
|
|
3837
|
-
];
|
|
3838
|
-
function bumpVersion(current) {
|
|
3839
|
-
const now = Date.now();
|
|
3840
|
-
return now <= current ? current + 1 : now;
|
|
3841
|
-
}
|
|
3842
|
-
function emit(event) {
|
|
3843
|
-
for (const listener of listeners) try {
|
|
3844
|
-
listener(event);
|
|
3845
|
-
} catch (err) {
|
|
3846
|
-
log$1.warn(`skills change listener failed: ${String(err)}`);
|
|
3847
|
-
}
|
|
3848
|
-
}
|
|
3849
|
-
function resolveWatchPaths(workspaceDir, config) {
|
|
3850
|
-
const paths = [];
|
|
3851
|
-
if (workspaceDir.trim()) {
|
|
3852
|
-
paths.push(path.join(workspaceDir, "skills"));
|
|
3853
|
-
paths.push(path.join(workspaceDir, ".agents", "skills"));
|
|
3854
|
-
}
|
|
3855
|
-
paths.push(path.join(CONFIG_DIR, "skills"));
|
|
3856
|
-
paths.push(path.join(os.homedir(), ".agents", "skills"));
|
|
3857
|
-
const extraDirs = (config?.skills?.load?.extraDirs ?? []).map((d) => typeof d === "string" ? d.trim() : "").filter(Boolean).map((dir) => resolveUserPath(dir));
|
|
3858
|
-
paths.push(...extraDirs);
|
|
3859
|
-
const pluginSkillDirs = resolvePluginSkillDirs({
|
|
3860
|
-
workspaceDir,
|
|
3861
|
-
config
|
|
3862
|
-
});
|
|
3863
|
-
paths.push(...pluginSkillDirs);
|
|
3864
|
-
return paths;
|
|
3865
|
-
}
|
|
3866
|
-
function toWatchGlobRoot(raw) {
|
|
3867
|
-
return raw.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
3868
|
-
}
|
|
3869
|
-
function resolveWatchTargets(workspaceDir, config) {
|
|
3870
|
-
const targets = /* @__PURE__ */ new Set();
|
|
3871
|
-
for (const root of resolveWatchPaths(workspaceDir, config)) {
|
|
3872
|
-
const globRoot = toWatchGlobRoot(root);
|
|
3873
|
-
targets.add(`${globRoot}/SKILL.md`);
|
|
3874
|
-
targets.add(`${globRoot}/*/SKILL.md`);
|
|
3875
|
-
}
|
|
3876
|
-
return Array.from(targets).toSorted();
|
|
3877
|
-
}
|
|
3878
|
-
function bumpSkillsSnapshotVersion(params) {
|
|
3879
|
-
const reason = params?.reason ?? "manual";
|
|
3880
|
-
const changedPath = params?.changedPath;
|
|
3881
|
-
if (params?.workspaceDir) {
|
|
3882
|
-
const next = bumpVersion(workspaceVersions.get(params.workspaceDir) ?? 0);
|
|
3883
|
-
workspaceVersions.set(params.workspaceDir, next);
|
|
3884
|
-
emit({
|
|
3885
|
-
workspaceDir: params.workspaceDir,
|
|
3886
|
-
reason,
|
|
3887
|
-
changedPath
|
|
3888
|
-
});
|
|
3889
|
-
return next;
|
|
3890
|
-
}
|
|
3891
|
-
globalVersion = bumpVersion(globalVersion);
|
|
3892
|
-
emit({
|
|
3893
|
-
reason,
|
|
3894
|
-
changedPath
|
|
3895
|
-
});
|
|
3896
|
-
return globalVersion;
|
|
3897
|
-
}
|
|
3898
|
-
function getSkillsSnapshotVersion(workspaceDir) {
|
|
3899
|
-
if (!workspaceDir) return globalVersion;
|
|
3900
|
-
const local = workspaceVersions.get(workspaceDir) ?? 0;
|
|
3901
|
-
return Math.max(globalVersion, local);
|
|
3902
|
-
}
|
|
3903
|
-
function ensureSkillsWatcher(params) {
|
|
3904
|
-
const workspaceDir = params.workspaceDir.trim();
|
|
3905
|
-
if (!workspaceDir) return;
|
|
3906
|
-
const watchEnabled = params.config?.skills?.load?.watch !== false;
|
|
3907
|
-
const debounceMsRaw = params.config?.skills?.load?.watchDebounceMs;
|
|
3908
|
-
const debounceMs = typeof debounceMsRaw === "number" && Number.isFinite(debounceMsRaw) ? Math.max(0, debounceMsRaw) : 250;
|
|
3909
|
-
const existing = watchers.get(workspaceDir);
|
|
3910
|
-
if (!watchEnabled) {
|
|
3911
|
-
if (existing) {
|
|
3912
|
-
watchers.delete(workspaceDir);
|
|
3913
|
-
if (existing.timer) clearTimeout(existing.timer);
|
|
3914
|
-
existing.watcher.close().catch(() => {});
|
|
3915
|
-
}
|
|
3916
|
-
return;
|
|
3917
|
-
}
|
|
3918
|
-
const watchTargets = resolveWatchTargets(workspaceDir, params.config);
|
|
3919
|
-
const pathsKey = watchTargets.join("|");
|
|
3920
|
-
if (existing && existing.pathsKey === pathsKey && existing.debounceMs === debounceMs) return;
|
|
3921
|
-
if (existing) {
|
|
3922
|
-
watchers.delete(workspaceDir);
|
|
3923
|
-
if (existing.timer) clearTimeout(existing.timer);
|
|
3924
|
-
existing.watcher.close().catch(() => {});
|
|
3925
|
-
}
|
|
3926
|
-
const watcher = chokidar.watch(watchTargets, {
|
|
3927
|
-
ignoreInitial: true,
|
|
3928
|
-
awaitWriteFinish: {
|
|
3929
|
-
stabilityThreshold: debounceMs,
|
|
3930
|
-
pollInterval: 100
|
|
3931
|
-
},
|
|
3932
|
-
ignored: DEFAULT_SKILLS_WATCH_IGNORED
|
|
3933
|
-
});
|
|
3934
|
-
const state = {
|
|
3935
|
-
watcher,
|
|
3936
|
-
pathsKey,
|
|
3937
|
-
debounceMs
|
|
3938
|
-
};
|
|
3939
|
-
const schedule = (changedPath) => {
|
|
3940
|
-
state.pendingPath = changedPath ?? state.pendingPath;
|
|
3941
|
-
if (state.timer) clearTimeout(state.timer);
|
|
3942
|
-
state.timer = setTimeout(() => {
|
|
3943
|
-
const pendingPath = state.pendingPath;
|
|
3944
|
-
state.pendingPath = void 0;
|
|
3945
|
-
state.timer = void 0;
|
|
3946
|
-
bumpSkillsSnapshotVersion({
|
|
3947
|
-
workspaceDir,
|
|
3948
|
-
reason: "watch",
|
|
3949
|
-
changedPath: pendingPath
|
|
3950
|
-
});
|
|
3951
|
-
}, debounceMs);
|
|
3952
|
-
};
|
|
3953
|
-
watcher.on("add", (p) => schedule(p));
|
|
3954
|
-
watcher.on("change", (p) => schedule(p));
|
|
3955
|
-
watcher.on("unlink", (p) => schedule(p));
|
|
3956
|
-
watcher.on("error", (err) => {
|
|
3957
|
-
log$1.warn(`skills watcher error (${workspaceDir}): ${String(err)}`);
|
|
3958
|
-
});
|
|
3959
|
-
watchers.set(workspaceDir, state);
|
|
3960
|
-
}
|
|
3961
|
-
|
|
3962
|
-
//#endregion
|
|
3963
|
-
//#region src/auto-reply/thinking.ts
|
|
3964
|
-
function normalizeProviderId(provider) {
|
|
3965
|
-
if (!provider) return "";
|
|
3966
|
-
const normalized = provider.trim().toLowerCase();
|
|
3967
|
-
if (normalized === "z.ai" || normalized === "z-ai") return "zai";
|
|
3968
|
-
return normalized;
|
|
3969
|
-
}
|
|
3970
|
-
function isBinaryThinkingProvider(provider) {
|
|
3971
|
-
return normalizeProviderId(provider) === "zai";
|
|
3972
|
-
}
|
|
3973
|
-
const XHIGH_MODEL_REFS = [
|
|
3974
|
-
"openai/gpt-5.2",
|
|
3975
|
-
"openai-codex/gpt-5.3-codex",
|
|
3976
|
-
"openai-codex/gpt-5.3-codex-spark",
|
|
3977
|
-
"openai-codex/gpt-5.2-codex",
|
|
3978
|
-
"openai-codex/gpt-5.1-codex",
|
|
3979
|
-
"github-copilot/gpt-5.2-codex",
|
|
3980
|
-
"github-copilot/gpt-5.2"
|
|
3981
|
-
];
|
|
3982
|
-
const XHIGH_MODEL_SET = new Set(XHIGH_MODEL_REFS.map((entry) => entry.toLowerCase()));
|
|
3983
|
-
const XHIGH_MODEL_IDS = new Set(XHIGH_MODEL_REFS.map((entry) => entry.split("/")[1]?.toLowerCase()).filter((entry) => Boolean(entry)));
|
|
3984
|
-
function normalizeThinkLevel(raw) {
|
|
3985
|
-
if (!raw) return;
|
|
3986
|
-
const key = raw.trim().toLowerCase();
|
|
3987
|
-
const collapsed = key.replace(/[\s_-]+/g, "");
|
|
3988
|
-
if (collapsed === "xhigh" || collapsed === "extrahigh") return "xhigh";
|
|
3989
|
-
if (["off"].includes(key)) return "off";
|
|
3990
|
-
if ([
|
|
3991
|
-
"on",
|
|
3992
|
-
"enable",
|
|
3993
|
-
"enabled"
|
|
3994
|
-
].includes(key)) return "low";
|
|
3995
|
-
if (["min", "minimal"].includes(key)) return "minimal";
|
|
3996
|
-
if ([
|
|
3997
|
-
"low",
|
|
3998
|
-
"thinkhard",
|
|
3999
|
-
"think-hard",
|
|
4000
|
-
"think_hard"
|
|
4001
|
-
].includes(key)) return "low";
|
|
4002
|
-
if ([
|
|
4003
|
-
"mid",
|
|
4004
|
-
"med",
|
|
4005
|
-
"medium",
|
|
4006
|
-
"thinkharder",
|
|
4007
|
-
"think-harder",
|
|
4008
|
-
"harder"
|
|
4009
|
-
].includes(key)) return "medium";
|
|
4010
|
-
if ([
|
|
4011
|
-
"high",
|
|
4012
|
-
"ultra",
|
|
4013
|
-
"ultrathink",
|
|
4014
|
-
"think-hard",
|
|
4015
|
-
"thinkhardest",
|
|
4016
|
-
"highest",
|
|
4017
|
-
"max"
|
|
4018
|
-
].includes(key)) return "high";
|
|
4019
|
-
if (["think"].includes(key)) return "minimal";
|
|
4020
|
-
}
|
|
4021
|
-
function supportsXHighThinking(provider, model) {
|
|
4022
|
-
const modelKey = model?.trim().toLowerCase();
|
|
4023
|
-
if (!modelKey) return false;
|
|
4024
|
-
const providerKey = provider?.trim().toLowerCase();
|
|
4025
|
-
if (providerKey) return XHIGH_MODEL_SET.has(`${providerKey}/${modelKey}`);
|
|
4026
|
-
return XHIGH_MODEL_IDS.has(modelKey);
|
|
4027
|
-
}
|
|
4028
|
-
function listThinkingLevels(provider, model) {
|
|
4029
|
-
const levels = [
|
|
4030
|
-
"off",
|
|
4031
|
-
"minimal",
|
|
4032
|
-
"low",
|
|
4033
|
-
"medium",
|
|
4034
|
-
"high"
|
|
4035
|
-
];
|
|
4036
|
-
if (supportsXHighThinking(provider, model)) levels.push("xhigh");
|
|
4037
|
-
return levels;
|
|
4038
|
-
}
|
|
4039
|
-
function listThinkingLevelLabels(provider, model) {
|
|
4040
|
-
if (isBinaryThinkingProvider(provider)) return ["off", "on"];
|
|
4041
|
-
return listThinkingLevels(provider, model);
|
|
4042
|
-
}
|
|
4043
|
-
function formatThinkingLevels(provider, model, separator = ", ") {
|
|
4044
|
-
return listThinkingLevelLabels(provider, model).join(separator);
|
|
4045
|
-
}
|
|
4046
|
-
function formatXHighModelHint() {
|
|
4047
|
-
const refs = [...XHIGH_MODEL_REFS];
|
|
4048
|
-
if (refs.length === 0) return "unknown model";
|
|
4049
|
-
if (refs.length === 1) return refs[0];
|
|
4050
|
-
if (refs.length === 2) return `${refs[0]} or ${refs[1]}`;
|
|
4051
|
-
return `${refs.slice(0, -1).join(", ")} or ${refs[refs.length - 1]}`;
|
|
4052
|
-
}
|
|
4053
|
-
function normalizeVerboseLevel(raw) {
|
|
4054
|
-
if (!raw) return;
|
|
4055
|
-
const key = raw.toLowerCase();
|
|
4056
|
-
if ([
|
|
4057
|
-
"off",
|
|
4058
|
-
"false",
|
|
4059
|
-
"no",
|
|
4060
|
-
"0"
|
|
4061
|
-
].includes(key)) return "off";
|
|
4062
|
-
if ([
|
|
4063
|
-
"full",
|
|
4064
|
-
"all",
|
|
4065
|
-
"everything"
|
|
4066
|
-
].includes(key)) return "full";
|
|
4067
|
-
if ([
|
|
4068
|
-
"on",
|
|
4069
|
-
"minimal",
|
|
4070
|
-
"true",
|
|
4071
|
-
"yes",
|
|
4072
|
-
"1"
|
|
4073
|
-
].includes(key)) return "on";
|
|
4074
|
-
}
|
|
4075
|
-
function normalizeUsageDisplay(raw) {
|
|
4076
|
-
if (!raw) return;
|
|
4077
|
-
const key = raw.toLowerCase();
|
|
4078
|
-
if ([
|
|
4079
|
-
"off",
|
|
4080
|
-
"false",
|
|
4081
|
-
"no",
|
|
4082
|
-
"0",
|
|
4083
|
-
"disable",
|
|
4084
|
-
"disabled"
|
|
4085
|
-
].includes(key)) return "off";
|
|
4086
|
-
if ([
|
|
4087
|
-
"on",
|
|
4088
|
-
"true",
|
|
4089
|
-
"yes",
|
|
4090
|
-
"1",
|
|
4091
|
-
"enable",
|
|
4092
|
-
"enabled"
|
|
4093
|
-
].includes(key)) return "tokens";
|
|
4094
|
-
if ([
|
|
4095
|
-
"tokens",
|
|
4096
|
-
"token",
|
|
4097
|
-
"tok",
|
|
4098
|
-
"minimal",
|
|
4099
|
-
"min"
|
|
4100
|
-
].includes(key)) return "tokens";
|
|
4101
|
-
if (["full", "session"].includes(key)) return "full";
|
|
4102
|
-
}
|
|
4103
|
-
function resolveResponseUsageMode(raw) {
|
|
4104
|
-
return normalizeUsageDisplay(raw) ?? "off";
|
|
4105
|
-
}
|
|
4106
|
-
function normalizeElevatedLevel(raw) {
|
|
4107
|
-
if (!raw) return;
|
|
4108
|
-
const key = raw.toLowerCase();
|
|
4109
|
-
if ([
|
|
4110
|
-
"off",
|
|
4111
|
-
"false",
|
|
4112
|
-
"no",
|
|
4113
|
-
"0"
|
|
4114
|
-
].includes(key)) return "off";
|
|
4115
|
-
if ([
|
|
4116
|
-
"full",
|
|
4117
|
-
"auto",
|
|
4118
|
-
"auto-approve",
|
|
4119
|
-
"autoapprove"
|
|
4120
|
-
].includes(key)) return "full";
|
|
4121
|
-
if ([
|
|
4122
|
-
"ask",
|
|
4123
|
-
"prompt",
|
|
4124
|
-
"approval",
|
|
4125
|
-
"approve"
|
|
4126
|
-
].includes(key)) return "ask";
|
|
4127
|
-
if ([
|
|
4128
|
-
"on",
|
|
4129
|
-
"true",
|
|
4130
|
-
"yes",
|
|
4131
|
-
"1"
|
|
4132
|
-
].includes(key)) return "on";
|
|
4133
|
-
}
|
|
4134
|
-
function normalizeReasoningLevel(raw) {
|
|
4135
|
-
if (!raw) return;
|
|
4136
|
-
const key = raw.toLowerCase();
|
|
4137
|
-
if ([
|
|
4138
|
-
"off",
|
|
4139
|
-
"false",
|
|
4140
|
-
"no",
|
|
4141
|
-
"0",
|
|
4142
|
-
"hide",
|
|
4143
|
-
"hidden",
|
|
4144
|
-
"disable",
|
|
4145
|
-
"disabled"
|
|
4146
|
-
].includes(key)) return "off";
|
|
4147
|
-
if ([
|
|
4148
|
-
"on",
|
|
4149
|
-
"true",
|
|
4150
|
-
"yes",
|
|
4151
|
-
"1",
|
|
4152
|
-
"show",
|
|
4153
|
-
"visible",
|
|
4154
|
-
"enable",
|
|
4155
|
-
"enabled"
|
|
4156
|
-
].includes(key)) return "on";
|
|
4157
|
-
if ([
|
|
4158
|
-
"stream",
|
|
4159
|
-
"streaming",
|
|
4160
|
-
"draft",
|
|
4161
|
-
"live"
|
|
4162
|
-
].includes(key)) return "stream";
|
|
4163
|
-
}
|
|
4164
|
-
|
|
4165
|
-
//#endregion
|
|
4166
|
-
//#region src/infra/pairing-files.ts
|
|
4167
|
-
function createAsyncLock() {
|
|
4168
|
-
let lock = Promise.resolve();
|
|
4169
|
-
return async function withLock(fn) {
|
|
4170
|
-
const prev = lock;
|
|
4171
|
-
let release;
|
|
4172
|
-
lock = new Promise((resolve) => {
|
|
4173
|
-
release = resolve;
|
|
4174
|
-
});
|
|
4175
|
-
await prev;
|
|
4176
|
-
try {
|
|
4177
|
-
return await fn();
|
|
4178
|
-
} finally {
|
|
4179
|
-
release?.();
|
|
4180
|
-
}
|
|
4181
|
-
};
|
|
4182
|
-
}
|
|
4183
|
-
|
|
4184
|
-
//#endregion
|
|
4185
|
-
//#region src/infra/node-pairing.ts
|
|
4186
|
-
const PENDING_TTL_MS = 300 * 1e3;
|
|
4187
|
-
const withLock = createAsyncLock();
|
|
4188
|
-
|
|
4189
|
-
//#endregion
|
|
4190
|
-
//#region src/infra/skills-remote.ts
|
|
4191
|
-
const log = createSubsystemLogger("gateway/skills-remote");
|
|
4192
|
-
const remoteNodes = /* @__PURE__ */ new Map();
|
|
4193
|
-
function isMacPlatform(platform, deviceFamily) {
|
|
4194
|
-
const platformNorm = String(platform ?? "").trim().toLowerCase();
|
|
4195
|
-
const familyNorm = String(deviceFamily ?? "").trim().toLowerCase();
|
|
4196
|
-
if (platformNorm.includes("mac")) return true;
|
|
4197
|
-
if (platformNorm.includes("darwin")) return true;
|
|
4198
|
-
if (familyNorm === "mac") return true;
|
|
4199
|
-
return false;
|
|
4200
|
-
}
|
|
4201
|
-
function supportsSystemRun(commands) {
|
|
4202
|
-
return Array.isArray(commands) && commands.includes("system.run");
|
|
4203
|
-
}
|
|
4204
|
-
function getRemoteSkillEligibility() {
|
|
4205
|
-
const macNodes = [...remoteNodes.values()].filter((node) => isMacPlatform(node.platform, node.deviceFamily) && supportsSystemRun(node.commands));
|
|
4206
|
-
if (macNodes.length === 0) return;
|
|
4207
|
-
const bins = /* @__PURE__ */ new Set();
|
|
4208
|
-
for (const node of macNodes) for (const bin of node.bins) bins.add(bin);
|
|
4209
|
-
const labels = macNodes.map((node) => node.displayName ?? node.nodeId).filter(Boolean);
|
|
4210
|
-
return {
|
|
4211
|
-
platforms: ["darwin"],
|
|
4212
|
-
hasBin: (bin) => bins.has(bin),
|
|
4213
|
-
hasAnyBin: (required) => required.some((bin) => bins.has(bin)),
|
|
4214
|
-
note: labels.length > 0 ? `Remote macOS node available (${labels.join(", ")}). Run macOS-only skills via nodes.run on that node.` : "Remote macOS node available. Run macOS-only skills via nodes.run on that node."
|
|
4215
|
-
};
|
|
4216
|
-
}
|
|
4217
|
-
|
|
4218
|
-
//#endregion
|
|
4219
|
-
//#region src/sessions/level-overrides.ts
|
|
4220
|
-
function applyVerboseOverride(entry, level) {
|
|
4221
|
-
if (level === void 0) return;
|
|
4222
|
-
if (level === null) {
|
|
4223
|
-
delete entry.verboseLevel;
|
|
4224
|
-
return;
|
|
4225
|
-
}
|
|
4226
|
-
entry.verboseLevel = level;
|
|
4227
|
-
}
|
|
4228
|
-
|
|
4229
|
-
//#endregion
|
|
4230
|
-
//#region src/sessions/model-overrides.ts
|
|
4231
|
-
function applyModelOverrideToSessionEntry(params) {
|
|
4232
|
-
const { entry, selection, profileOverride } = params;
|
|
4233
|
-
const profileOverrideSource = params.profileOverrideSource ?? "user";
|
|
4234
|
-
let updated = false;
|
|
4235
|
-
if (selection.isDefault) {
|
|
4236
|
-
if (entry.providerOverride) {
|
|
4237
|
-
delete entry.providerOverride;
|
|
4238
|
-
updated = true;
|
|
4239
|
-
}
|
|
4240
|
-
if (entry.modelOverride) {
|
|
4241
|
-
delete entry.modelOverride;
|
|
4242
|
-
updated = true;
|
|
4243
|
-
}
|
|
4244
|
-
} else {
|
|
4245
|
-
if (entry.providerOverride !== selection.provider) {
|
|
4246
|
-
entry.providerOverride = selection.provider;
|
|
4247
|
-
updated = true;
|
|
4248
|
-
}
|
|
4249
|
-
if (entry.modelOverride !== selection.model) {
|
|
4250
|
-
entry.modelOverride = selection.model;
|
|
4251
|
-
updated = true;
|
|
4252
|
-
}
|
|
4253
|
-
}
|
|
4254
|
-
if (profileOverride) {
|
|
4255
|
-
if (entry.authProfileOverride !== profileOverride) {
|
|
4256
|
-
entry.authProfileOverride = profileOverride;
|
|
4257
|
-
updated = true;
|
|
4258
|
-
}
|
|
4259
|
-
if (entry.authProfileOverrideSource !== profileOverrideSource) {
|
|
4260
|
-
entry.authProfileOverrideSource = profileOverrideSource;
|
|
4261
|
-
updated = true;
|
|
4262
|
-
}
|
|
4263
|
-
if (entry.authProfileOverrideCompactionCount !== void 0) {
|
|
4264
|
-
delete entry.authProfileOverrideCompactionCount;
|
|
4265
|
-
updated = true;
|
|
4266
|
-
}
|
|
4267
|
-
} else {
|
|
4268
|
-
if (entry.authProfileOverride) {
|
|
4269
|
-
delete entry.authProfileOverride;
|
|
4270
|
-
updated = true;
|
|
4271
|
-
}
|
|
4272
|
-
if (entry.authProfileOverrideSource) {
|
|
4273
|
-
delete entry.authProfileOverrideSource;
|
|
4274
|
-
updated = true;
|
|
4275
|
-
}
|
|
4276
|
-
if (entry.authProfileOverrideCompactionCount !== void 0) {
|
|
4277
|
-
delete entry.authProfileOverrideCompactionCount;
|
|
4278
|
-
updated = true;
|
|
4279
|
-
}
|
|
4280
|
-
}
|
|
4281
|
-
if (updated) entry.updatedAt = Date.now();
|
|
4282
|
-
return { updated };
|
|
4283
|
-
}
|
|
4284
|
-
|
|
4285
|
-
//#endregion
|
|
4286
|
-
//#region src/sessions/send-policy.ts
|
|
4287
|
-
function normalizeSendPolicy(raw) {
|
|
4288
|
-
const value = raw?.trim().toLowerCase();
|
|
4289
|
-
if (value === "allow") return "allow";
|
|
4290
|
-
if (value === "deny") return "deny";
|
|
4291
|
-
}
|
|
4292
|
-
function normalizeMatchValue(raw) {
|
|
4293
|
-
const value = raw?.trim().toLowerCase();
|
|
4294
|
-
return value ? value : void 0;
|
|
4295
|
-
}
|
|
4296
|
-
function stripAgentSessionKeyPrefix(key) {
|
|
4297
|
-
if (!key) return;
|
|
4298
|
-
const parts = key.split(":").filter(Boolean);
|
|
4299
|
-
if (parts.length >= 3 && parts[0] === "agent") return parts.slice(2).join(":");
|
|
4300
|
-
return key;
|
|
4301
|
-
}
|
|
4302
|
-
function deriveChannelFromKey(key) {
|
|
4303
|
-
const normalizedKey = stripAgentSessionKeyPrefix(key);
|
|
4304
|
-
if (!normalizedKey) return;
|
|
4305
|
-
const parts = normalizedKey.split(":").filter(Boolean);
|
|
4306
|
-
if (parts.length >= 3 && (parts[1] === "group" || parts[1] === "channel")) return normalizeMatchValue(parts[0]);
|
|
4307
|
-
}
|
|
4308
|
-
function deriveChatTypeFromKey(key) {
|
|
4309
|
-
const normalizedKey = stripAgentSessionKeyPrefix(key);
|
|
4310
|
-
if (!normalizedKey) return;
|
|
4311
|
-
if (normalizedKey.includes(":group:")) return "group";
|
|
4312
|
-
if (normalizedKey.includes(":channel:")) return "channel";
|
|
4313
|
-
}
|
|
4314
|
-
function resolveSendPolicy(params) {
|
|
4315
|
-
const override = normalizeSendPolicy(params.entry?.sendPolicy);
|
|
4316
|
-
if (override) return override;
|
|
4317
|
-
const policy = params.cfg.session?.sendPolicy;
|
|
4318
|
-
if (!policy) return "allow";
|
|
4319
|
-
const channel = normalizeMatchValue(params.channel) ?? normalizeMatchValue(params.entry?.channel) ?? normalizeMatchValue(params.entry?.lastChannel) ?? deriveChannelFromKey(params.sessionKey);
|
|
4320
|
-
const chatType = normalizeChatType(params.chatType ?? params.entry?.chatType) ?? normalizeChatType(deriveChatTypeFromKey(params.sessionKey));
|
|
4321
|
-
const rawSessionKey = params.sessionKey ?? "";
|
|
4322
|
-
const strippedSessionKey = stripAgentSessionKeyPrefix(rawSessionKey) ?? "";
|
|
4323
|
-
const rawSessionKeyNorm = rawSessionKey.toLowerCase();
|
|
4324
|
-
const strippedSessionKeyNorm = strippedSessionKey.toLowerCase();
|
|
4325
|
-
let allowedMatch = false;
|
|
4326
|
-
for (const rule of policy.rules ?? []) {
|
|
4327
|
-
if (!rule) continue;
|
|
4328
|
-
const action = normalizeSendPolicy(rule.action) ?? "allow";
|
|
4329
|
-
const match = rule.match ?? {};
|
|
4330
|
-
const matchChannel = normalizeMatchValue(match.channel);
|
|
4331
|
-
const matchChatType = normalizeChatType(match.chatType);
|
|
4332
|
-
const matchPrefix = normalizeMatchValue(match.keyPrefix);
|
|
4333
|
-
const matchRawPrefix = normalizeMatchValue(match.rawKeyPrefix);
|
|
4334
|
-
if (matchChannel && matchChannel !== channel) continue;
|
|
4335
|
-
if (matchChatType && matchChatType !== chatType) continue;
|
|
4336
|
-
if (matchRawPrefix && !rawSessionKeyNorm.startsWith(matchRawPrefix)) continue;
|
|
4337
|
-
if (matchPrefix && !rawSessionKeyNorm.startsWith(matchPrefix) && !strippedSessionKeyNorm.startsWith(matchPrefix)) continue;
|
|
4338
|
-
if (action === "deny") return "deny";
|
|
4339
|
-
allowedMatch = true;
|
|
4340
|
-
}
|
|
4341
|
-
if (allowedMatch) return "allow";
|
|
4342
|
-
return normalizeSendPolicy(policy.default) ?? "allow";
|
|
4343
|
-
}
|
|
4344
|
-
|
|
4345
|
-
//#endregion
|
|
4346
|
-
//#region src/infra/outbound/target-errors.ts
|
|
4347
|
-
function missingTargetMessage(provider, hint) {
|
|
4348
|
-
return `Delivering to ${provider} requires target${formatTargetHint(hint)}`;
|
|
4349
|
-
}
|
|
4350
|
-
function missingTargetError(provider, hint) {
|
|
4351
|
-
return new Error(missingTargetMessage(provider, hint));
|
|
4352
|
-
}
|
|
4353
|
-
function ambiguousTargetMessage(provider, raw, hint) {
|
|
4354
|
-
return `Ambiguous target "${raw}" for ${provider}. Provide a unique name or an explicit id.${formatTargetHint(hint, true)}`;
|
|
4355
|
-
}
|
|
4356
|
-
function ambiguousTargetError(provider, raw, hint) {
|
|
4357
|
-
return new Error(ambiguousTargetMessage(provider, raw, hint));
|
|
4358
|
-
}
|
|
4359
|
-
function unknownTargetMessage(provider, raw, hint) {
|
|
4360
|
-
return `Unknown target "${raw}" for ${provider}.${formatTargetHint(hint, true)}`;
|
|
4361
|
-
}
|
|
4362
|
-
function unknownTargetError(provider, raw, hint) {
|
|
4363
|
-
return new Error(unknownTargetMessage(provider, raw, hint));
|
|
4364
|
-
}
|
|
4365
|
-
function formatTargetHint(hint, withLabel = false) {
|
|
4366
|
-
if (!hint) return "";
|
|
4367
|
-
return withLabel ? ` Hint: ${hint}` : ` ${hint}`;
|
|
4368
|
-
}
|
|
4369
|
-
|
|
4370
|
-
//#endregion
|
|
4371
|
-
//#region src/infra/outbound/targets.ts
|
|
4372
|
-
function resolveSessionDeliveryTarget(params) {
|
|
4373
|
-
const context = deliveryContextFromSession(params.entry);
|
|
4374
|
-
const lastChannel = context?.channel && isDeliverableMessageChannel(context.channel) ? context.channel : void 0;
|
|
4375
|
-
const lastTo = context?.to;
|
|
4376
|
-
const lastAccountId = context?.accountId;
|
|
4377
|
-
const lastThreadId = context?.threadId;
|
|
4378
|
-
const rawRequested = params.requestedChannel ?? "last";
|
|
4379
|
-
const requested = rawRequested === "last" ? "last" : normalizeMessageChannel(rawRequested);
|
|
4380
|
-
const requestedChannel = requested === "last" ? "last" : requested && isDeliverableMessageChannel(requested) ? requested : void 0;
|
|
4381
|
-
const explicitTo = typeof params.explicitTo === "string" && params.explicitTo.trim() ? params.explicitTo.trim() : void 0;
|
|
4382
|
-
const explicitThreadId = params.explicitThreadId != null && params.explicitThreadId !== "" ? params.explicitThreadId : void 0;
|
|
4383
|
-
let channel = requestedChannel === "last" ? lastChannel : requestedChannel;
|
|
4384
|
-
if (!channel && params.fallbackChannel && isDeliverableMessageChannel(params.fallbackChannel)) channel = params.fallbackChannel;
|
|
4385
|
-
let to = explicitTo;
|
|
4386
|
-
if (!to && lastTo) {
|
|
4387
|
-
if (channel && channel === lastChannel) to = lastTo;
|
|
4388
|
-
else if (params.allowMismatchedLastTo) to = lastTo;
|
|
4389
|
-
}
|
|
4390
|
-
const accountId = channel && channel === lastChannel ? lastAccountId : void 0;
|
|
4391
|
-
const threadId = channel && channel === lastChannel ? lastThreadId : void 0;
|
|
4392
|
-
const mode = params.mode ?? (explicitTo ? "explicit" : "implicit");
|
|
4393
|
-
return {
|
|
4394
|
-
channel,
|
|
4395
|
-
to,
|
|
4396
|
-
accountId,
|
|
4397
|
-
threadId: explicitThreadId ?? threadId,
|
|
4398
|
-
mode,
|
|
4399
|
-
lastChannel,
|
|
4400
|
-
lastTo,
|
|
4401
|
-
lastAccountId,
|
|
4402
|
-
lastThreadId
|
|
4403
|
-
};
|
|
4404
|
-
}
|
|
4405
|
-
function resolveOutboundTarget(params) {
|
|
4406
|
-
if (params.channel === INTERNAL_MESSAGE_CHANNEL) return {
|
|
4407
|
-
ok: false,
|
|
4408
|
-
error: /* @__PURE__ */ new Error(`Delivering to WebChat is not supported via \`${formatCliCommand("anima agent")}\`; use WhatsApp/Telegram or run with --deliver=false.`)
|
|
4409
|
-
};
|
|
4410
|
-
const plugin = getChannelPlugin(params.channel);
|
|
4411
|
-
if (!plugin) return {
|
|
4412
|
-
ok: false,
|
|
4413
|
-
error: /* @__PURE__ */ new Error(`Unsupported channel: ${params.channel}`)
|
|
4414
|
-
};
|
|
4415
|
-
const allowFrom = params.allowFrom ?? (params.cfg && plugin.config.resolveAllowFrom ? plugin.config.resolveAllowFrom({
|
|
4416
|
-
cfg: params.cfg,
|
|
4417
|
-
accountId: params.accountId ?? void 0
|
|
4418
|
-
}) : void 0);
|
|
4419
|
-
const resolveTarget = plugin.outbound?.resolveTarget;
|
|
4420
|
-
if (resolveTarget) return resolveTarget({
|
|
4421
|
-
cfg: params.cfg,
|
|
4422
|
-
to: params.to,
|
|
4423
|
-
allowFrom,
|
|
4424
|
-
accountId: params.accountId ?? void 0,
|
|
4425
|
-
mode: params.mode ?? "explicit"
|
|
4426
|
-
});
|
|
4427
|
-
const trimmed = params.to?.trim();
|
|
4428
|
-
if (trimmed) return {
|
|
4429
|
-
ok: true,
|
|
4430
|
-
to: trimmed
|
|
4431
|
-
};
|
|
4432
|
-
const hint = plugin.messaging?.targetResolver?.hint;
|
|
4433
|
-
return {
|
|
4434
|
-
ok: false,
|
|
4435
|
-
error: missingTargetError(plugin.meta.label ?? params.channel, hint)
|
|
4436
|
-
};
|
|
4437
|
-
}
|
|
4438
|
-
|
|
4439
|
-
//#endregion
|
|
4440
|
-
//#region src/agents/context.ts
|
|
4441
|
-
const MODEL_CACHE = /* @__PURE__ */ new Map();
|
|
4442
|
-
(async () => {
|
|
4443
|
-
try {
|
|
4444
|
-
const { discoverAuthStorage, discoverModels } = await import("./pi-model-discovery-Cxs4pvC2.js");
|
|
4445
|
-
await ensureAnimaModelsJson(loadConfig());
|
|
4446
|
-
const agentDir = resolveAnimaAgentDir();
|
|
4447
|
-
const models = discoverModels(discoverAuthStorage(agentDir), agentDir).getAll();
|
|
4448
|
-
for (const m of models) {
|
|
4449
|
-
if (!m?.id) continue;
|
|
4450
|
-
if (typeof m.contextWindow === "number" && m.contextWindow > 0) MODEL_CACHE.set(m.id, m.contextWindow);
|
|
4451
|
-
}
|
|
4452
|
-
} catch {}
|
|
4453
|
-
})();
|
|
4454
|
-
function lookupContextTokens(modelId) {
|
|
4455
|
-
if (!modelId) return;
|
|
4456
|
-
return MODEL_CACHE.get(modelId);
|
|
4457
|
-
}
|
|
4458
|
-
|
|
4459
|
-
//#endregion
|
|
4460
|
-
//#region src/agents/usage.ts
|
|
4461
|
-
const asFiniteNumber = (value) => {
|
|
4462
|
-
if (typeof value !== "number") return;
|
|
4463
|
-
if (!Number.isFinite(value)) return;
|
|
4464
|
-
return value;
|
|
4465
|
-
};
|
|
4466
|
-
function hasNonzeroUsage(usage) {
|
|
4467
|
-
if (!usage) return false;
|
|
4468
|
-
return [
|
|
4469
|
-
usage.input,
|
|
4470
|
-
usage.output,
|
|
4471
|
-
usage.cacheRead,
|
|
4472
|
-
usage.cacheWrite,
|
|
4473
|
-
usage.total
|
|
4474
|
-
].some((v) => typeof v === "number" && Number.isFinite(v) && v > 0);
|
|
4475
|
-
}
|
|
4476
|
-
function normalizeUsage(raw) {
|
|
4477
|
-
if (!raw) return;
|
|
4478
|
-
const input = asFiniteNumber(raw.input ?? raw.inputTokens ?? raw.input_tokens ?? raw.promptTokens ?? raw.prompt_tokens);
|
|
4479
|
-
const output = asFiniteNumber(raw.output ?? raw.outputTokens ?? raw.output_tokens ?? raw.completionTokens ?? raw.completion_tokens);
|
|
4480
|
-
const cacheRead = asFiniteNumber(raw.cacheRead ?? raw.cache_read ?? raw.cache_read_input_tokens);
|
|
4481
|
-
const cacheWrite = asFiniteNumber(raw.cacheWrite ?? raw.cache_write ?? raw.cache_creation_input_tokens);
|
|
4482
|
-
const total = asFiniteNumber(raw.total ?? raw.totalTokens ?? raw.total_tokens);
|
|
4483
|
-
if (input === void 0 && output === void 0 && cacheRead === void 0 && cacheWrite === void 0 && total === void 0) return;
|
|
4484
|
-
return {
|
|
4485
|
-
input,
|
|
4486
|
-
output,
|
|
4487
|
-
cacheRead,
|
|
4488
|
-
cacheWrite,
|
|
4489
|
-
total
|
|
4490
|
-
};
|
|
4491
|
-
}
|
|
4492
|
-
function derivePromptTokens(usage) {
|
|
4493
|
-
if (!usage) return;
|
|
4494
|
-
const input = usage.input ?? 0;
|
|
4495
|
-
const cacheRead = usage.cacheRead ?? 0;
|
|
4496
|
-
const cacheWrite = usage.cacheWrite ?? 0;
|
|
4497
|
-
const sum = input + cacheRead + cacheWrite;
|
|
4498
|
-
return sum > 0 ? sum : void 0;
|
|
4499
|
-
}
|
|
4500
|
-
function deriveSessionTotalTokens(params) {
|
|
4501
|
-
const promptOverride = params.promptTokens;
|
|
4502
|
-
const hasPromptOverride = typeof promptOverride === "number" && Number.isFinite(promptOverride) && promptOverride > 0;
|
|
4503
|
-
const usage = params.usage;
|
|
4504
|
-
if (!usage && !hasPromptOverride) return;
|
|
4505
|
-
const input = usage?.input ?? 0;
|
|
4506
|
-
let total = (hasPromptOverride ? promptOverride : derivePromptTokens({
|
|
4507
|
-
input: usage?.input,
|
|
4508
|
-
cacheRead: usage?.cacheRead,
|
|
4509
|
-
cacheWrite: usage?.cacheWrite
|
|
4510
|
-
})) ?? usage?.total ?? input;
|
|
4511
|
-
if (!(total > 0)) return;
|
|
4512
|
-
return total;
|
|
4513
|
-
}
|
|
4514
|
-
|
|
4515
|
-
//#endregion
|
|
4516
|
-
export { getTtsProvider as $, assertSandboxPath as A, runCliAgent as B, supportsXHighThinking as C, buildWorkspaceSkillSnapshot as D, buildWorkspaceSkillCommandSpecs as E, loadModelCatalog as F, resolveUserTimezone as G, buildSystemPromptParams as H, modelSupportsVision as I, killProcessTree as J, withNormalizedTimestamp as K, ensureAnimaModelsJson as L, runWithImageModelFallback as M, runWithModelFallback as N, syncSkillsToWorkspace as O, findModelInCatalog as P, getTtsMaxLength as Q, getCliSessionId as R, resolveResponseUsageMode as S, getSkillsSnapshotVersion as T, formatUserTime as U, buildAgentSystemPrompt as V, resolveUserTimeFormat as W, buildTtsSystemPromptHint as X, sanitizeBinaryOutput as Y, getLastTtsAttempt as Z, normalizeElevatedLevel as _, resolveBootstrapContextForRun as _t, lookupContextTokens as a, resolveTtsApiKey as at, normalizeUsageDisplay as b, ambiguousTargetError as c, resolveTtsPrefsPath as ct, applyModelOverrideToSessionEntry as d, setTtsEnabled as dt, isSummarizationEnabled as et, applyVerboseOverride as f, setTtsMaxLength as ft, listThinkingLevels as g, isVoiceCompatibleAudio as gt, formatXHighModelHint as h, textToSpeechTelephony as ht, normalizeUsage as i, normalizeTtsAutoMode as it, resolveSandboxedMediaSource as j, assertMediaNotDataUrl as k, unknownTargetError as l, setLastTtsAttempt as lt, formatThinkingLevels as m, textToSpeech as mt, deriveSessionTotalTokens as n, isTtsProviderConfigured as nt, resolveOutboundTarget as o, resolveTtsAutoMode as ot, getRemoteSkillEligibility as p, setTtsProvider as pt, getShellConfig as q, hasNonzeroUsage as r, maybeApplyTtsToPayload as rt, resolveSessionDeliveryTarget as s, resolveTtsConfig as st, derivePromptTokens as t, isTtsEnabled as tt, resolveSendPolicy as u, setSummarizationEnabled as ut, normalizeReasoningLevel as v, clearSessionAuthProfileOverride as vt, ensureSkillsWatcher as w, normalizeVerboseLevel as x, normalizeThinkLevel as y, resolveSessionAuthProfileOverride as yt, setCliSessionId as z };
|