@miller-tech/uap 1.118.2 → 1.119.1
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/.tsbuildinfo +1 -1
- package/dist/cli/handsfree.d.ts.map +1 -1
- package/dist/cli/handsfree.js +39 -3
- package/dist/cli/handsfree.js.map +1 -1
- package/dist/delivery/handsfree-config.d.ts.map +1 -1
- package/dist/delivery/handsfree-config.js +2 -0
- package/dist/delivery/handsfree-config.js.map +1 -1
- package/dist/delivery/persistence-profile.d.ts +9 -0
- package/dist/delivery/persistence-profile.d.ts.map +1 -1
- package/dist/delivery/persistence-profile.js.map +1 -1
- package/package.json +1 -1
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
- package/tools/agents/scripts/anthropic_proxy.py +168 -1
- package/tools/agents/tests/test_deferral_break.py +177 -0
- package/tools/agents/tests/test_stuck_break_reattach.py +67 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handsfree.d.ts","sourceRoot":"","sources":["../../src/cli/handsfree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"handsfree.d.ts","sourceRoot":"","sources":["../../src/cli/handsfree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAiEH;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,OAAO,GACtB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAgFvD;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CA8Jf"}
|
package/dist/cli/handsfree.js
CHANGED
|
@@ -22,6 +22,8 @@ import { findUapConfigPath, modifyUapConfig } from '../utils/config-loader.js';
|
|
|
22
22
|
import { loadLedger, initLedger, markItem, remainingItems, isComplete, formatRemaining, progress, syncLedgerFromTodos, } from '../delivery/completion-ledger.js';
|
|
23
23
|
import { loadPersistenceConfig, resolveActiveModel } from '../delivery/handsfree-config.js';
|
|
24
24
|
import { resolvePersistenceProfile } from '../delivery/persistence-profile.js';
|
|
25
|
+
/** Fix C: hard cap on pre-ledger nudges so a planning stall can never wedge. */
|
|
26
|
+
const PRE_LEDGER_MAX = Math.max(0, Number(process.env.UAP_HANDSFREE_PRELEDGER_MAX ?? 1));
|
|
25
27
|
function statePath(cwd) {
|
|
26
28
|
return join(cwd, '.uap', 'handsfree-state.json');
|
|
27
29
|
}
|
|
@@ -44,7 +46,7 @@ function saveState(cwd, st) {
|
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
function resetState(cwd) {
|
|
47
|
-
saveState(cwd, { blocks: 0, lastRemaining: Number.MAX_SAFE_INTEGER });
|
|
49
|
+
saveState(cwd, { blocks: 0, lastRemaining: Number.MAX_SAFE_INTEGER, preLedgerBlocks: 0 });
|
|
48
50
|
}
|
|
49
51
|
async function readStdin() {
|
|
50
52
|
if (process.stdin.isTTY)
|
|
@@ -70,8 +72,42 @@ export function decideStopCheck(cwd, stopHookActive) {
|
|
|
70
72
|
if (stopHookActive)
|
|
71
73
|
return { block: false, message: 'stop_hook_active — never re-block' };
|
|
72
74
|
const ledger = loadLedger(cwd);
|
|
73
|
-
if (!ledger)
|
|
74
|
-
|
|
75
|
+
if (!ledger) {
|
|
76
|
+
// Fix C: pre-ledger safety net. A LOCAL model (qwen) can defer at the
|
|
77
|
+
// PLANNING stage — "I need more exploration cycles to complete the plan" —
|
|
78
|
+
// and end the turn before ever writing a TodoWrite plan, so no ledger exists
|
|
79
|
+
// and the build silently stops. Nudge it (bounded to PRE_LEDGER_MAX,
|
|
80
|
+
// anti-wedge) to lay out the plan and start. Scoped to the LOCAL family only:
|
|
81
|
+
// it is the one that emits these deferrals and drives hands-free builds here.
|
|
82
|
+
// Frontier models keep their post-ledger blocker + intrinsic persistence, and
|
|
83
|
+
// Fable is trusted — so a casual (non-build) frontier/Fable session is never
|
|
84
|
+
// pre-ledger blocked. Disable via config / UAP_HANDSFREE_PRELEDGER=0.
|
|
85
|
+
const preProfile = resolvePersistenceProfile(resolveActiveModel(cwd), cfg);
|
|
86
|
+
const nudgeOn = cfg.preLedgerNudge !== false && PRE_LEDGER_MAX > 0;
|
|
87
|
+
const driven = preProfile.stopHookBlocks && preProfile.injectAutonomy && preProfile.family === 'local';
|
|
88
|
+
if (!nudgeOn || !driven) {
|
|
89
|
+
return { block: false, message: 'no active build ledger' };
|
|
90
|
+
}
|
|
91
|
+
const st0 = loadState(cwd);
|
|
92
|
+
const pre = st0.preLedgerBlocks ?? 0;
|
|
93
|
+
if (pre >= PRE_LEDGER_MAX) {
|
|
94
|
+
resetState(cwd);
|
|
95
|
+
return {
|
|
96
|
+
block: false,
|
|
97
|
+
giveUp: true,
|
|
98
|
+
message: `hands-free pre-ledger nudge exhausted after ${pre} attempt(s) — no ` +
|
|
99
|
+
'build plan was started; allowing stop. Consider escalating the model.',
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
saveState(cwd, { ...st0, preLedgerBlocks: pre + 1 });
|
|
103
|
+
return {
|
|
104
|
+
block: true,
|
|
105
|
+
message: 'NOT DONE — hands-free is on but no build plan exists yet. Do NOT stop to ' +
|
|
106
|
+
'ask for more cycles or permission. Lay out the full build as a TodoWrite ' +
|
|
107
|
+
'plan now (it auto-creates the completion ledger) and start building the ' +
|
|
108
|
+
'first item this turn.',
|
|
109
|
+
};
|
|
110
|
+
}
|
|
75
111
|
if (isComplete(ledger)) {
|
|
76
112
|
resetState(cwd);
|
|
77
113
|
return { block: false, message: 'build complete — all ledger items done' };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handsfree.js","sourceRoot":"","sources":["../../src/cli/handsfree.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"handsfree.js","sourceRoot":"","sources":["../../src/cli/handsfree.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handsfree-config.d.ts","sourceRoot":"","sources":["../../src/delivery/handsfree-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,mFAAmF;AACnF,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAsB,GAAG,iBAAiB,
|
|
1
|
+
{"version":3,"file":"handsfree-config.d.ts","sourceRoot":"","sources":["../../src/delivery/handsfree-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,mFAAmF;AACnF,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAsB,GAAG,iBAAiB,CAiBpF;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAWtE"}
|
|
@@ -22,6 +22,8 @@ export function loadPersistenceConfig(cwd = process.cwd()) {
|
|
|
22
22
|
enabled: hf.enabled !== false && process.env.UAP_HANDSFREE !== '0',
|
|
23
23
|
...(envIntensity ? { intensity: envIntensity } : hf.intensity ? { intensity: hf.intensity } : {}),
|
|
24
24
|
...(hf.overrides ? { overrides: hf.overrides } : {}),
|
|
25
|
+
// Fix C: pre-ledger nudge, default ON; disable via config or UAP_HANDSFREE_PRELEDGER=0.
|
|
26
|
+
preLedgerNudge: hf.preLedgerNudge !== false && process.env.UAP_HANDSFREE_PRELEDGER !== '0',
|
|
25
27
|
};
|
|
26
28
|
}
|
|
27
29
|
/** The model doing the work — env override, else the executor role, else unknown. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handsfree-config.js","sourceRoot":"","sources":["../../src/delivery/handsfree-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAG7D,mFAAmF;AACnF,MAAM,UAAU,qBAAqB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAC/D,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,GAAG;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACjE,IAAI,GAAG,GAA4B,EAAE,CAAC;IACtC,IAAI,CAAC;QACH,GAAG,GAAI,gBAAgB,CAAC,GAAG,CAA6B,IAAI,EAAE,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,GAAG,EAAE,CAAC;IACX,CAAC;IACD,MAAM,EAAE,GAAI,GAAG,CAAC,SAA2C,IAAI,EAAE,CAAC;IAClE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAqE,CAAC;IACvG,OAAO;QACL,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,GAAG;QAClE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjG,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"handsfree-config.js","sourceRoot":"","sources":["../../src/delivery/handsfree-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAG7D,mFAAmF;AACnF,MAAM,UAAU,qBAAqB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAC/D,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,GAAG;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACjE,IAAI,GAAG,GAA4B,EAAE,CAAC;IACtC,IAAI,CAAC;QACH,GAAG,GAAI,gBAAgB,CAAC,GAAG,CAA6B,IAAI,EAAE,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,GAAG,EAAE,CAAC;IACX,CAAC;IACD,MAAM,EAAE,GAAI,GAAG,CAAC,SAA2C,IAAI,EAAE,CAAC;IAClE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAqE,CAAC;IACvG,OAAO;QACL,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,GAAG;QAClE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjG,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,wFAAwF;QACxF,cAAc,EAAE,EAAE,CAAC,cAAc,KAAK,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,GAAG;KAC3F,CAAC;AACJ,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,kBAAkB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAC5D,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACtE,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IACpE,IAAI,CAAC;QACH,MAAM,GAAG,GAAI,gBAAgB,CAAC,GAAG,CAA6B,IAAI,EAAE,CAAC;QACrE,MAAM,EAAE,GAAG,GAAG,CAAC,UAA2D,CAAC;QAC3E,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ;YAAE,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;IACpB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -37,6 +37,15 @@ export interface PersistenceConfig {
|
|
|
37
37
|
intensity?: PersistenceIntensity;
|
|
38
38
|
/** per-model overrides keyed by model id substring. */
|
|
39
39
|
overrides?: Record<string, Partial<PersistenceProfile>>;
|
|
40
|
+
/**
|
|
41
|
+
* Fix C: pre-ledger safety net. When hands-free is ON but NO completion
|
|
42
|
+
* ledger exists yet, a driven model (local/frontier) can defer at the
|
|
43
|
+
* planning stage — "I need more exploration cycles to complete the plan" —
|
|
44
|
+
* and end the turn before ever writing a plan, so nothing blocks the stop.
|
|
45
|
+
* When enabled, the Stop hook nudges once (bounded, anti-wedge) to lay out
|
|
46
|
+
* the plan and start building. Default ON; only ever nudges driven models.
|
|
47
|
+
*/
|
|
48
|
+
preLedgerNudge?: boolean;
|
|
40
49
|
}
|
|
41
50
|
/**
|
|
42
51
|
* Resolve the effective persistence profile for a model. `off` when hands-free
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence-profile.d.ts","sourceRoot":"","sources":["../../src/delivery/persistence-profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,OAAO,GAAG,UAAU,GAAG,YAAY,CAAC;AAC/E,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;AAErE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,oBAAoB,CAAC;IAChC,iFAAiF;IACjF,cAAc,EAAE,OAAO,CAAC;IACxB,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,eAAe,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,cAAc,EAAE,OAAO,CAAC;CACzB;AAmBD,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAMhE;AAeD,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sDAAsD;IACtD,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"persistence-profile.d.ts","sourceRoot":"","sources":["../../src/delivery/persistence-profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,OAAO,GAAG,UAAU,GAAG,YAAY,CAAC;AAC/E,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;AAErE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,oBAAoB,CAAC;IAChC,iFAAiF;IACjF,cAAc,EAAE,OAAO,CAAC;IACxB,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,eAAe,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,cAAc,EAAE,OAAO,CAAC;CACzB;AAmBD,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAMhE;AAeD,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sDAAsD;IACtD,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACxD;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,GAAG,GAAE,iBAAsB,GAC1B,kBAAkB,CAqBpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence-profile.js","sourceRoot":"","sources":["../../src/delivery/persistence-profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAmBH,MAAM,QAAQ,GAA+F;IAC3G,qEAAqE;IACrE,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE;IAC5G,kEAAkE;IAClE,QAAQ,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE;IACjH,gFAAgF;IAChF,UAAU,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE;CACtH,CAAC;AAEF,MAAM,WAAW,GAAiD;IAChE,SAAS,EAAE,KAAK;IAChB,cAAc,EAAE,KAAK;IACrB,SAAS,EAAE,CAAC;IACZ,eAAe,EAAE,CAAC;IAClB,cAAc,EAAE,KAAK;CACtB,CAAC;AAEF,wEAAwE;AACxE,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACxC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IACxC,IAAI,wEAAwE,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,OAAO,CAAC;IACrG,IAAI,gDAAgD,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,UAAU,CAAC;IAChF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,eAAe,CAAC,MAAmB;IAC1C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,OAAO;YACV,OAAO,YAAY,CAAC;QACtB,KAAK,UAAU;YACb,OAAO,UAAU,CAAC;QACpB;YACE,OAAO,UAAU,CAAC;IACtB,CAAC;AACH,CAAC;
|
|
1
|
+
{"version":3,"file":"persistence-profile.js","sourceRoot":"","sources":["../../src/delivery/persistence-profile.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -231,6 +231,48 @@ _RATE_LIMITED_API_RE = re.compile(r"api\.github\.com", re.IGNORECASE)
|
|
|
231
231
|
PROXY_STUCK_TEXT_THRESHOLD = int(os.environ.get("PROXY_STUCK_TEXT_THRESHOLD", "2"))
|
|
232
232
|
PROXY_STUCK_API_THRESHOLD = int(os.environ.get("PROXY_STUCK_API_THRESHOLD", "3"))
|
|
233
233
|
|
|
234
|
+
# ---------------------------------------------------------------------------
|
|
235
|
+
# DEFERRAL-BREAK guardrail (Fix A): a model can end a turn with plain prose that
|
|
236
|
+
# DEFERS the work instead of doing it -- "I need more exploration cycles to
|
|
237
|
+
# complete the plan", "let me continue exploring", "I'll need a few more passes"
|
|
238
|
+
# -- with NO tool call. This is a turn-ending *capitulation*, not a loop
|
|
239
|
+
# admission, so STUCK-BREAK's phrase list never matches it; and because it is a
|
|
240
|
+
# no-tool turn, recon-convergence never advanced its streak either (that counter
|
|
241
|
+
# only moves on turns that emit tool calls). The stall therefore slips through
|
|
242
|
+
# every guardrail and silently halts a hands-free build (observed live: a run of
|
|
243
|
+
# back-to-back session-ends with "Code changed: false"). When a no-tool turn
|
|
244
|
+
# matches the deferral phrasing PROXY_DEFERRAL_THRESHOLD times in a row, the
|
|
245
|
+
# proxy forces the NEXT turn to take a concrete action: tool_choice=required plus
|
|
246
|
+
# a firm "continue autonomously, you will not be re-prompted" directive. This is
|
|
247
|
+
# the INVERSE of STUCK-BREAK (which releases to a prose exit) -- a deferral means
|
|
248
|
+
# work REMAINS, so we drive an action rather than allow a stop. Default on;
|
|
249
|
+
# PROXY_DEFERRAL_BREAK=off to disable.
|
|
250
|
+
PROXY_DEFERRAL_BREAK = os.environ.get("PROXY_DEFERRAL_BREAK", "on").lower() not in {
|
|
251
|
+
"0", "false", "off", "no",
|
|
252
|
+
}
|
|
253
|
+
# Turn-ending deferral/capitulation phrases (lowercased match). Deliberately
|
|
254
|
+
# narrow -- it must catch "I need more exploration cycles to complete the plan"
|
|
255
|
+
# and close kin, WITHOUT firing on ordinary forward-looking narration that is
|
|
256
|
+
# actually followed by a tool call (the no-tool-turn gate handles that too).
|
|
257
|
+
_DEFERRAL_PHRASE_RE = re.compile(
|
|
258
|
+
r"need (?:more|additional|further|extra) (?:exploration |investigation |research )?"
|
|
259
|
+
r"(?:cycles|passes|turns|iterations|rounds)"
|
|
260
|
+
r"|more (?:exploration |investigation )?(?:cycles|passes|iterations) "
|
|
261
|
+
r"(?:to|are needed|is needed|required|before)"
|
|
262
|
+
r"|to (?:complete|finish|continue) (?:the|my) (?:plan|exploration|investigation)"
|
|
263
|
+
r"|(?:let me|allow me to|i'?ll|i will|i need to|i'?d need to|"
|
|
264
|
+
r"we(?:'?ll| will| need to)) (?:keep|continue) "
|
|
265
|
+
r"(?:exploring|investigating|researching|working through|going)"
|
|
266
|
+
r"|(?:once|after) i(?:'ve| have)? (?:explored|investigated|gathered|reviewed) "
|
|
267
|
+
r"(?:more|additional|further|enough)"
|
|
268
|
+
r"|need to (?:gather|do|run|perform) (?:more|additional|further) "
|
|
269
|
+
r"(?:exploration|research|investigation|analysis)",
|
|
270
|
+
re.IGNORECASE,
|
|
271
|
+
)
|
|
272
|
+
# Fire on the FIRST deferral by default: a single "I need more cycles" no-tool
|
|
273
|
+
# turn IS the halt, unlike STUCK-BREAK which waits for a sustained loop.
|
|
274
|
+
PROXY_DEFERRAL_THRESHOLD = int(os.environ.get("PROXY_DEFERRAL_THRESHOLD", "1"))
|
|
275
|
+
|
|
234
276
|
PROXY_TOOL_STATE_MACHINE = os.environ.get(
|
|
235
277
|
"PROXY_TOOL_STATE_MACHINE", "on"
|
|
236
278
|
).lower() not in {
|
|
@@ -1252,6 +1294,8 @@ class SessionMonitor:
|
|
|
1252
1294
|
self_stuck_streak: int = 0 # consecutive assistant texts self-reporting a loop
|
|
1253
1295
|
rate_limited_api_streak: int = 0 # consecutive tool calls hitting a rate-limited API host
|
|
1254
1296
|
stuck_break_fires: int = 0 # monotonic count of forced stuck-breaks
|
|
1297
|
+
deferral_streak: int = 0 # consecutive no-tool turns deferring the work (Fix A)
|
|
1298
|
+
deferral_break_fires: int = 0 # monotonic count of forced deferral-breaks (Fix A)
|
|
1255
1299
|
tool_starvation_streak: int = 0 # Consecutive forced turns with no tool_calls produced
|
|
1256
1300
|
malformed_tool_streak: int = 0 # consecutive malformed pseudo tool payloads
|
|
1257
1301
|
invalid_tool_call_streak: int = 0 # consecutive invalid tool arg payloads
|
|
@@ -1521,6 +1565,50 @@ class SessionMonitor:
|
|
|
1521
1565
|
return True, f"rate-limited-API retries x{self.rate_limited_api_streak}"
|
|
1522
1566
|
return False, ""
|
|
1523
1567
|
|
|
1568
|
+
def note_deferral_signal(self, text: str, had_tool_call: bool) -> None:
|
|
1569
|
+
"""Track a turn-ending deferral/capitulation stall (Fix A): a plain-text
|
|
1570
|
+
assistant turn with NO tool call that asks for more cycles / more
|
|
1571
|
+
exploration / permission to keep going instead of taking the next build
|
|
1572
|
+
action. Only a no-tool turn whose text matches the deferral phrasing
|
|
1573
|
+
increments the streak; ANY tool call or non-matching text resets it, so a
|
|
1574
|
+
model that actually acts (or writes a normal summary) is never flagged."""
|
|
1575
|
+
if not PROXY_DEFERRAL_BREAK:
|
|
1576
|
+
self.deferral_streak = 0
|
|
1577
|
+
return
|
|
1578
|
+
if (not had_tool_call) and text and _DEFERRAL_PHRASE_RE.search(text):
|
|
1579
|
+
self.deferral_streak += 1
|
|
1580
|
+
else:
|
|
1581
|
+
self.deferral_streak = 0
|
|
1582
|
+
|
|
1583
|
+
def should_force_deferral_break(self) -> tuple[bool, str]:
|
|
1584
|
+
"""True + reason when a deferral-break should be forced this turn."""
|
|
1585
|
+
if not PROXY_DEFERRAL_BREAK:
|
|
1586
|
+
return False, ""
|
|
1587
|
+
if self.deferral_streak >= PROXY_DEFERRAL_THRESHOLD:
|
|
1588
|
+
return True, f"deferral/plan-capitulation x{self.deferral_streak}"
|
|
1589
|
+
return False, ""
|
|
1590
|
+
|
|
1591
|
+
def recon_convergence_pending(self) -> bool:
|
|
1592
|
+
"""True when recon-convergence will own this turn. DEFERRAL-BREAK yields
|
|
1593
|
+
to it (as it does to STUCK-BREAK) so the two guards never emit
|
|
1594
|
+
contradictory tool_choice/directives in the same request. Fix B makes
|
|
1595
|
+
their triggers climb in lockstep on prose-only stalls, so without this
|
|
1596
|
+
yield a deep prose stall could trip both and undo recon's terminal tier
|
|
1597
|
+
(which may strip tools and force a plain-text summary that ends the task)."""
|
|
1598
|
+
return (
|
|
1599
|
+
PROXY_RECON_CONVERGENCE_THRESHOLD > 0
|
|
1600
|
+
and self.consecutive_no_write_turns >= PROXY_RECON_CONVERGENCE_THRESHOLD
|
|
1601
|
+
)
|
|
1602
|
+
|
|
1603
|
+
def note_no_tool_turn(self) -> None:
|
|
1604
|
+
"""Fix B: a plain-text assistant turn with no tool call is still a
|
|
1605
|
+
non-write turn, so advance the recon-convergence streak. The old code
|
|
1606
|
+
only moved `consecutive_no_write_turns` on turns that emitted tool calls,
|
|
1607
|
+
so a model that stalls in prose (no tools at all) froze the counter and
|
|
1608
|
+
never escalated to the recon-convergence directive. Resets, like the
|
|
1609
|
+
tool-turn path, whenever a write tool is later emitted."""
|
|
1610
|
+
self.consecutive_no_write_turns += 1
|
|
1611
|
+
|
|
1524
1612
|
def has_duplicate_read_target(self, threshold: int = 2) -> tuple[bool, str]:
|
|
1525
1613
|
"""Check if any read-only tool has re-read the same target >= threshold times.
|
|
1526
1614
|
|
|
@@ -4253,14 +4341,71 @@ def _maybe_inject_stuck_break(openai_body: dict, monitor: "SessionMonitor") -> N
|
|
|
4253
4341
|
"operator the single blocking question in one sentence. Take a DIFFERENT "
|
|
4254
4342
|
"action now."
|
|
4255
4343
|
)
|
|
4256
|
-
msgs = openai_body.get("messages")
|
|
4344
|
+
msgs = openai_body.get("messages")
|
|
4345
|
+
if not isinstance(msgs, list):
|
|
4346
|
+
msgs = []
|
|
4257
4347
|
if msgs and msgs[0].get("role") == "system":
|
|
4258
4348
|
msgs[0]["content"] = (msgs[0].get("content") or "") + directive
|
|
4259
4349
|
else:
|
|
4260
4350
|
msgs.insert(0, {"role": "system", "content": directive.strip()})
|
|
4351
|
+
openai_body["messages"] = msgs # reattach in case messages was empty/absent
|
|
4261
4352
|
logger.warning("STUCK-BREAK: forced terminal turn (%s, fires=%d)", reason, monitor.stuck_break_fires)
|
|
4262
4353
|
|
|
4263
4354
|
|
|
4355
|
+
def _maybe_inject_deferral_break(openai_body: dict, monitor: "SessionMonitor") -> None:
|
|
4356
|
+
"""Convert a turn-ending deferral into forward motion (Fix A).
|
|
4357
|
+
|
|
4358
|
+
The model ended a turn with prose that DEFERS the work -- "I need more
|
|
4359
|
+
exploration cycles to complete the plan", "let me continue exploring" -- with
|
|
4360
|
+
no tool call, instead of taking the next build step. That stall is invisible
|
|
4361
|
+
to STUCK-BREAK (not a loop-admission phrase) and to recon-convergence (a
|
|
4362
|
+
no-tool turn never advanced its streak), so it silently ends a hands-free
|
|
4363
|
+
build. This forces the NEXT turn to ACT: it forces tool_choice and tells the
|
|
4364
|
+
model it will not be re-prompted. The INVERSE of STUCK-BREAK, which releases
|
|
4365
|
+
to a prose exit -- a deferral means work REMAINS.
|
|
4366
|
+
"""
|
|
4367
|
+
should, reason = monitor.should_force_deferral_break()
|
|
4368
|
+
if not should:
|
|
4369
|
+
return
|
|
4370
|
+
# STUCK-BREAK (a self-aware loop wanting a prose exit) is the more urgent
|
|
4371
|
+
# signal; if it will fire this turn, yield to it rather than force a tool.
|
|
4372
|
+
stuck, _ = monitor.should_force_stuck_break()
|
|
4373
|
+
if stuck:
|
|
4374
|
+
return
|
|
4375
|
+
# Also yield to recon-convergence: once the no-write streak is deep enough
|
|
4376
|
+
# for recon to own the turn (it may strip tools / force a terminal summary),
|
|
4377
|
+
# a "keep building" deferral directive would directly contradict it.
|
|
4378
|
+
if monitor.recon_convergence_pending():
|
|
4379
|
+
return
|
|
4380
|
+
# Only force an action if there are tools to call and the choice is not
|
|
4381
|
+
# already pinned to a specific tool by an earlier guard.
|
|
4382
|
+
has_tools = bool(openai_body.get("tools"))
|
|
4383
|
+
if has_tools and openai_body.get("tool_choice") in (None, "auto"):
|
|
4384
|
+
openai_body["tool_choice"] = "required"
|
|
4385
|
+
monitor.deferral_break_fires += 1
|
|
4386
|
+
directive = (
|
|
4387
|
+
"\n\nCONTINUE AUTONOMOUSLY (" + reason + "). You do NOT need more "
|
|
4388
|
+
"exploration cycles, another pass, or permission, and you will NOT be "
|
|
4389
|
+
"re-prompted to keep going. Do the next concrete step of the plan NOW: "
|
|
4390
|
+
"pick the next un-built file/component and create it with the write tool "
|
|
4391
|
+
"(or run the next required command). Never end a turn with only a plan, a "
|
|
4392
|
+
"status note, or a request for more cycles -- take the action this turn."
|
|
4393
|
+
)
|
|
4394
|
+
msgs = openai_body.get("messages")
|
|
4395
|
+
if not isinstance(msgs, list):
|
|
4396
|
+
msgs = []
|
|
4397
|
+
if msgs and msgs[0].get("role") == "system":
|
|
4398
|
+
msgs[0]["content"] = (msgs[0].get("content") or "") + directive
|
|
4399
|
+
else:
|
|
4400
|
+
msgs.insert(0, {"role": "system", "content": directive.strip()})
|
|
4401
|
+
openai_body["messages"] = msgs # reattach in case messages was empty/absent
|
|
4402
|
+
logger.warning(
|
|
4403
|
+
"DEFERRAL-BREAK: forced action turn (%s, fires=%d)",
|
|
4404
|
+
reason,
|
|
4405
|
+
monitor.deferral_break_fires,
|
|
4406
|
+
)
|
|
4407
|
+
|
|
4408
|
+
|
|
4264
4409
|
def _maybe_inject_recon_convergence(
|
|
4265
4410
|
openai_body: dict,
|
|
4266
4411
|
monitor: "SessionMonitor",
|
|
@@ -5041,6 +5186,10 @@ def build_openai_request(
|
|
|
5041
5186
|
|
|
5042
5187
|
_maybe_inject_stuck_break(openai_body, monitor)
|
|
5043
5188
|
|
|
5189
|
+
# DEFERRAL-BREAK (Fix A): after stuck-break, drive a no-tool deferral turn
|
|
5190
|
+
# into a concrete action. Runs last so it can yield to stuck-break.
|
|
5191
|
+
_maybe_inject_deferral_break(openai_body, monitor)
|
|
5192
|
+
|
|
5044
5193
|
_apply_thinking_grammar(openai_body)
|
|
5045
5194
|
|
|
5046
5195
|
_apply_json_response_grammar(openai_body, anthropic_body)
|
|
@@ -5172,12 +5321,21 @@ def _record_last_assistant_tool_calls(
|
|
|
5172
5321
|
messages = anthropic_body.get("messages", [])
|
|
5173
5322
|
tool_fingerprints = []
|
|
5174
5323
|
tool_targets: dict[str, str] = {}
|
|
5324
|
+
assistant_had_text = False # Fix B: did the last assistant turn emit prose?
|
|
5175
5325
|
for msg in reversed(messages):
|
|
5176
5326
|
if msg.get("role") != "assistant":
|
|
5177
5327
|
continue
|
|
5178
5328
|
content = msg.get("content")
|
|
5329
|
+
if isinstance(content, str) and content.strip():
|
|
5330
|
+
assistant_had_text = True
|
|
5179
5331
|
if isinstance(content, list):
|
|
5180
5332
|
for block in content:
|
|
5333
|
+
if (
|
|
5334
|
+
isinstance(block, dict)
|
|
5335
|
+
and block.get("type") == "text"
|
|
5336
|
+
and str(block.get("text", "")).strip()
|
|
5337
|
+
):
|
|
5338
|
+
assistant_had_text = True
|
|
5181
5339
|
if isinstance(block, dict) and block.get("type") == "tool_use":
|
|
5182
5340
|
tool_fingerprints.append(_tool_call_fingerprint(block))
|
|
5183
5341
|
# Extract target key for read-only dedup (Option 3)
|
|
@@ -5201,6 +5359,12 @@ def _record_last_assistant_tool_calls(
|
|
|
5201
5359
|
fingerprint=fingerprint,
|
|
5202
5360
|
)
|
|
5203
5361
|
return fingerprint
|
|
5362
|
+
# Fix B: no tool call in the last assistant turn. A plain-text turn is still
|
|
5363
|
+
# a non-write turn, so advance the recon-convergence streak (previously it
|
|
5364
|
+
# only moved on tool turns, freezing the counter through prose-only stalls).
|
|
5365
|
+
# Guard on real prose so an empty/absent assistant turn never inflates it.
|
|
5366
|
+
if assistant_had_text:
|
|
5367
|
+
monitor.note_no_tool_turn()
|
|
5204
5368
|
return ""
|
|
5205
5369
|
|
|
5206
5370
|
|
|
@@ -8811,6 +8975,9 @@ async def stream_anthropic_response(
|
|
|
8811
8975
|
try:
|
|
8812
8976
|
monitor.note_assistant_text(accumulated_text)
|
|
8813
8977
|
monitor.note_tool_arg_hosts(list(tc_args))
|
|
8978
|
+
# DEFERRAL-BREAK signal (Fix A): a no-tool prose turn that defers the
|
|
8979
|
+
# work. `tc_names` empty means this turn emitted no tool call.
|
|
8980
|
+
monitor.note_deferral_signal(accumulated_text, bool(tc_names))
|
|
8814
8981
|
except Exception:
|
|
8815
8982
|
pass
|
|
8816
8983
|
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Unit tests for the DEFERRAL-BREAK guardrail (Fix A) and the no-tool-turn
|
|
3
|
+
recon-convergence counting (Fix B).
|
|
4
|
+
|
|
5
|
+
Regression: a model could end a turn with plain prose that DEFERS the work --
|
|
6
|
+
"I need more exploration cycles to complete the plan" -- with no tool call. That
|
|
7
|
+
stall was invisible to STUCK-BREAK (not a loop-admission phrase) and to
|
|
8
|
+
recon-convergence (a no-tool turn never advanced its streak), so it silently
|
|
9
|
+
halted a hands-free build. The deferral-break detects the no-tool capitulation
|
|
10
|
+
and forces the next turn to take a concrete action; Fix B makes prose-only turns
|
|
11
|
+
count toward convergence so prolonged stalls also escalate.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import importlib.util
|
|
15
|
+
import unittest
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _load_proxy_module():
|
|
20
|
+
proxy_path = Path(__file__).resolve().parents[1] / "scripts" / "anthropic_proxy.py"
|
|
21
|
+
spec = importlib.util.spec_from_file_location("anthropic_proxy", proxy_path)
|
|
22
|
+
assert spec is not None and spec.loader is not None
|
|
23
|
+
module = importlib.util.module_from_spec(spec)
|
|
24
|
+
spec.loader.exec_module(module)
|
|
25
|
+
return module
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
proxy = _load_proxy_module()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TestDeferralPhraseRegex(unittest.TestCase):
|
|
32
|
+
def test_matches_the_reported_stall(self):
|
|
33
|
+
self.assertTrue(
|
|
34
|
+
proxy._DEFERRAL_PHRASE_RE.search(
|
|
35
|
+
"I need more exploration cycles to complete the plan. "
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def test_matches_close_kin(self):
|
|
40
|
+
for s in (
|
|
41
|
+
"Let me continue exploring the codebase before I proceed.",
|
|
42
|
+
"I'll need a few more passes to complete the plan.",
|
|
43
|
+
"I need to gather more research before writing anything.",
|
|
44
|
+
"Once I have explored more, I can start.",
|
|
45
|
+
):
|
|
46
|
+
self.assertTrue(proxy._DEFERRAL_PHRASE_RE.search(s), s)
|
|
47
|
+
|
|
48
|
+
def test_does_not_match_progress_narration(self):
|
|
49
|
+
for s in (
|
|
50
|
+
"Done. I created src/index.ts and wired the routes.",
|
|
51
|
+
"Here is the summary of what I built.",
|
|
52
|
+
"Running the tests now.",
|
|
53
|
+
"The build passes and all items are complete.",
|
|
54
|
+
):
|
|
55
|
+
self.assertIsNone(proxy._DEFERRAL_PHRASE_RE.search(s), s)
|
|
56
|
+
|
|
57
|
+
def test_does_not_match_generic_time_or_steps_question(self):
|
|
58
|
+
# A legitimate clarifying question must not trip the guard (was a false
|
|
59
|
+
# positive when bare "time"/"steps" were object tokens).
|
|
60
|
+
for s in (
|
|
61
|
+
"I need more time to review your requirements — could you clarify X?",
|
|
62
|
+
"There are a few more steps, let me know which environment to target.",
|
|
63
|
+
):
|
|
64
|
+
self.assertIsNone(proxy._DEFERRAL_PHRASE_RE.search(s), s)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class TestDeferralStreak(unittest.TestCase):
|
|
68
|
+
def test_no_tool_deferral_increments_and_fires(self):
|
|
69
|
+
mon = proxy.SessionMonitor()
|
|
70
|
+
mon.note_deferral_signal(
|
|
71
|
+
"I need more exploration cycles to complete the plan.", had_tool_call=False
|
|
72
|
+
)
|
|
73
|
+
self.assertEqual(mon.deferral_streak, 1)
|
|
74
|
+
should, reason = mon.should_force_deferral_break()
|
|
75
|
+
self.assertTrue(should)
|
|
76
|
+
self.assertIn("deferral", reason)
|
|
77
|
+
|
|
78
|
+
def test_tool_call_turn_resets_streak(self):
|
|
79
|
+
mon = proxy.SessionMonitor()
|
|
80
|
+
mon.note_deferral_signal("let me continue exploring", had_tool_call=False)
|
|
81
|
+
self.assertEqual(mon.deferral_streak, 1)
|
|
82
|
+
# Model actually acted this turn -> not deferring anymore.
|
|
83
|
+
mon.note_deferral_signal("let me continue exploring", had_tool_call=True)
|
|
84
|
+
self.assertEqual(mon.deferral_streak, 0)
|
|
85
|
+
self.assertFalse(mon.should_force_deferral_break()[0])
|
|
86
|
+
|
|
87
|
+
def test_non_matching_text_resets_streak(self):
|
|
88
|
+
mon = proxy.SessionMonitor()
|
|
89
|
+
mon.note_deferral_signal("I need more cycles", had_tool_call=False)
|
|
90
|
+
self.assertEqual(mon.deferral_streak, 1)
|
|
91
|
+
mon.note_deferral_signal("All done, files written.", had_tool_call=False)
|
|
92
|
+
self.assertEqual(mon.deferral_streak, 0)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class TestDeferralInjection(unittest.TestCase):
|
|
96
|
+
def test_forces_tool_choice_and_directive(self):
|
|
97
|
+
mon = proxy.SessionMonitor()
|
|
98
|
+
mon.note_deferral_signal("I need more exploration cycles", had_tool_call=False)
|
|
99
|
+
body = {
|
|
100
|
+
"tools": [{"function": {"name": "Write"}}],
|
|
101
|
+
"tool_choice": "auto",
|
|
102
|
+
"messages": [{"role": "system", "content": "sys"}],
|
|
103
|
+
}
|
|
104
|
+
proxy._maybe_inject_deferral_break(body, mon)
|
|
105
|
+
self.assertEqual(body["tool_choice"], "required")
|
|
106
|
+
self.assertIn("CONTINUE AUTONOMOUSLY", body["messages"][0]["content"])
|
|
107
|
+
self.assertEqual(mon.deferral_break_fires, 1)
|
|
108
|
+
|
|
109
|
+
def test_does_not_fire_below_threshold(self):
|
|
110
|
+
mon = proxy.SessionMonitor() # streak 0
|
|
111
|
+
body = {"tools": [{"function": {"name": "Write"}}], "tool_choice": "auto", "messages": []}
|
|
112
|
+
proxy._maybe_inject_deferral_break(body, mon)
|
|
113
|
+
self.assertEqual(body["tool_choice"], "auto")
|
|
114
|
+
self.assertEqual(mon.deferral_break_fires, 0)
|
|
115
|
+
|
|
116
|
+
def test_yields_to_stuck_break(self):
|
|
117
|
+
mon = proxy.SessionMonitor()
|
|
118
|
+
mon.deferral_streak = 5
|
|
119
|
+
mon.self_stuck_streak = 99 # stuck-break will fire this turn
|
|
120
|
+
body = {"tools": [{"function": {"name": "Write"}}], "tool_choice": "auto", "messages": []}
|
|
121
|
+
proxy._maybe_inject_deferral_break(body, mon)
|
|
122
|
+
# deferral defers to the more-urgent stuck-break (prose exit).
|
|
123
|
+
self.assertEqual(body["tool_choice"], "auto")
|
|
124
|
+
self.assertEqual(mon.deferral_break_fires, 0)
|
|
125
|
+
|
|
126
|
+
def test_disabled_when_off(self):
|
|
127
|
+
mon = proxy.SessionMonitor()
|
|
128
|
+
# Simulate the phrase but with the guard disabled.
|
|
129
|
+
original = proxy.PROXY_DEFERRAL_BREAK
|
|
130
|
+
try:
|
|
131
|
+
proxy.PROXY_DEFERRAL_BREAK = False
|
|
132
|
+
mon.note_deferral_signal("I need more exploration cycles", had_tool_call=False)
|
|
133
|
+
self.assertEqual(mon.deferral_streak, 0)
|
|
134
|
+
self.assertFalse(mon.should_force_deferral_break()[0])
|
|
135
|
+
finally:
|
|
136
|
+
proxy.PROXY_DEFERRAL_BREAK = original
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class TestDeferralYieldsAndToolAbsence(unittest.TestCase):
|
|
140
|
+
def test_yields_to_recon_convergence(self):
|
|
141
|
+
mon = proxy.SessionMonitor()
|
|
142
|
+
mon.deferral_streak = 5
|
|
143
|
+
# Push the no-write streak into recon-convergence territory.
|
|
144
|
+
mon.consecutive_no_write_turns = proxy.PROXY_RECON_CONVERGENCE_THRESHOLD
|
|
145
|
+
body = {
|
|
146
|
+
"tools": [{"function": {"name": "Write"}}],
|
|
147
|
+
"tool_choice": "auto",
|
|
148
|
+
"messages": [],
|
|
149
|
+
}
|
|
150
|
+
proxy._maybe_inject_deferral_break(body, mon)
|
|
151
|
+
# recon owns the turn -> deferral must not fire or touch tool_choice.
|
|
152
|
+
self.assertEqual(body["tool_choice"], "auto")
|
|
153
|
+
self.assertEqual(mon.deferral_break_fires, 0)
|
|
154
|
+
|
|
155
|
+
def test_no_tools_injects_directive_but_leaves_tool_choice(self):
|
|
156
|
+
mon = proxy.SessionMonitor()
|
|
157
|
+
mon.deferral_streak = 1 # recon NOT pending (streak stays 0)
|
|
158
|
+
body = {"tools": [], "tool_choice": "auto", "messages": []}
|
|
159
|
+
proxy._maybe_inject_deferral_break(body, mon)
|
|
160
|
+
# No tools to force, so tool_choice is left as-is, but the directive and
|
|
161
|
+
# the telemetry counter still apply (the nudge is still worth sending).
|
|
162
|
+
self.assertEqual(body["tool_choice"], "auto")
|
|
163
|
+
self.assertEqual(mon.deferral_break_fires, 1)
|
|
164
|
+
self.assertIn("CONTINUE AUTONOMOUSLY", body["messages"][0]["content"])
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class TestNoToolTurnConvergence(unittest.TestCase):
|
|
168
|
+
def test_no_tool_turn_advances_convergence_streak(self):
|
|
169
|
+
mon = proxy.SessionMonitor()
|
|
170
|
+
before = mon.consecutive_no_write_turns
|
|
171
|
+
mon.note_no_tool_turn()
|
|
172
|
+
mon.note_no_tool_turn()
|
|
173
|
+
self.assertEqual(mon.consecutive_no_write_turns, before + 2)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
if __name__ == "__main__":
|
|
177
|
+
unittest.main()
|