AUDIT / src /lib /agentLoop /callBudgetForecastBlock.ts
Arypulka98's picture
feat(audit): deploy full backend cluster node (part 2)
cc11e77 verified
Raw
History Blame Contribute Delete
4.05 kB
/**
* callBudgetForecastBlock.ts — S-FORECAST: pre-turn budget forecast
*
* Prima di qualsiasi acquireExtraCall, analizza il task classificato e
* RISERVA ogni slot (HIGH/LOW) per la capability più utile in quel contesto.
*
* Problema risolto (on-demand race condition):
* reflection arriva all'iter 4 → prende LOW slot → verify alla fine non trova
* slot → output di codice mai verificato. Non era un problema di logica, era
* un problema di TIMING: chi arrivava prima vinceva.
*
* Con forecast: LOW è pre-riservato per verify su task di codice → reflection
* è bloccata dalla riserva, non dal timing fortuito. Garanzia strutturale.
*
* Design:
* - Zero LLM calls, < 0.1ms, deterministic, pure function
* - BudgetForecast importato da callBudgetCoordinator (nessun circular import)
* - null = nessuna restrizione (backward-compatible con on-demand)
* - Stringa specifica = solo quella capability può acquisire lo slot
*
* Regole (priorità decrescente):
* 1. isDirectAnswer → HIGH: null, LOW: 'verify' fast path
* 2. code + complex/err → HIGH: 'thinking', LOW: 'verify' qualità codice
* 3. code semplice → HIGH: null, LOW: 'verify' verify essenziale
* 4. reasoning=high+text → HIGH: 'debate', LOW: 'reflection' testo complesso
* 5. medium + errors → HIGH: 'thinking', LOW: 'verify' recovery boost
* 6. default → HIGH: null, LOW: null no restriction
*
* @module callBudgetForecastBlock
*/
import type { BudgetForecast } from './callBudgetCoordinator';
export interface BudgetForecastInput {
preCls: { type?: string; isDirectAnswer?: boolean; complexity?: number } | null;
isCodeTask: boolean;
reasoningDepth: 'low' | 'medium' | 'high';
hasRecentErrors: boolean;
}
/**
* Calcola la previsione ottimale di allocazione budget per questo turno.
* Chiamare DOPO la classificazione del task e PRIMA di runPreLoopFinalizer.
* Risultato passato a callBudget.setForecast() per attivare la riserva.
*/
export function forecastBudget(input: BudgetForecastInput): BudgetForecast {
const { preCls, isCodeTask, reasoningDepth, hasRecentErrors } = input;
const _complexity = preCls?.complexity ?? 5;
const _isDirectAns = preCls?.isDirectAnswer ?? false;
// 1. Risposta diretta → nessun HIGH necessario, LOW riservato per verify
if (_isDirectAns) {
return {
highReserved: null,
lowReserved: 'verify',
rationale: 'isDirectAnswer → LOW:verify (fast path, solo check completezza)',
};
}
// 2. Codice complesso o con errori → thinking garantito + verify garantito
if (isCodeTask && (_complexity >= 7 || hasRecentErrors)) {
return {
highReserved: 'thinking',
lowReserved: 'verify',
rationale: `code+${_complexity >= 7 ? 'complexity' + _complexity : 'errors'} → HIGH:thinking LOW:verify`,
};
}
// 3. Codice semplice → solo verify garantito (thinking non necessario)
if (isCodeTask) {
return {
highReserved: null,
lowReserved: 'verify',
rationale: 'code+simple → LOW:verify (nessun ragionamento avanzato; verify essenziale)',
};
}
// 4. Ragionamento alto + testo → debate + reflection (multi-prospettiva + validazione)
if (reasoningDepth === 'high') {
return {
highReserved: 'debate',
lowReserved: 'reflection',
rationale: 'reasoning=high+text → HIGH:debate LOW:reflection',
};
}
// 5. Ragionamento medio con errori → thinking per recovery + verify output
if (hasRecentErrors && reasoningDepth !== 'low') {
return {
highReserved: 'thinking',
lowReserved: 'verify',
rationale: 'medium+errors → HIGH:thinking LOW:verify (recovery boost)',
};
}
// 6. Default — nessuna restrizione (comportamento backward-compatible on-demand)
return {
highReserved: null,
lowReserved: null,
rationale: 'default → no restriction (on-demand fallback)',
};
}