v0.16.8: Agent Loop P0-P3 修复 + 死代码清理 + 版本号升级

- P0: executeToolWithTimeout 重写为 Promise.race,实现真正超时中断
- P1 #2: R8 紧急压缩限制最多 2 次,防止溢出→压缩→重试无限循环
- P1 #3: 新增 snapshotSafetyState/restoreSafetyState,Sub-Agent 在隔离环境中运行
- P1 #4: persistLoopContext 中止时持久化 TERMINATED 状态
- P1 #5: Completion Gate 失败时注入纠正提示并重试(最多 1 次)
- P2 #6: executeSingleTool 重试逻辑兜底返回完善
- P2 #7: 压缩阈值提高(0.3→0.5, 0.8→0.85)+ compressedThisCycle 防同轮重复压缩
- P2 #8: 路径依赖检查优先于 ALWAYS_PARALLEL,防止读写同路径被错误并行
- P2 #9: R105 消息年龄追踪改为内容哈希 key(后被确认为死代码并清理)
- P3 #11: ctx_tokens 统一语义为 prompt_eval_count
- P3 #12: 自动记忆提取捕获 signal 引用,避免竞态
- P3 #13: verifyToolResult 返回警告字符串供 Completion Gate 使用
- 注入消毒增强:零宽字符移除、全角→半角、新增覆盖模式
- 死代码清理:R105 上下文年龄追踪系列函数(无任何调用点)
- 版本号 0.16.7 → 0.16.8(package.json/lock, menu.ts, index.html, README.md)
This commit is contained in:
紫影233
2026-07-16 14:31:19 +08:00
parent 4b1b64dddc
commit 2ac07208b5
10 changed files with 230 additions and 118 deletions
+55 -42
View File
@@ -552,7 +552,7 @@ export function addResultMetadata(formattedResult: string): string {
// R97: 错误模式学习 — 从重复错误中学习并生成改进建议
// ═══════════════════════════════════════════════════════════════
interface ErrorPatternEntry {
export interface ErrorPatternEntry {
toolName: string;
errorSignature: string;
count: number;
@@ -624,7 +624,7 @@ export function recordErrorPattern(toolName: string, errorMsg: string): string |
// R104: 工具结果去重 — 相似结果检测,减少上下文中的冗余
// ═══════════════════════════════════════════════════════════════
interface ToolResultFingerprint {
export interface ToolResultFingerprint {
toolName: string;
contentHash: string;
timestamp: number;
@@ -671,43 +671,6 @@ export function isDuplicateToolResult(toolName: string, resultContent: string):
return { duplicate: false };
}
// ═══════════════════════════════════════════════════════════════
// R105: 上下文年龄追踪 — 跟踪消息年龄以优化压缩决策
// ═══════════════════════════════════════════════════════════════
const _messageTimestamps = new Map<number, number>(); // message index → creation timestamp
/** R105: 记录消息创建时间 */
export function recordMessageAge(msgIndex: number): void {
_messageTimestamps.set(msgIndex, Date.now());
}
/** R105: 获取消息年龄(毫秒),-1 表示未记录 */
export function getMessageAge(msgIndex: number): number {
const ts = _messageTimestamps.get(msgIndex);
if (!ts) return -1;
return Date.now() - ts;
}
/** R105: 获取年龄超过阈值的消息索引列表 */
export function getAgedMessageIndices(thresholdMs: number): number[] {
const now = Date.now();
const result: number[] = [];
for (const [idx, ts] of _messageTimestamps) {
if (now - ts > thresholdMs) result.push(idx);
}
return result.sort((a, b) => a - b);
}
/** R105: 清理已删除消息的时间戳记录 */
export function cleanupMessageTimestamps(validIndices: Set<number>): void {
for (const key of _messageTimestamps.keys()) {
if (!validIndices.has(key)) {
_messageTimestamps.delete(key);
}
}
}
// ═══════════════════════════════════════════════════════════════
// R109: 工具参数消毒 — 防止通过工具参数注入恶意内容
// ═══════════════════════════════════════════════════════════════
@@ -1052,13 +1015,63 @@ export function resetAllSafetyState(): void {
_errorPatterns.clear();
// R104: 清理结果指纹
_resultFingerprints.length = 0;
// R105: 清理消息时间戳
_messageTimestamps.clear();
// R118: 清理性能分析数据
_loopTimings.length = 0;
logInfo('Agent Safety: 所有安全状态已重置');
}
// ═══════════════════════════════════════════════════════════════
// P1 #3: 安全状态快照/恢复 — 供 Sub-Agent 隔离使用
// ═══════════════════════════════════════════════════════════════
export interface SafetyStateSnapshot {
toolResultStore: Map<string, { toolName: string; fullContent: string; timestamp: number }>;
toolCallHistory: string[];
userGoal: string;
toolCallTimestamps: Map<string, number[]>;
toolFailureCount: Map<string, number>;
circuitBreakerTripped: Map<string, number>;
errorPatterns: Map<string, ErrorPatternEntry>;
resultFingerprints: ToolResultFingerprint[];
loopTimings: LoopTiming[];
}
/** P1 #3: 快照当前安全状态(供 Sub-Agent 在隔离环境中使用) */
export function snapshotSafetyState(): SafetyStateSnapshot {
return {
toolResultStore: new Map(_toolResultStore),
toolCallHistory: [..._toolCallHistory],
userGoal: _userGoal,
toolCallTimestamps: new Map(_toolCallTimestamps),
toolFailureCount: new Map(_toolFailureCount),
circuitBreakerTripped: new Map(_circuitBreakerTripped),
errorPatterns: new Map(_errorPatterns),
resultFingerprints: [..._resultFingerprints],
loopTimings: [..._loopTimings],
};
}
/** P1 #3: 从快照恢复安全状态(Sub-Agent 执行完毕后恢复主 Agent 状态) */
export function restoreSafetyState(snapshot: SafetyStateSnapshot): void {
_toolResultStore.clear();
snapshot.toolResultStore.forEach((v, k) => _toolResultStore.set(k, v));
_toolCallHistory.length = 0;
_toolCallHistory.push(...snapshot.toolCallHistory);
_userGoal = snapshot.userGoal;
_toolCallTimestamps.clear();
snapshot.toolCallTimestamps.forEach((v, k) => _toolCallTimestamps.set(k, [...v]));
_toolFailureCount.clear();
snapshot.toolFailureCount.forEach((v, k) => _toolFailureCount.set(k, v));
_circuitBreakerTripped.clear();
snapshot.circuitBreakerTripped.forEach((v, k) => _circuitBreakerTripped.set(k, v));
_errorPatterns.clear();
snapshot.errorPatterns.forEach((v, k) => _errorPatterns.set(k, v));
_resultFingerprints.length = 0;
_resultFingerprints.push(...snapshot.resultFingerprints);
_loopTimings.length = 0;
_loopTimings.push(...snapshot.loopTimings);
}
// ═══════════════════════════════════════════════════════════════
// R116: 错误恢复建议增强 — 提供上下文化的错误恢复建议
// ═══════════════════════════════════════════════════════════════
@@ -1195,7 +1208,7 @@ export function formatErrorRecovery(suggestion: ErrorRecoverySuggestion): string
// R118: Agent 循环性能分析 — 识别 Agent Loop 瓶颈
// ═══════════════════════════════════════════════════════════════
interface LoopTiming {
export interface LoopTiming {
loop: number;
phase: string;
durationMs: number;