terminal-smart-cli 0.97.11 → 0.97.12
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/lib/agent.js +20 -7
- package/package.json +1 -1
package/lib/agent.js
CHANGED
|
@@ -225,7 +225,11 @@ function isCycle(sigs) {
|
|
|
225
225
|
// Veredito do watchdog (PURO, testável): 'break' | 'warn' | 'ok'.
|
|
226
226
|
// break = 2º strike (repetiu demais OU já avisado e ainda em ciclo) → encerra o loop.
|
|
227
227
|
// warn = 1º strike (bateu o limite de repetição OU 1º ciclo) e ainda não avisou ESTA sig.
|
|
228
|
-
function loopDecision({ nSig, cycling, warnedThis, loopWarned, WARN, BREAK }) {
|
|
228
|
+
function loopDecision({ nSig, cycling, warnedThis, loopWarned, WARN, BREAK, cacheHit = false }) {
|
|
229
|
+
// Uma leitura idêntica já atendida pelo cache não é ausência de progresso:
|
|
230
|
+
// ela não consulta a fonte, não cria efeito colateral e deve voltar ao modelo
|
|
231
|
+
// como referência curta. O watchdog continua valendo para execuções reais.
|
|
232
|
+
if (cacheHit) return 'cache';
|
|
229
233
|
if (nSig >= BREAK || (cycling && loopWarned)) return 'break';
|
|
230
234
|
if ((nSig >= WARN || cycling) && !warnedThis) return 'warn';
|
|
231
235
|
return 'ok';
|
|
@@ -695,13 +699,22 @@ async function run(task, opts = {}) {
|
|
|
695
699
|
result = { erro: 'MISSÃO INTERROMPIDA PELO LIMITE DE CUSTO/TEMPO. Esta ferramenta não foi executada.', guard: guardStopped };
|
|
696
700
|
}
|
|
697
701
|
|
|
698
|
-
//
|
|
702
|
+
// Consulta o cache antes do watchdog, mas só entrega o resultado depois dos gates
|
|
703
|
+
// de segurança. Assim uma leitura repetida não vira falso loop, sem permitir que
|
|
704
|
+
// cache contorne escopo estrito, modo somente leitura ou outras políticas.
|
|
705
|
+
const _cachedRead = READONLY.has(name) ? _missionCache.get(name, input) : null;
|
|
706
|
+
|
|
707
|
+
// ── WATCHDOG anti-loop: mede somente chamadas que realmente precisariam executar ──
|
|
699
708
|
const _sig = loopSig(name, input);
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
709
|
+
let _nSig = _callCounts.get(_sig) || 0;
|
|
710
|
+
let _cycling = false;
|
|
711
|
+
if (!_cachedRead) {
|
|
712
|
+
_recentSigs.push(_sig); if (_recentSigs.length > 8) _recentSigs.shift();
|
|
713
|
+
_nSig++; _callCounts.set(_sig, _nSig);
|
|
714
|
+
_cycling = isCycle(_recentSigs);
|
|
715
|
+
}
|
|
703
716
|
const _verdict = loopedOut ? 'ended'
|
|
704
|
-
: loopDecision({ nSig: _nSig, cycling: _cycling, warnedThis: _warnedSigs.has(_sig), loopWarned: _loopWarned, WARN: LOOP_WARN, BREAK: LOOP_BREAK });
|
|
717
|
+
: loopDecision({ nSig: _nSig, cycling: _cycling, warnedThis: _warnedSigs.has(_sig), loopWarned: _loopWarned, WARN: LOOP_WARN, BREAK: LOOP_BREAK, cacheHit: !!_cachedRead });
|
|
705
718
|
if (_verdict === 'ended') {
|
|
706
719
|
// um tc anterior deste lote já disparou o corte → os demais fecham sem executar
|
|
707
720
|
result = { erro: lang !== 'en' ? 'LOOP encerrado — não execute mais ferramentas; conclua.' : 'LOOP ended — do not run more tools; conclude.' };
|
|
@@ -985,7 +998,7 @@ async function run(task, opts = {}) {
|
|
|
985
998
|
steps++; _ran = true;
|
|
986
999
|
}
|
|
987
1000
|
if (result === undefined && READONLY.has(name)) {
|
|
988
|
-
const _cached =
|
|
1001
|
+
const _cached = _cachedRead;
|
|
989
1002
|
if (_cached) {
|
|
990
1003
|
const _visible = messages.some(m => m && m.role === 'tool' && m.tool_call_id === _cached.toolCallId);
|
|
991
1004
|
_cachedContent = cacheReference(_cached, name, _visible);
|