feat: 上下文压缩支持状态持久化缓存,前端过滤隐藏消息

- summarization_middleware 摘要缓存写入 LangGraph thread state,跨进程/重启可复用
- 摘要消息改为 SystemMessage,提示模型静默使用、不泄露
- thread_state 新增 context_summary_cache 字段
- app_config 加载时记录 summarization 配置日志
- config.yaml 压缩触发/保留阈值调整为生产值(token 预算)
- 前端 input-box / message-list 过滤 hide_from_ui 消息

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
AdministratorandClaude Opus 4.8 committed 2026-06-16 22:16:06 +08:00
1 parent 5f39879e4d
commit 5b610fd807
7 files changed
+159 -71

No files matched your search

@@ -61,8 +61,9 @@ import {
} from "@/components/ui/dropdown-menu";
import { apiFetch } from "@/core/api";
import { getBackendBaseURL } from "@/core/config";
import { useI18n } from "@/core/i18n/hooks";
import { useModels } from "@/core/models/hooks";
import { useI18n } from "@/core/i18n/hooks";
import { isHiddenFromUIMessage } from "@/core/messages/utils";
import { useModels } from "@/core/models/hooks";
import type { AgentThreadContext } from "@/core/threads";
import { textOfMessage } from "@/core/threads/utils";
import { desensitize } from "@/lib/desensitize";
@@ -467,14 +468,15 @@ export function InputBox({
return;
}
const lastAi = [...thread.messages].reverse().find((m) => m.type === "ai");
const visibleMessages = thread.messages.filter((m) => !isHiddenFromUIMessage(m));
const lastAi = [...visibleMessages].reverse().find((m) => m.type === "ai");
const lastAiId = lastAi?.id ?? null;
if (!lastAiId || lastAiId === lastGeneratedForAiIdRef.current) {
return;
}
lastGeneratedForAiIdRef.current = lastAiId;
const recent = thread.messages
const recent = visibleMessages
.filter((m) => m.type === "human" || m.type === "ai")
.map((m) => {
const role = m.type === "human" ? "user" : "assistant";
@@ -20,9 +20,10 @@ import {
groupMessages,
hasContent,
hasPresentFiles,
hasReasoning,
hasToolCalls,
} from "@/core/messages/utils";
hasReasoning,
hasToolCalls,
isHiddenFromUIMessage,
} from "@/core/messages/utils";
import { useRehypeSplitWordsIntoSpans } from "@/core/rehype";
import { isThreadRagModeLocked, useLocalSettings } from "@/core/settings";
import { useSkills } from "@/core/skills/hooks";
@@ -151,7 +152,10 @@ export function MessageList({
});
}, []);
const allMessages = thread.messages;
const allMessages = useMemo(
() => thread.messages.filter((m) => !isHiddenFromUIMessage(m)),
[thread.messages],
);
const messages = useMemo(
() =>
hiddenMessageIds.size === 0