#!/usr/bin/env node /** * Stage A baseline for chat-task intent routing. * Reads existing agent-run events; does not change routing. * * Usage: * node scripts/report-chat-intent-baseline.mjs * node scripts/report-chat-intent-baseline.mjs --hours 48 */ import { loadH5Environment } from './load-env.mjs'; import { createDbPool } from '../db.mjs'; import { aggregateChatIntentObservations, observationFromIntentRoutedData, } from '../chat-intent-observation.mjs'; loadH5Environment(import.meta.dirname); function parseHours(argv) { const index = argv.indexOf('--hours'); if (index < 0) return 24; const parsed = Number(argv[index + 1]); return Number.isFinite(parsed) && parsed > 0 ? parsed : 24; } function parseJson(value) { if (!value) return {}; if (typeof value === 'object') return value; try { return JSON.parse(String(value)); } catch { return {}; } } async function main() { const hours = parseHours(process.argv.slice(2)); const sinceMs = Date.now() - hours * 60 * 60 * 1000; const pool = await createDbPool(); try { const [rows] = await pool.query( `SELECT event_type, data_json FROM h5_agent_run_events WHERE created_at >= ? AND event_type IN ( 'intent_routed', 'direct_session_escalated_to_deep_reasoning', 'direct_escalation_context_injected' ) ORDER BY created_at ASC`, [sinceMs], ); const routed = []; let escalatedCount = 0; let contextInjectedCount = 0; for (const row of rows ?? []) { if (row.event_type === 'direct_session_escalated_to_deep_reasoning') { escalatedCount += 1; continue; } if (row.event_type === 'direct_escalation_context_injected') { contextInjectedCount += 1; continue; } routed.push(observationFromIntentRoutedData(parseJson(row.data_json))); } const summary = aggregateChatIntentObservations({ routed, escalatedCount, contextInjectedCount, }); console.log(`==> chat intent baseline last ${hours}h`); console.log(JSON.stringify(summary, null, 2)); if (summary.total === 0) { console.log('NOTE 窗口内没有 intent_routed。阶段 A 需要先有聊天流量。'); } else { console.log( `NOTE 0.72 兜底 ${summary.ruleFallbackCount}/${summary.total}` + ` (${summary.ruleFallbackRatio});` + ` 升级 ${summary.escalatedCount};` + ` 记忆召回仍走 direct ${summary.memoryRecallDirectRatio};` + ` shadow wouldChangeRoute ${summary.wouldChangeRoute}/${summary.shadowObserved}`, ); } } finally { await pool.end(); } } main().catch((err) => { console.error(err instanceof Error ? err.message : err); process.exitCode = 1; });