exec('CREATE TABLE IF NOT EXISTS traces (id INTEGER PRIMARY KEY AUTOINCREMENT, ts TEXT, message TEXT, route TEXT, engine TEXT, providers TEXT, confidence REAL, tokens_in INTEGER, tokens_out INTEGER, latency_ms INTEGER, session_id TEXT)'); $db->exec('CREATE INDEX IF NOT EXISTS idx_ts ON traces(ts)'); } return $db; } $db = ensure_db($db_path); if ($action === 'log') { // Called by master-api to log decisions $stmt = $db->prepare('INSERT INTO traces(ts, message, route, engine, providers, confidence, tokens_in, tokens_out, latency_ms, session_id) VALUES(:ts, :msg, :route, :engine, :prov, :conf, :tin, :tout, :lat, :sess)'); $stmt->bindValue(':ts', date('c')); $stmt->bindValue(':msg', $_POST['message'] ?? ''); $stmt->bindValue(':route', $_POST['route'] ?? ''); $stmt->bindValue(':engine', $_POST['engine'] ?? ''); $stmt->bindValue(':prov', $_POST['providers'] ?? ''); $stmt->bindValue(':conf', (float)($_POST['confidence'] ?? 0.8)); $stmt->bindValue(':tin', (int)($_POST['tokens_in'] ?? 0)); $stmt->bindValue(':tout', (int)($_POST['tokens_out'] ?? 0)); $stmt->bindValue(':lat', (int)($_POST['latency_ms'] ?? 0)); $stmt->bindValue(':sess', $_POST['session_id'] ?? session_id() ?: 'anon'); $stmt->execute(); echo json_encode(['ok'=>true, 'id'=>$db->lastInsertRowID()]); exit; } if ($action === 'explain_last') { $session = $_GET['session'] ?? 'anon'; $r = $db->query("SELECT * FROM traces WHERE session_id='" . SQLite3::escapeString($session) . "' ORDER BY id DESC LIMIT 1"); $row = $r->fetchArray(SQLITE3_ASSOC); if (!$row) { echo json_encode(['ok'=>false, 'error'=>'No trace found', 'session'=>$session]); exit; } $explanation = "## Décision explainability "; $explanation .= "**Message** : " . $row['message'] . " "; $explanation .= "**Route** : " . $row['route'] . " "; $explanation .= "**Engine** : " . $row['engine'] . " "; $explanation .= "**Providers** : " . $row['providers'] . " "; $explanation .= "**Confidence** : " . round($row['confidence']*100) . "% "; $explanation .= "**Latency** : " . $row['latency_ms'] . "ms "; $explanation .= "**Tokens** : " . $row['tokens_in'] . " in / " . $row['tokens_out'] . " out "; $explanation .= "**Timestamp** : " . $row['ts'] . " "; echo json_encode(['ok'=>true, 'trace'=>$row, 'explanation'=>$explanation]); exit; } if ($action === 'stats') { $r = $db->query('SELECT COUNT(*) as n, AVG(confidence) as avg_conf, AVG(latency_ms) as avg_lat FROM traces'); $stats = $r->fetchArray(SQLITE3_ASSOC); echo json_encode(['ok'=>true, 'stats'=>$stats]); exit; } echo json_encode(['ok'=>false, 'error'=>'Unknown action', 'actions'=>['log','explain_last','stats']]);