修复: 上下文管理第二批(E5注入产物/E13超时收敛/E2降级透出)

- E5:[补充指令]与[系统恢复]同治三处——载入滤出/恢复回放剔除/
  首条任务消息排除(434c8c40占位实证),is_guide_artifact统一判据
- E13:同工具超时连败≥3跨签名聚合,执行前软收敛警告(治换档位调参
  逃逸,434c8c40 run_command 8连败实证)
- E2:压缩失败走关键词摘要兜底时新发AiContextDegraded,前端toast
  「上下文已降级」不再静默失忆(76730ce8 seq166实证)
- vite watch忽略target/(cargo编译写.o触发EBUSY杀dev进程)
- provider-list模板根div缺闭合补齐(拆分半成品断链)

验收:tool_failure 5/keyword_fallback 3/recovery 6 passed;vue-tsc EXIT 0
This commit is contained in:
lxy
2026-10-19 00:25:51 +08:00
parent 25ec9cf69a
commit eec5978fa7
13 changed files with 171 additions and 22 deletions
+3
View File
@@ -539,6 +539,9 @@ export type AiChatEvent = ({
} | {
// 上下文已清空:前端刷新消息列表 + toast 提示
type: 'AiContextCleared'
} | {
// E2 压缩失败降级(关键词摘要兜底,loop 仍在跑):前端 toast 提示不中断流
type: 'AiContextDegraded'; reason: string
}) & {
conversation_id?: ConvId
}
+4
View File
@@ -698,6 +698,10 @@ async function initContextEventListeners(): Promise<void> {
onError: (_convId, message) => {
showToast(t('aiChat.compressError', { msg: message }), 'error')
},
// E2 压缩失败降级:仅提示不刷新不打断流(loop 仍在跑,实证静默降级致用户原句重发)
onContextDegraded: (_convId, reason) => {
showToast(t('aiChat.contextDegraded', { reason }), 'warning')
},
})
}
</script>
@@ -50,6 +50,7 @@
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
+6
View File
@@ -46,6 +46,7 @@ async function initContextListener(callbacks: {
onCleared?: (conversationId: string) => void
onCompressed?: (conversationId: string, summary: string) => void
onError?: (conversationId: string, message: string) => void
onContextDegraded?: (conversationId: string, reason: string) => void
}): Promise<void> {
setContextCallbacks({
onCompressing: () => { isCompressing.value = true },
@@ -62,6 +63,11 @@ async function initContextListener(callbacks: {
autoCompressedFlashTimer = setTimeout(() => { autoCompressedFlash.value = false }, 4000)
},
onCleared: (convId) => callbacks.onCleared?.(convId),
onContextDegraded: (convId, reason) => {
// E2:压缩失败降级为关键词摘要兜底——复位 loading + 上抛 toast(不中断 LLM 流)
isCompressing.value = false
callbacks.onContextDegraded?.(convId, reason)
},
onError: (convId, message) => {
// AiError 也用于流式生成失败(useAiEvents 已处理);此处仅在压缩中时复位 + toast,
// 避免双重处理流式错误。
@@ -30,6 +30,8 @@ export interface ContextCallbacks {
onCleared?: (conversationId: string) => void
/** 错误(AiError,含压缩失败):仅在 loading 时置 false + toast */
onError?: (conversationId: string, message: string) => void
/** E2 压缩失败降级(AiContextDegraded):loop 仍在跑,仅提示上下文已降级不中断流 */
onContextDegraded?: (conversationId: string, reason: string) => void
}
let _contextCallbacks: ContextCallbacks = {}
@@ -344,6 +346,11 @@ export async function handleLifecycleEvent(event: AiChatEvent): Promise<boolean>
_contextCallbacks.onCleared?.(event.conversation_id || '')
return true
case 'AiContextDegraded':
// E2:压缩失败已走关键词摘要兜底,loop 继续——透出降级提示而非静默失忆
_contextCallbacks.onContextDegraded?.(event.conversation_id || '', event.reason || '')
return true
default:
return false
}
+1
View File
@@ -275,6 +275,7 @@ export default {
// B4: one-shot auto-compress notice (loop auto-compress no longer fully silent)
autoCompressed: 'Context auto-compressed (earlier messages folded into summary)',
compressError: 'Compression failed: {msg}',
contextDegraded: 'Context degraded: {reason} — the AI may be missing some earlier details',
clearError: 'Clear failed: {msg}',
initError: 'AI panel init failed: {msg} (reopen panel to retry)',
initDegraded: 'List load failed, continuing in degraded mode: {msg}',
+2
View File
@@ -276,6 +276,8 @@ export default {
// B4: 自动压缩完成一次性提示(loop 自动压缩不再全程静默)
autoCompressed: '上下文已自动压缩(较早消息已折叠为摘要)',
compressError: '压缩失败:{msg}',
// E2:压缩失败走关键词摘要兜底,loop 继续——提示降级而非静默失忆
contextDegraded: '上下文已降级:{reason},AI 可能缺失部分早前细节',
clearError: '清空失败:{msg}',
initError: 'AI 面板初始化失败:{msg}(重开面板可重试)',
initDegraded: '列表加载失败,面板降级继续:{msg}',