@symerian/symi 2.6.0 → 2.6.2
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/dist/{agents-Bi50kp6u.js → agents-qLMWAYwU.js} +4 -4
- package/dist/{agents.config-BcTeP94V.js → agents.config-BfjAwFCr.js} +1 -1
- package/dist/{agents.config-Duce7lam.js → agents.config-BmdFH4J5.js} +1 -1
- package/dist/{audio-preflight-DHTaS5U1.js → audio-preflight-BVaaZWkg.js} +4 -4
- package/dist/{audio-preflight-C40mKAp7.js → audio-preflight-CPBOQV4I.js} +4 -4
- package/dist/{auth-choice-Dyq-0MNq.js → auth-choice-D1u_GPfQ.js} +1 -1
- package/dist/{auth-choice-BFIBR4l9.js → auth-choice-zFq3WRQ0.js} +1 -1
- package/dist/{banner-D50f_0qf.js → banner-DpH44qlJ.js} +1 -1
- package/dist/build-info.json +3 -3
- package/dist/bundled/boot-md/handler.js +6 -6
- package/dist/bundled/session-memory/handler.js +6 -6
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/{channel-options-BFqaanEt.js → channel-options-0iOfzVR3.js} +1 -1
- package/dist/{channel-options-BvBcjqyk.js → channel-options-C8tKm8re.js} +1 -1
- package/dist/{channel-web-BQtFg4IP.js → channel-web-DYinYBz4.js} +1 -1
- package/dist/{channels-cli-BuTH-iVi.js → channels-cli-93tLT17t.js} +4 -4
- package/dist/{channels-cli-BYFQdWnL.js → channels-cli-C8HgSMTH.js} +4 -4
- package/dist/{chrome-DYZwl5Gv.js → chrome-D2SKJnR7.js} +5 -5
- package/dist/{chrome-CDJYxX5a.js → chrome-DkaXoP36.js} +5 -5
- package/dist/{cli-r2L-UK6y.js → cli-BYJyRW2M.js} +1 -1
- package/dist/{cli-eOBlVLcC.js → cli-DapZXGSB.js} +1 -1
- package/dist/{command-registry-D-pwcAIW.js → command-registry-9EhYc6da.js} +9 -9
- package/dist/{completion-cli-DIx7KyOG.js → completion-cli-BFZv3K5D.js} +2 -2
- package/dist/{completion-cli-DMO2OGTm.js → completion-cli-CCeQlMlC.js} +1 -1
- package/dist/{config-cli-BsDxqYDU.js → config-cli-DbWMIBUz.js} +1 -1
- package/dist/{config-cli-seaVWVru.js → config-cli-Dv2mtIeM.js} +1 -1
- package/dist/{configure-BmPwuHXL.js → configure-B8zV6Hxj.js} +3 -3
- package/dist/{configure-CqbKA0_V.js → configure-CVQf2UJE.js} +3 -3
- package/dist/{deliver-BH0l3UKW.js → deliver-C-37cZUe.js} +1 -1
- package/dist/{deliver-dODxSv3b.js → deliver-C46-vyqg.js} +1 -1
- package/dist/{doctor-completion-DMjs7-Qa.js → doctor-completion-BunqvoqZ.js} +1 -1
- package/dist/{doctor-completion-C2IV3lKi.js → doctor-completion-CLeX1kaN.js} +1 -1
- package/dist/entry.js +1 -1
- package/dist/extensionAPI.js +6 -6
- package/dist/{gateway-cli-BanaeKQ_.js → gateway-cli-Co-tp-WC.js} +9 -9
- package/dist/{gateway-cli-C-J_s559.js → gateway-cli-DMey_29a.js} +9 -9
- package/dist/{glass-ui-ws-DUzp9m0D.js → glass-ui-ws-C4O227UO.js} +7 -7
- package/dist/{glass-ui-ws-DK7x3Tz7.js → glass-ui-ws-CKb1jTZR.js} +7 -7
- package/dist/{health-DK6rAOhC.js → health-CDGOsNeD.js} +1 -1
- package/dist/{health-BpHgCv-u.js → health-CM1asUG8.js} +1 -1
- package/dist/{hooks-cli-D-75G_66.js → hooks-cli-DFKB3Z6X.js} +2 -2
- package/dist/{hooks-cli-Cin_3tFg.js → hooks-cli-Tx0TzSju.js} +2 -2
- package/dist/{image-CXu8W39c.js → image-CuzFLQWC.js} +1 -1
- package/dist/{image-CHzdaNJ4.js → image-DcpMiprB.js} +1 -1
- package/dist/index.js +6 -6
- package/dist/llm-slug-generator.js +6 -6
- package/dist/{models-CeKIXf5B.js → models-CiqHYwje.js} +2 -2
- package/dist/{models-cli-2NcPKR9A.js → models-cli-B-b-gBKG.js} +2 -2
- package/dist/{models-cli-DN4AVlpI.js → models-cli-B4ATSsNS.js} +3 -3
- package/dist/{onboard-BukRqcRH.js → onboard-B_ECX48L.js} +2 -2
- package/dist/{onboard-BcxDiUl_.js → onboard-DcnGZKZX.js} +2 -2
- package/dist/{onboard-channels-DS6s341R.js → onboard-channels-FFQPpuEN.js} +1 -1
- package/dist/{onboard-channels-HPxu77wp.js → onboard-channels-pfSGhg_C.js} +1 -1
- package/dist/{onboarding-DI-o_sax.js → onboarding-BU14cspo.js} +3 -3
- package/dist/{onboarding-B8uz24jt.js → onboarding-jhZxQcZ3.js} +3 -3
- package/dist/{onboarding.finalize-CfE_AEto.js → onboarding.finalize-B8oOMfHc.js} +6 -6
- package/dist/{onboarding.finalize-Bn2e61yb.js → onboarding.finalize-ByZT4dF5.js} +5 -5
- package/dist/{pi-embedded-B5qBa69e.js → pi-embedded-BY9AnmoP.js} +203 -27
- package/dist/{pi-embedded-helpers-lgx_U5KS.js → pi-embedded-helpers-B8kqLWns.js} +4 -4
- package/dist/{pi-embedded-helpers-pubKo8HQ.js → pi-embedded-helpers-CfqDGQ9J.js} +4 -4
- package/dist/{plugin-registry-NIUxULTk.js → plugin-registry-CNf1_8hj.js} +1 -1
- package/dist/{plugin-registry-cj99EI0k.js → plugin-registry-DXWJkJX6.js} +1 -1
- package/dist/plugin-sdk/{accounts-BtaOa4z_.js → accounts-BToL3HlP.js} +1 -1
- package/dist/plugin-sdk/{accounts-Ddm33hQm.js → accounts-D9zGZU5t.js} +3 -3
- package/dist/plugin-sdk/{accounts-s-AdhXVR.js → accounts-Dtszw3Zn.js} +1 -1
- package/dist/plugin-sdk/{active-listener-BXYeALs0.js → active-listener-bEk__wbB.js} +1 -1
- package/dist/plugin-sdk/{agent-scope-CYYpcO9W.js → agent-scope-C3gMMKCU.js} +2 -2
- package/dist/plugin-sdk/agents/model-token-filter.d.ts +10 -0
- package/dist/plugin-sdk/agents/pi-tools.validate-wrapper.d.ts +23 -0
- package/dist/plugin-sdk/agents/pi-tools.validate.d.ts +26 -0
- package/dist/plugin-sdk/agents/tool-loop-detection.d.ts +3 -1
- package/dist/plugin-sdk/{api-key-rotation-D_sMvI5W.js → api-key-rotation-CVBMpnPc.js} +1 -1
- package/dist/plugin-sdk/{audio-preflight-VpItkiy3.js → audio-preflight-DoQQKlxa.js} +24 -24
- package/dist/plugin-sdk/{bindings-C7hRtgYW.js → bindings-BbwoUGPx.js} +2 -2
- package/dist/plugin-sdk/{channel-activity-DoC1xtDu.js → channel-activity-Ji7f0gqq.js} +1 -1
- package/dist/plugin-sdk/{channel-web-CSd16cDi.js → channel-web-DZQQ0mzN.js} +22 -22
- package/dist/plugin-sdk/{chrome-B7RdxmJ0.js → chrome-C7c_0I5M.js} +3 -3
- package/dist/plugin-sdk/{chunk-Dw2XBYXv.js → chunk-jvk9axTQ.js} +1 -1
- package/dist/plugin-sdk/{command-format-GKSevep4.js → command-format-DSdvQ_M5.js} +1 -1
- package/dist/plugin-sdk/{commands-registry-COIaslGl.js → commands-registry-CQFbmUMs.js} +4 -4
- package/dist/plugin-sdk/config/model-profiles.d.ts +2 -0
- package/dist/plugin-sdk/{config-KlTNfkFF.js → config-DDkdiUOR.js} +9 -9
- package/dist/plugin-sdk/{deliver-BZ99UKQq.js → deliver-BZ6iNLl7.js} +10 -10
- package/dist/plugin-sdk/{diagnostic-05pm5Rxi.js → diagnostic-mFf4i4G9.js} +1 -1
- package/dist/plugin-sdk/{image-CLOPx7yW.js → image-BOYy0Ump.js} +4 -4
- package/dist/plugin-sdk/{image-ops-BlQR__MN.js → image-ops-Bnp6LXEx.js} +1 -1
- package/dist/plugin-sdk/index.js +53 -53
- package/dist/plugin-sdk/infra/diagnostic-events.d.ts +1 -1
- package/dist/plugin-sdk/{ir-BJ6BHE5b.js → ir-Fb3qpcis.js} +4 -4
- package/dist/plugin-sdk/{local-roots-BHLNSI8U.js → local-roots-Ckk1QfzI.js} +3 -3
- package/dist/plugin-sdk/logging/diagnostic-session-state.d.ts +2 -0
- package/dist/plugin-sdk/logging/diagnostic.d.ts +1 -1
- package/dist/plugin-sdk/{login-DQMXuxOk.js → login-Bh3DZPam.js} +7 -7
- package/dist/plugin-sdk/{login-qr-BjVZSoCi.js → login-qr-DbR7odSr.js} +9 -9
- package/dist/plugin-sdk/{manager-CBSBFuFz.js → manager-DckktAQ3.js} +8 -8
- package/dist/plugin-sdk/{manifest-registry-CPnHl_K3.js → manifest-registry-B3ugY9-f.js} +1 -1
- package/dist/plugin-sdk/{markdown-tables-BoYFajMu.js → markdown-tables-Dfaqilz6.js} +1 -1
- package/dist/plugin-sdk/{message-channel-COTAJzHd.js → message-channel-BdI5Ra9S.js} +1 -1
- package/dist/plugin-sdk/{model-selection-CsbEfrS0.js → model-selection-OpU8HN50.js} +4 -4
- package/dist/plugin-sdk/{outbound-attachment-CnslKL38.js → outbound-attachment-DnVQfTG2.js} +2 -2
- package/dist/plugin-sdk/{outbound-B0e8KdaR.js → outbound-rF6G8Xpr.js} +7 -7
- package/dist/plugin-sdk/{pi-auth-json-qWi7ZIYV.js → pi-auth-json-CJk8t14T.js} +5 -5
- package/dist/plugin-sdk/{pi-embedded-helpers-CW630epe.js → pi-embedded-helpers-BveUP4hk.js} +17 -17
- package/dist/plugin-sdk/{plugins-BNByVCIH.js → plugins-BbAvhC25.js} +4 -4
- package/dist/plugin-sdk/{pw-ai-CnbPIPY9.js → pw-ai-DjGUsee-.js} +8 -8
- package/dist/plugin-sdk/{qmd-manager-CH0XbIHf.js → qmd-manager-mjKcdwVr.js} +4 -4
- package/dist/plugin-sdk/{registry-D0xTnUWt.js → registry--_pGht6S.js} +2 -2
- package/dist/plugin-sdk/{replies-LLcQL3w6.js → replies-fI39rPGa.js} +3 -3
- package/dist/plugin-sdk/{reply-CkqSfQZN.js → reply-DvZeyOVA.js} +263 -87
- package/dist/plugin-sdk/{reply-prefix-uxfMZW4p.js → reply-prefix-BHuV5t70.js} +1 -1
- package/dist/plugin-sdk/{resolve-outbound-target-BiyAyTWz.js → resolve-outbound-target-BkCUbYGV.js} +2 -2
- package/dist/plugin-sdk/{resolve-route-B3CCBumQ.js → resolve-route-D3JH_D2N.js} +3 -3
- package/dist/plugin-sdk/{retry-CwQ_iIj8.js → retry-ilSJqnz9.js} +1 -1
- package/dist/plugin-sdk/{runner-CGBT7tgF.js → runner-BVqnEfNe.js} +9 -9
- package/dist/plugin-sdk/{send-C5h_YxNb.js → send-BHbXh8Ly.js} +7 -7
- package/dist/plugin-sdk/{send-pYqe432l.js → send-BMfJIhCk.js} +6 -6
- package/dist/plugin-sdk/{send-B2CEnVLL.js → send-BtANzsAo.js} +6 -6
- package/dist/plugin-sdk/{send-CjOBB3Vo.js → send-Bxdu6ZZy.js} +10 -10
- package/dist/plugin-sdk/{send-CRsR8-vO.js → send-D6LMZJ_h.js} +10 -10
- package/dist/plugin-sdk/{session-BsOrxiMj.js → session-kI0tzViQ.js} +4 -4
- package/dist/plugin-sdk/{skill-commands-ff_01_r3.js → skill-commands-DCNXVERE.js} +5 -5
- package/dist/plugin-sdk/{skills-_yTP47Cd.js → skills-B1GeRYlu.js} +7 -7
- package/dist/plugin-sdk/{sqlite-CxAR5ttJ.js → sqlite-Cq_7Cg4E.js} +1 -1
- package/dist/plugin-sdk/{store-BdrNabcU.js → store-Do3t33-c.js} +2 -2
- package/dist/plugin-sdk/{subsystem-B2uDN3TV.js → subsystem-Coz2AgU8.js} +1 -1
- package/dist/plugin-sdk/{tables-DNwXwNFa.js → tables-DR0NmBeH.js} +1 -1
- package/dist/plugin-sdk/{target-errors-Paro1BjP.js → target-errors-B7YyMnIi.js} +2 -2
- package/dist/plugin-sdk/{thinking-CXqf7WTe.js → thinking-DCNUIAHY.js} +5 -5
- package/dist/plugin-sdk/{tokens-bC3UVmVH.js → tokens-CWMflosr.js} +1 -1
- package/dist/plugin-sdk/{tool-images-HJ2sfZDV.js → tool-images-D7Lno-TE.js} +2 -2
- package/dist/plugin-sdk/{tool-loop-detection-BVA6fax-.js → tool-loop-detection-DU5sTIKg.js} +55 -5
- package/dist/plugin-sdk/web-BCsJFuQu.js +65 -0
- package/dist/plugin-sdk/{whatsapp-actions-DfseosPO.js → whatsapp-actions-CcBzDuL-.js} +21 -21
- package/dist/{plugins-cli-CcjxxESJ.js → plugins-cli-BiedlZMy.js} +2 -2
- package/dist/{plugins-cli-D8hhTHZD.js → plugins-cli-C9TYM40P.js} +2 -2
- package/dist/{program-D09h71pS.js → program-bnWda72r.js} +7 -7
- package/dist/{program-context-CLJSWBZr.js → program-context-CY1jWc5A.js} +17 -17
- package/dist/{prompt-select-styled-DQqZEGoo.js → prompt-select-styled-BEnZY8wI.js} +4 -4
- package/dist/{prompt-select-styled-zRUqu0c8.js → prompt-select-styled-B_lFTtqp.js} +4 -4
- package/dist/{provider-auth-helpers-LzJ2WQIc.js → provider-auth-helpers-DApJuzBd.js} +1 -1
- package/dist/{provider-auth-helpers-16r2WHNe.js → provider-auth-helpers-DcNKxc7D.js} +1 -1
- package/dist/{push-apns-DJddAK3u.js → push-apns-CKKHlj6j.js} +1 -1
- package/dist/{push-apns-B5xZKIxK.js → push-apns-DA7UMNQH.js} +1 -1
- package/dist/{pw-ai-De-KR9_s.js → pw-ai-1htA-NnS.js} +1 -1
- package/dist/{pw-ai-B5asscAD.js → pw-ai-m0mj2KWK.js} +1 -1
- package/dist/{register.agent-D7NKuUkY.js → register.agent-8lxVlmzQ.js} +5 -5
- package/dist/{register.agent-CP_sigRh.js → register.agent-ulu0VmOg.js} +6 -6
- package/dist/{register.configure-BEsGd0PR.js → register.configure-45--Sly1.js} +6 -6
- package/dist/{register.configure-BjRLNatb.js → register.configure-rq0h5r3X.js} +6 -6
- package/dist/{register.maintenance-DD6TNFtV.js → register.maintenance-CXbxRtWI.js} +8 -8
- package/dist/{register.maintenance-CN6KUuX7.js → register.maintenance-DyEJx7NY.js} +7 -7
- package/dist/{register.message-DEUcNly1.js → register.message-C7Yh1uky.js} +2 -2
- package/dist/{register.message-DMVC_Sqm.js → register.message-CiN_pt6K.js} +2 -2
- package/dist/{register.onboard-CP6RP90V.js → register.onboard-BWaRkbei.js} +4 -4
- package/dist/{register.onboard-J1pgV7lz.js → register.onboard-e_2hc2Rm.js} +4 -4
- package/dist/{register.setup-Dhc3jKpK.js → register.setup-BIIFHtF7.js} +4 -4
- package/dist/{register.setup-BeHpW3xI.js → register.setup-zwh90Vn-.js} +4 -4
- package/dist/{register.status-health-sessions-b-lWNsTM.js → register.status-health-sessions-D6t5maEr.js} +3 -3
- package/dist/{register.status-health-sessions-DDkC0aoW.js → register.status-health-sessions-O-sVAFHE.js} +3 -3
- package/dist/{register.subclis-BJqiT8Q2.js → register.subclis-DOiZocR6.js} +9 -9
- package/dist/{reply-D40cmAci.js → reply-05js8eGB.js} +189 -13
- package/dist/{run-main-BruREeZ6.js → run-main-u-Eyc8Wm.js} +14 -14
- package/dist/{runner-DUBExAb5.js → runner-BcQ0sF9T.js} +1 -1
- package/dist/{runner-WAG0M5s9.js → runner-CU9l0uJh.js} +1 -1
- package/dist/{server-methods-K-0MHs8x.js → server-methods-Bvl1xubo.js} +7 -7
- package/dist/{server-methods-Cyw_WS3A.js → server-methods-Dds-iEoY.js} +7 -7
- package/dist/{server-node-events-89R9Ryky.js → server-node-events-Qp-gJMET.js} +2 -2
- package/dist/{server-node-events-RA8RurtC.js → server-node-events-qGqpsPxm.js} +2 -2
- package/dist/{status-DHJLMwQN.js → status-BATOXGRi.js} +2 -2
- package/dist/{status-CtNKWuzg.js → status-BRSo-LY3.js} +2 -2
- package/dist/{status-Kv_hsY8N.js → status-BqQ9mm64.js} +1 -1
- package/dist/{status-BSMEjz4q.js → status-CfYa1Q9K.js} +1 -1
- package/dist/{subagent-registry-Cb5e_x99.js → subagent-registry-lbDgDwLy.js} +189 -13
- package/dist/{tool-loop-detection-BgbtzUGc.js → tool-loop-detection-C7TCF2V2.js} +53 -3
- package/dist/{tool-loop-detection-BU3fbtCd.js → tool-loop-detection-D7qjFnRh.js} +53 -3
- package/dist/{tool-loop-detection-B6j1r-Wk.js → tool-loop-detection-DPVtQOfM.js} +53 -3
- package/dist/{tool-loop-detection-D0kUzUGu.js → tool-loop-detection-DR_rrIA1.js} +53 -3
- package/dist/{unified-runner-CkJLTsTK.js → unified-runner-B4ICXRlg.js} +203 -27
- package/dist/{update-cli-CrRBoiVU.js → update-cli-BOaP4XyQ.js} +8 -8
- package/dist/{update-cli-Bl66LJZ4.js → update-cli-R8-SSkbS.js} +7 -7
- package/dist/{update-runner-DxpSPK-f.js → update-runner-B8UmqtLI.js} +1 -1
- package/dist/{update-runner-FgrqoxvV.js → update-runner-CWJ4pC1b.js} +1 -1
- package/dist/{web-BYRKX5Ln.js → web-BWybtnEa.js} +2 -2
- package/dist/{web-RePh7lRy.js → web-CQH9fSkH.js} +6 -6
- package/dist/{web-Czp0JS6-.js → web-CSrDbJJ7.js} +1 -1
- package/dist/{web-D99WHLTL.js → web-DBFW0ejP.js} +6 -6
- package/package.json +1 -1
- package/dist/plugin-sdk/web-DdTTil50.js +0 -65
|
@@ -7,6 +7,8 @@ const TOOL_CALL_HISTORY_SIZE = 30;
|
|
|
7
7
|
const WARNING_THRESHOLD = 10;
|
|
8
8
|
const CRITICAL_THRESHOLD = 20;
|
|
9
9
|
const GLOBAL_CIRCUIT_BREAKER_THRESHOLD = 30;
|
|
10
|
+
const CONSECUTIVE_FAILURE_WARNING_THRESHOLD = 3;
|
|
11
|
+
const CONSECUTIVE_FAILURE_CRITICAL_THRESHOLD = 5;
|
|
10
12
|
const DEFAULT_LOOP_DETECTION_CONFIG = {
|
|
11
13
|
enabled: false,
|
|
12
14
|
historySize: TOOL_CALL_HISTORY_SIZE,
|
|
@@ -16,8 +18,11 @@ const DEFAULT_LOOP_DETECTION_CONFIG = {
|
|
|
16
18
|
detectors: {
|
|
17
19
|
genericRepeat: true,
|
|
18
20
|
knownPollNoProgress: true,
|
|
19
|
-
pingPong: true
|
|
20
|
-
|
|
21
|
+
pingPong: true,
|
|
22
|
+
consecutiveFailure: true
|
|
23
|
+
},
|
|
24
|
+
consecutiveFailureWarningThreshold: CONSECUTIVE_FAILURE_WARNING_THRESHOLD,
|
|
25
|
+
consecutiveFailureCriticalThreshold: CONSECUTIVE_FAILURE_CRITICAL_THRESHOLD
|
|
21
26
|
};
|
|
22
27
|
function asPositiveInt(value, fallback) {
|
|
23
28
|
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) return fallback;
|
|
@@ -35,10 +40,13 @@ function resolveLoopDetectionConfig(config) {
|
|
|
35
40
|
warningThreshold,
|
|
36
41
|
criticalThreshold,
|
|
37
42
|
globalCircuitBreakerThreshold,
|
|
43
|
+
consecutiveFailureWarningThreshold: asPositiveInt(config?.consecutiveFailureWarningThreshold, DEFAULT_LOOP_DETECTION_CONFIG.consecutiveFailureWarningThreshold),
|
|
44
|
+
consecutiveFailureCriticalThreshold: asPositiveInt(config?.consecutiveFailureCriticalThreshold, DEFAULT_LOOP_DETECTION_CONFIG.consecutiveFailureCriticalThreshold),
|
|
38
45
|
detectors: {
|
|
39
46
|
genericRepeat: config?.detectors?.genericRepeat ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.genericRepeat,
|
|
40
47
|
knownPollNoProgress: config?.detectors?.knownPollNoProgress ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.knownPollNoProgress,
|
|
41
|
-
pingPong: config?.detectors?.pingPong ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.pingPong
|
|
48
|
+
pingPong: config?.detectors?.pingPong ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.pingPong,
|
|
49
|
+
consecutiveFailure: (config?.detectors)?.consecutiveFailure ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.consecutiveFailure
|
|
42
50
|
}
|
|
43
51
|
};
|
|
44
52
|
}
|
|
@@ -216,6 +224,22 @@ function canonicalPairKey(signatureA, signatureB) {
|
|
|
216
224
|
return [signatureA, signatureB].toSorted().join("|");
|
|
217
225
|
}
|
|
218
226
|
/**
|
|
227
|
+
* Count consecutive error results for a specific tool, walking backward from
|
|
228
|
+
* the most recent call. A success or a call to a different tool resets the streak.
|
|
229
|
+
* Only counts entries that have been resolved (have a resultHash or isError flag).
|
|
230
|
+
*/
|
|
231
|
+
function getConsecutiveFailureStreak(history, toolName) {
|
|
232
|
+
let count = 0;
|
|
233
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
234
|
+
const entry = history[i];
|
|
235
|
+
if (entry.toolName !== toolName) break;
|
|
236
|
+
if (entry.resultHash === void 0 && entry.isError === void 0) break;
|
|
237
|
+
if (!entry.isError) break;
|
|
238
|
+
count++;
|
|
239
|
+
}
|
|
240
|
+
return count;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
219
243
|
* Detect if an agent is stuck in a repetitive tool call loop.
|
|
220
244
|
* Checks if the same tool+params combination has been called excessively.
|
|
221
245
|
*/
|
|
@@ -228,6 +252,31 @@ function detectToolCallLoop(state, toolName, params, config) {
|
|
|
228
252
|
const noProgressStreak = noProgress.count;
|
|
229
253
|
const knownPollTool = isKnownPollToolCall(toolName, params);
|
|
230
254
|
const pingPong = getPingPongStreak(history, currentHash);
|
|
255
|
+
if (resolvedConfig.detectors.consecutiveFailure) {
|
|
256
|
+
const failureStreak = getConsecutiveFailureStreak(history, toolName);
|
|
257
|
+
if (failureStreak >= resolvedConfig.consecutiveFailureCriticalThreshold) {
|
|
258
|
+
log.error(`Consecutive failure circuit breaker: ${toolName} failed ${failureStreak} times in a row`);
|
|
259
|
+
return {
|
|
260
|
+
stuck: true,
|
|
261
|
+
level: "critical",
|
|
262
|
+
detector: "consecutive_failure",
|
|
263
|
+
count: failureStreak,
|
|
264
|
+
message: `CRITICAL: ${toolName} has failed ${failureStreak} consecutive times. Stop calling this tool. Explain to the user what you were trying to do and why it failed.`,
|
|
265
|
+
warningKey: `consecutive-failure:${toolName}`
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
if (failureStreak >= resolvedConfig.consecutiveFailureWarningThreshold) {
|
|
269
|
+
log.warn(`Consecutive failure warning: ${toolName} failed ${failureStreak} times in a row`);
|
|
270
|
+
return {
|
|
271
|
+
stuck: true,
|
|
272
|
+
level: "warning",
|
|
273
|
+
detector: "consecutive_failure",
|
|
274
|
+
count: failureStreak,
|
|
275
|
+
message: `WARNING: You have failed to call ${toolName} ${failureStreak} times consecutively. Stop retrying and explain to the user what you were trying to do. The tool arguments may contain invalid syntax from model control tokens.`,
|
|
276
|
+
warningKey: `consecutive-failure:${toolName}`
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
}
|
|
231
280
|
if (noProgressStreak >= resolvedConfig.globalCircuitBreakerThreshold) {
|
|
232
281
|
log.error(`Global circuit breaker triggered: ${toolName} repeated ${noProgressStreak} times with no progress`);
|
|
233
282
|
return {
|
|
@@ -332,6 +381,7 @@ function recordToolCallOutcome(state, params) {
|
|
|
332
381
|
if (call.toolName !== params.toolName || call.argsHash !== argsHash) continue;
|
|
333
382
|
if (call.resultHash !== void 0) continue;
|
|
334
383
|
call.resultHash = resultHash;
|
|
384
|
+
call.isError = params.error !== void 0;
|
|
335
385
|
matched = true;
|
|
336
386
|
break;
|
|
337
387
|
}
|
|
@@ -10,6 +10,8 @@ const TOOL_CALL_HISTORY_SIZE = 30;
|
|
|
10
10
|
const WARNING_THRESHOLD = 10;
|
|
11
11
|
const CRITICAL_THRESHOLD = 20;
|
|
12
12
|
const GLOBAL_CIRCUIT_BREAKER_THRESHOLD = 30;
|
|
13
|
+
const CONSECUTIVE_FAILURE_WARNING_THRESHOLD = 3;
|
|
14
|
+
const CONSECUTIVE_FAILURE_CRITICAL_THRESHOLD = 5;
|
|
13
15
|
const DEFAULT_LOOP_DETECTION_CONFIG = {
|
|
14
16
|
enabled: false,
|
|
15
17
|
historySize: TOOL_CALL_HISTORY_SIZE,
|
|
@@ -19,8 +21,11 @@ const DEFAULT_LOOP_DETECTION_CONFIG = {
|
|
|
19
21
|
detectors: {
|
|
20
22
|
genericRepeat: true,
|
|
21
23
|
knownPollNoProgress: true,
|
|
22
|
-
pingPong: true
|
|
23
|
-
|
|
24
|
+
pingPong: true,
|
|
25
|
+
consecutiveFailure: true
|
|
26
|
+
},
|
|
27
|
+
consecutiveFailureWarningThreshold: CONSECUTIVE_FAILURE_WARNING_THRESHOLD,
|
|
28
|
+
consecutiveFailureCriticalThreshold: CONSECUTIVE_FAILURE_CRITICAL_THRESHOLD
|
|
24
29
|
};
|
|
25
30
|
function asPositiveInt(value, fallback) {
|
|
26
31
|
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) return fallback;
|
|
@@ -38,10 +43,13 @@ function resolveLoopDetectionConfig(config) {
|
|
|
38
43
|
warningThreshold,
|
|
39
44
|
criticalThreshold,
|
|
40
45
|
globalCircuitBreakerThreshold,
|
|
46
|
+
consecutiveFailureWarningThreshold: asPositiveInt(config?.consecutiveFailureWarningThreshold, DEFAULT_LOOP_DETECTION_CONFIG.consecutiveFailureWarningThreshold),
|
|
47
|
+
consecutiveFailureCriticalThreshold: asPositiveInt(config?.consecutiveFailureCriticalThreshold, DEFAULT_LOOP_DETECTION_CONFIG.consecutiveFailureCriticalThreshold),
|
|
41
48
|
detectors: {
|
|
42
49
|
genericRepeat: config?.detectors?.genericRepeat ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.genericRepeat,
|
|
43
50
|
knownPollNoProgress: config?.detectors?.knownPollNoProgress ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.knownPollNoProgress,
|
|
44
|
-
pingPong: config?.detectors?.pingPong ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.pingPong
|
|
51
|
+
pingPong: config?.detectors?.pingPong ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.pingPong,
|
|
52
|
+
consecutiveFailure: (config?.detectors)?.consecutiveFailure ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.consecutiveFailure
|
|
45
53
|
}
|
|
46
54
|
};
|
|
47
55
|
}
|
|
@@ -219,6 +227,22 @@ function canonicalPairKey(signatureA, signatureB) {
|
|
|
219
227
|
return [signatureA, signatureB].toSorted().join("|");
|
|
220
228
|
}
|
|
221
229
|
/**
|
|
230
|
+
* Count consecutive error results for a specific tool, walking backward from
|
|
231
|
+
* the most recent call. A success or a call to a different tool resets the streak.
|
|
232
|
+
* Only counts entries that have been resolved (have a resultHash or isError flag).
|
|
233
|
+
*/
|
|
234
|
+
function getConsecutiveFailureStreak(history, toolName) {
|
|
235
|
+
let count = 0;
|
|
236
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
237
|
+
const entry = history[i];
|
|
238
|
+
if (entry.toolName !== toolName) break;
|
|
239
|
+
if (entry.resultHash === void 0 && entry.isError === void 0) break;
|
|
240
|
+
if (!entry.isError) break;
|
|
241
|
+
count++;
|
|
242
|
+
}
|
|
243
|
+
return count;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
222
246
|
* Detect if an agent is stuck in a repetitive tool call loop.
|
|
223
247
|
* Checks if the same tool+params combination has been called excessively.
|
|
224
248
|
*/
|
|
@@ -231,6 +255,31 @@ function detectToolCallLoop(state, toolName, params, config) {
|
|
|
231
255
|
const noProgressStreak = noProgress.count;
|
|
232
256
|
const knownPollTool = isKnownPollToolCall(toolName, params);
|
|
233
257
|
const pingPong = getPingPongStreak(history, currentHash);
|
|
258
|
+
if (resolvedConfig.detectors.consecutiveFailure) {
|
|
259
|
+
const failureStreak = getConsecutiveFailureStreak(history, toolName);
|
|
260
|
+
if (failureStreak >= resolvedConfig.consecutiveFailureCriticalThreshold) {
|
|
261
|
+
log.error(`Consecutive failure circuit breaker: ${toolName} failed ${failureStreak} times in a row`);
|
|
262
|
+
return {
|
|
263
|
+
stuck: true,
|
|
264
|
+
level: "critical",
|
|
265
|
+
detector: "consecutive_failure",
|
|
266
|
+
count: failureStreak,
|
|
267
|
+
message: `CRITICAL: ${toolName} has failed ${failureStreak} consecutive times. Stop calling this tool. Explain to the user what you were trying to do and why it failed.`,
|
|
268
|
+
warningKey: `consecutive-failure:${toolName}`
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
if (failureStreak >= resolvedConfig.consecutiveFailureWarningThreshold) {
|
|
272
|
+
log.warn(`Consecutive failure warning: ${toolName} failed ${failureStreak} times in a row`);
|
|
273
|
+
return {
|
|
274
|
+
stuck: true,
|
|
275
|
+
level: "warning",
|
|
276
|
+
detector: "consecutive_failure",
|
|
277
|
+
count: failureStreak,
|
|
278
|
+
message: `WARNING: You have failed to call ${toolName} ${failureStreak} times consecutively. Stop retrying and explain to the user what you were trying to do. The tool arguments may contain invalid syntax from model control tokens.`,
|
|
279
|
+
warningKey: `consecutive-failure:${toolName}`
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
}
|
|
234
283
|
if (noProgressStreak >= resolvedConfig.globalCircuitBreakerThreshold) {
|
|
235
284
|
log.error(`Global circuit breaker triggered: ${toolName} repeated ${noProgressStreak} times with no progress`);
|
|
236
285
|
return {
|
|
@@ -335,6 +384,7 @@ function recordToolCallOutcome(state, params) {
|
|
|
335
384
|
if (call.toolName !== params.toolName || call.argsHash !== argsHash) continue;
|
|
336
385
|
if (call.resultHash !== void 0) continue;
|
|
337
386
|
call.resultHash = resultHash;
|
|
387
|
+
call.isError = params.error !== void 0;
|
|
338
388
|
matched = true;
|
|
339
389
|
break;
|
|
340
390
|
}
|
|
@@ -9,6 +9,8 @@ const TOOL_CALL_HISTORY_SIZE = 30;
|
|
|
9
9
|
const WARNING_THRESHOLD = 10;
|
|
10
10
|
const CRITICAL_THRESHOLD = 20;
|
|
11
11
|
const GLOBAL_CIRCUIT_BREAKER_THRESHOLD = 30;
|
|
12
|
+
const CONSECUTIVE_FAILURE_WARNING_THRESHOLD = 3;
|
|
13
|
+
const CONSECUTIVE_FAILURE_CRITICAL_THRESHOLD = 5;
|
|
12
14
|
const DEFAULT_LOOP_DETECTION_CONFIG = {
|
|
13
15
|
enabled: false,
|
|
14
16
|
historySize: TOOL_CALL_HISTORY_SIZE,
|
|
@@ -18,8 +20,11 @@ const DEFAULT_LOOP_DETECTION_CONFIG = {
|
|
|
18
20
|
detectors: {
|
|
19
21
|
genericRepeat: true,
|
|
20
22
|
knownPollNoProgress: true,
|
|
21
|
-
pingPong: true
|
|
22
|
-
|
|
23
|
+
pingPong: true,
|
|
24
|
+
consecutiveFailure: true
|
|
25
|
+
},
|
|
26
|
+
consecutiveFailureWarningThreshold: CONSECUTIVE_FAILURE_WARNING_THRESHOLD,
|
|
27
|
+
consecutiveFailureCriticalThreshold: CONSECUTIVE_FAILURE_CRITICAL_THRESHOLD
|
|
23
28
|
};
|
|
24
29
|
function asPositiveInt(value, fallback) {
|
|
25
30
|
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) return fallback;
|
|
@@ -37,10 +42,13 @@ function resolveLoopDetectionConfig(config) {
|
|
|
37
42
|
warningThreshold,
|
|
38
43
|
criticalThreshold,
|
|
39
44
|
globalCircuitBreakerThreshold,
|
|
45
|
+
consecutiveFailureWarningThreshold: asPositiveInt(config?.consecutiveFailureWarningThreshold, DEFAULT_LOOP_DETECTION_CONFIG.consecutiveFailureWarningThreshold),
|
|
46
|
+
consecutiveFailureCriticalThreshold: asPositiveInt(config?.consecutiveFailureCriticalThreshold, DEFAULT_LOOP_DETECTION_CONFIG.consecutiveFailureCriticalThreshold),
|
|
40
47
|
detectors: {
|
|
41
48
|
genericRepeat: config?.detectors?.genericRepeat ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.genericRepeat,
|
|
42
49
|
knownPollNoProgress: config?.detectors?.knownPollNoProgress ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.knownPollNoProgress,
|
|
43
|
-
pingPong: config?.detectors?.pingPong ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.pingPong
|
|
50
|
+
pingPong: config?.detectors?.pingPong ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.pingPong,
|
|
51
|
+
consecutiveFailure: (config?.detectors)?.consecutiveFailure ?? DEFAULT_LOOP_DETECTION_CONFIG.detectors.consecutiveFailure
|
|
44
52
|
}
|
|
45
53
|
};
|
|
46
54
|
}
|
|
@@ -218,6 +226,22 @@ function canonicalPairKey(signatureA, signatureB) {
|
|
|
218
226
|
return [signatureA, signatureB].toSorted().join("|");
|
|
219
227
|
}
|
|
220
228
|
/**
|
|
229
|
+
* Count consecutive error results for a specific tool, walking backward from
|
|
230
|
+
* the most recent call. A success or a call to a different tool resets the streak.
|
|
231
|
+
* Only counts entries that have been resolved (have a resultHash or isError flag).
|
|
232
|
+
*/
|
|
233
|
+
function getConsecutiveFailureStreak(history, toolName) {
|
|
234
|
+
let count = 0;
|
|
235
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
236
|
+
const entry = history[i];
|
|
237
|
+
if (entry.toolName !== toolName) break;
|
|
238
|
+
if (entry.resultHash === void 0 && entry.isError === void 0) break;
|
|
239
|
+
if (!entry.isError) break;
|
|
240
|
+
count++;
|
|
241
|
+
}
|
|
242
|
+
return count;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
221
245
|
* Detect if an agent is stuck in a repetitive tool call loop.
|
|
222
246
|
* Checks if the same tool+params combination has been called excessively.
|
|
223
247
|
*/
|
|
@@ -230,6 +254,31 @@ function detectToolCallLoop(state, toolName, params, config) {
|
|
|
230
254
|
const noProgressStreak = noProgress.count;
|
|
231
255
|
const knownPollTool = isKnownPollToolCall(toolName, params);
|
|
232
256
|
const pingPong = getPingPongStreak(history, currentHash);
|
|
257
|
+
if (resolvedConfig.detectors.consecutiveFailure) {
|
|
258
|
+
const failureStreak = getConsecutiveFailureStreak(history, toolName);
|
|
259
|
+
if (failureStreak >= resolvedConfig.consecutiveFailureCriticalThreshold) {
|
|
260
|
+
log.error(`Consecutive failure circuit breaker: ${toolName} failed ${failureStreak} times in a row`);
|
|
261
|
+
return {
|
|
262
|
+
stuck: true,
|
|
263
|
+
level: "critical",
|
|
264
|
+
detector: "consecutive_failure",
|
|
265
|
+
count: failureStreak,
|
|
266
|
+
message: `CRITICAL: ${toolName} has failed ${failureStreak} consecutive times. Stop calling this tool. Explain to the user what you were trying to do and why it failed.`,
|
|
267
|
+
warningKey: `consecutive-failure:${toolName}`
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
if (failureStreak >= resolvedConfig.consecutiveFailureWarningThreshold) {
|
|
271
|
+
log.warn(`Consecutive failure warning: ${toolName} failed ${failureStreak} times in a row`);
|
|
272
|
+
return {
|
|
273
|
+
stuck: true,
|
|
274
|
+
level: "warning",
|
|
275
|
+
detector: "consecutive_failure",
|
|
276
|
+
count: failureStreak,
|
|
277
|
+
message: `WARNING: You have failed to call ${toolName} ${failureStreak} times consecutively. Stop retrying and explain to the user what you were trying to do. The tool arguments may contain invalid syntax from model control tokens.`,
|
|
278
|
+
warningKey: `consecutive-failure:${toolName}`
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
}
|
|
233
282
|
if (noProgressStreak >= resolvedConfig.globalCircuitBreakerThreshold) {
|
|
234
283
|
log.error(`Global circuit breaker triggered: ${toolName} repeated ${noProgressStreak} times with no progress`);
|
|
235
284
|
return {
|
|
@@ -334,6 +383,7 @@ function recordToolCallOutcome(state, params) {
|
|
|
334
383
|
if (call.toolName !== params.toolName || call.argsHash !== argsHash) continue;
|
|
335
384
|
if (call.resultHash !== void 0) continue;
|
|
336
385
|
call.resultHash = resultHash;
|
|
386
|
+
call.isError = params.error !== void 0;
|
|
337
387
|
matched = true;
|
|
338
388
|
break;
|
|
339
389
|
}
|