159 lines
5.7 KiB
JavaScript
159 lines
5.7 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* P0 补丁脚本 — 将冷启动防护 + 消歧接入 + 遥测发射写入 route-interceptor.js
|
|
*
|
|
* 用法: node scripts/patch-interceptor-p0.js
|
|
* node scripts/patch-interceptor-p0.js --dry-run (仅预览不写入)
|
|
*
|
|
* 三处变更:
|
|
* 1. runRouteEngine() 中插入消歧 + 冷启动 (归一化之前)
|
|
* 2. runRouteEngine() return 附加元数据
|
|
* 3. writeRouteState() 中插入遥测发射
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const dryRun = process.argv.includes('--dry-run');
|
|
const HOOK_FILE = path.join(__dirname, '..', 'hooks', 'route-interceptor.js');
|
|
|
|
if (!fs.existsSync(HOOK_FILE)) {
|
|
console.error('错误: 找不到 route-interceptor.js');
|
|
process.exit(1);
|
|
}
|
|
|
|
let code = fs.readFileSync(HOOK_FILE, 'utf8');
|
|
let patchCount = 0;
|
|
|
|
// === 补丁 1: 归一化之前插入消歧 + 冷启动 ===
|
|
// 使用正则匹配,兼容 \r\n 和 \n 换行
|
|
const PATCH1_RE = /( +\/\/ .*\r?\n const normalized = routeAnalyzer\.normalizeScores\(results\)\.slice\(0, 5\);\r?\n const recommendation = routeAnalyzer\.getRecommendation\(normalized\);)/;
|
|
|
|
const PATCH1_REPLACEMENT = ` // v5.8: 冲突消歧 (加权投票 + specificity)
|
|
let disambiguated = results;
|
|
let firedRules = [];
|
|
if (routeAnalyzer.applyDisambiguation) {
|
|
try {
|
|
const disambResult = routeAnalyzer.applyDisambiguation(results, prompt, index);
|
|
disambiguated = disambResult.results || results;
|
|
firedRules = disambResult.firedRules || [];
|
|
} catch {}
|
|
}
|
|
|
|
// v5.8: 冷启动防护 (epsilon-greedy + 新技能 boost)
|
|
let coldStartApplied = false;
|
|
let coldStartSkills = [];
|
|
const routeTelemetry = safeRequire(path.join(SCRIPTS_DIR, 'route-telemetry.js'));
|
|
if (routeAnalyzer.applyColdStartBoost && routeTelemetry) {
|
|
try {
|
|
const routeStats = routeTelemetry.getSkillRouteStats(30);
|
|
const { boostedSkills } = routeAnalyzer.applyColdStartBoost(disambiguated, routeStats);
|
|
if (boostedSkills && boostedSkills.length > 0) {
|
|
coldStartApplied = true;
|
|
coldStartSkills = boostedSkills;
|
|
disambiguated.sort((a, b) => b.score - a.score);
|
|
}
|
|
} catch {}
|
|
}
|
|
|
|
// 归一化
|
|
const normalized = routeAnalyzer.normalizeScores(disambiguated).slice(0, 5);
|
|
const recommendation = routeAnalyzer.getRecommendation(normalized);`;
|
|
|
|
if (PATCH1_RE.test(code)) {
|
|
code = code.replace(PATCH1_RE, PATCH1_REPLACEMENT);
|
|
patchCount++;
|
|
console.log('✓ 补丁 1/3: 消歧 + 冷启动 已插入 runRouteEngine()');
|
|
} else if (code.includes('v5.8:')) {
|
|
console.log('⊘ 补丁 1/3: 已存在,跳过');
|
|
} else {
|
|
console.error('✗ 补丁 1/3: 找不到锚点,请检查 route-interceptor.js 是否已被修改');
|
|
}
|
|
|
|
// === 补丁 2: runRouteEngine return 附加元数据 ===
|
|
const PATCH2_ANCHOR = ` return { primary, candidates, confidence, chain, composable };`;
|
|
|
|
const PATCH2_REPLACEMENT = ` return {
|
|
primary, candidates, confidence, chain, composable,
|
|
_firedRules: firedRules || [],
|
|
_coldStartApplied: coldStartApplied || false,
|
|
_coldStartSkills: coldStartSkills || [],
|
|
_startTs: Date.now(),
|
|
};`;
|
|
|
|
if (code.includes(PATCH2_ANCHOR)) {
|
|
code = code.replace(PATCH2_ANCHOR, PATCH2_REPLACEMENT);
|
|
patchCount++;
|
|
console.log('✓ 补丁 2/3: return 元数据 已附加');
|
|
} else if (code.includes('_firedRules')) {
|
|
console.log('⊘ 补丁 2/3: 已存在,跳过');
|
|
} else {
|
|
console.error('✗ 补丁 2/3: 找不到锚点');
|
|
}
|
|
|
|
// === 补丁 3: writeRouteState 中插入遥测发射 ===
|
|
const PATCH3_ANCHOR = ` // 追加到每日路由日志
|
|
appendRouteLog(prompt, routing, traceId);
|
|
|
|
return state;`;
|
|
|
|
const PATCH3_REPLACEMENT = ` // 追加到每日路由日志
|
|
appendRouteLog(prompt, routing, traceId);
|
|
|
|
// v5.8: 发射路由遥测指标
|
|
try {
|
|
const telemetry = require(path.join(SCRIPTS_DIR, 'route-telemetry.js'));
|
|
if (telemetry.emitRouteMetric) {
|
|
telemetry.emitRouteMetric({
|
|
queryLength: (prompt || '').split(/\\s+/).length,
|
|
selectedSkill: routing.primary,
|
|
topScore: routing.candidates?.[0]?.confidence || 0,
|
|
gap12: (routing.candidates?.[0]?.confidence || 0) - (routing.candidates?.[1]?.confidence || 0),
|
|
confidence: routing.confidence,
|
|
rulesFired: routing._firedRules || [],
|
|
coldStartApplied: routing._coldStartApplied || false,
|
|
coldStartSkills: routing._coldStartSkills || [],
|
|
latencyMs: Date.now() - (routing._startTs || Date.now()),
|
|
experimentId: routing.experiment?.id || null,
|
|
});
|
|
}
|
|
} catch {}
|
|
|
|
return state;`;
|
|
|
|
if (code.includes(PATCH3_ANCHOR)) {
|
|
code = code.replace(PATCH3_ANCHOR, PATCH3_REPLACEMENT);
|
|
patchCount++;
|
|
console.log('✓ 补丁 3/3: 遥测发射 已插入 writeRouteState()');
|
|
} else if (code.includes('v5.8: 发射路由遥测')) {
|
|
console.log('⊘ 补丁 3/3: 已存在,跳过');
|
|
} else {
|
|
console.error('✗ 补丁 3/3: 找不到锚点');
|
|
}
|
|
|
|
// === 更新版本号 ===
|
|
if (code.includes("version: '5.6'")) {
|
|
code = code.replace("version: '5.6'", "version: '5.8'");
|
|
console.log('✓ 版本号: 5.6 → 5.8');
|
|
}
|
|
|
|
// === 写入 ===
|
|
if (patchCount === 0) {
|
|
console.log('\n无需变更。');
|
|
process.exit(0);
|
|
}
|
|
|
|
if (dryRun) {
|
|
console.log(`\n[dry-run] 将应用 ${patchCount} 个补丁,但未写入文件。`);
|
|
process.exit(0);
|
|
}
|
|
|
|
// 备份原文件
|
|
const backupFile = HOOK_FILE + '.bak-' + new Date().toISOString().slice(0, 10);
|
|
fs.copyFileSync(HOOK_FILE, backupFile);
|
|
console.log(`\n备份: ${backupFile}`);
|
|
|
|
fs.writeFileSync(HOOK_FILE, code);
|
|
console.log(`已写入 ${patchCount} 个补丁到 route-interceptor.js`);
|
|
console.log('完成 ✓');
|