@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.
@@ -1 +1 @@
1
- {"version":3,"file":"handsfree.d.ts","sourceRoot":"","sources":["../../src/cli/handsfree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AA4DH;;;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,CA2CvD;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"}
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"}
@@ -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
- return { block: false, message: 'no active build ledger' };
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,CAepF;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAWtE"}
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;KACrD,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"}
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;CACzD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,GAAG,GAAE,iBAAsB,GAC1B,kBAAkB,CAqBpB"}
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;AAWD;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACvC,OAA2B,EAC3B,MAAyB,EAAE;IAE3B,MAAM,KAAK,GAAG,OAAO,IAAI,SAAS,CAAC;IACnC,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAE1C,IAAI,GAAG,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,SAAS,GAAyB,GAAG,CAAC,SAAS,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;IACjF,MAAM,IAAI,GAAG,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACrE,IAAI,OAAO,GAAuB,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,CAAC;IAExE,yEAAyE;IACzE,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QAClB,KAAK,MAAM,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACtD,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;gBACpD,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;YACjD,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miller-tech/uap",
3
- "version": "1.118.2",
3
+ "version": "1.119.1",
4
4
  "description": "Autonomous AI agent memory system with CLAUDE.md protocol enforcement",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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") or []
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()