File size: 4,050 Bytes
cc11e77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
 * 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)',
  };
}