fix(小宝预警): 增加快照节流和 AI cooldown

This commit is contained in:
Script Generator
2026-06-30 09:28:12 +08:00
parent 37695a8101
commit bf4b32f17d
7 changed files with 207 additions and 8 deletions

View File

@@ -24,6 +24,14 @@ type RiskInsightPrevious = Pick<
const SCORE_TRIGGER_DELTA = 15;
const CONFIDENCE_DROP_DELTA = 15;
const ONE_DAY_MS = 86_400_000;
const RISK_INSIGHT_COOLDOWN_MS = 6 * 60 * 60 * 1000;
const RISK_LEVEL_RANK: Record<XiaobaoVersionRisk['riskLevel'], number> = {
on_track: 0,
attention: 1,
at_risk: 2,
likely_delayed: 3,
blocked: 4,
};
export function shouldRequestRiskInsight(current: RiskInsightCurrent, previous?: RiskInsightPrevious): boolean {
if (current.riskLevel === 'on_track') return false;
@@ -57,6 +65,31 @@ export function shouldRequestRiskInsight(current: RiskInsightCurrent, previous?:
);
}
export function findLatestRiskInsightForVersion(
cache: XiaobaoRiskInsightCacheItem[],
versionId: string,
): XiaobaoRiskInsightCacheItem | undefined {
return cache
.filter((item) => item.versionId === versionId)
.sort((a, b) => getTime(b.generatedAt) - getTime(a.generatedAt))[0];
}
export function shouldRequestRiskInsightWithCooldown(
current: RiskInsightCurrent,
previous?: RiskInsightPrevious,
latestInsight?: XiaobaoRiskInsightCacheItem,
now: Date = new Date(),
): boolean {
if (!shouldRequestRiskInsight(current, previous)) return false;
if (!latestInsight) return true;
if (isRiskLevelEscalation(current.riskLevel, latestInsight)) return true;
const generatedAt = getTime(latestInsight.generatedAt);
const nowTime = now.getTime();
if (!Number.isFinite(generatedAt) || !Number.isFinite(nowTime)) return true;
return nowTime - generatedAt >= RISK_INSIGHT_COOLDOWN_MS;
}
export function buildRiskInsightSignature(risk: XiaobaoVersionRisk): string {
return JSON.stringify({
versionId: risk.versionId,
@@ -219,3 +252,26 @@ function compareSignatureRows<T>(a: T, b: T): number {
function clampScore(score: number): number {
return Math.max(0, Math.min(100, Math.round(score)));
}
function isRiskLevelEscalation(
currentLevel: XiaobaoVersionRisk['riskLevel'],
latestInsight: XiaobaoRiskInsightCacheItem,
): boolean {
const previousLevel = parseRiskLevel(latestInsight.riskSignature);
if (!previousLevel) return false;
return RISK_LEVEL_RANK[currentLevel] > RISK_LEVEL_RANK[previousLevel];
}
function parseRiskLevel(signature: string): XiaobaoVersionRisk['riskLevel'] | undefined {
try {
const parsed = JSON.parse(signature) as { riskLevel?: XiaobaoVersionRisk['riskLevel'] };
return parsed.riskLevel && parsed.riskLevel in RISK_LEVEL_RANK ? parsed.riskLevel : undefined;
} catch {
return undefined;
}
}
function getTime(value: string): number {
const time = new Date(value).getTime();
return Number.isFinite(time) ? time : Number.NaN;
}