feat(summarization): 非破坏性上下文压缩——保留原始对话仅在请求时瞬态压缩

重写 DeerFlowSummarizationMiddleware:将 stock before_model 的
RemoveMessage(REMOVE_ALL_MESSAGES) 改为 no-op,改在 wrap_model_call 中
瞬态压缩为 [summary, *recent],完整原始对话仍保留在 state 中,前端继续
渲染用户真实问答。summary 消息标记 hide_from_ui 且永不持久化,按 thread
缓存以避免每次模型调用都触发 LLM。前端 isHiddenFromUIMessage 额外隐藏旧
版本持久化的 name="summary" 消息。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
AdministratorandClaude Opus 4.8 committed 2026-06-11 08:34:28 +08:00
commit 22222308a1
47 files changed
+2856 -1063

No files matched your search

@@ -70,6 +70,14 @@ class TaskUpdateRequest(BaseModel):
messages: list[dict[str, Any]] | None = None
class TaskEnsureRequest(BaseModel):
"""get-or-create:宿主传的 taskId 不固定,新 id 直接**初始化**一条空记录返回(不 404)。"""
id: str = Field(min_length=1, max_length=64)
title: str = Field(default="", max_length=512)
brief: str | None = None
agents: list[TaskAgentSchema] = []
# ── helpers ──────────────────────────────────────────────────────────────
@@ -115,6 +123,30 @@ async def create_task(request: Request, body: TaskCreateRequest) -> TaskResponse
return TaskResponse(**row)
@router.post("/ensure", response_model=TaskResponse)
async def ensure_task(request: Request, body: TaskEnsureRequest) -> TaskResponse:
"""存在则返回(含 messages 供回显);不存在则用该 id **初始化**一条空记录返回。
宿主传的 taskId 不固定:新 id 不再 404,而是即时建好、可直接回显/保存。幂等。
"""
store = _get_store(request)
user_id = _current_user_id(request)
existing = await store.get_task(body.id, user_id)
if existing is not None:
return TaskResponse(**existing)
row = await store.create_task(
user_id,
{
"id": body.id,
"title": body.title.strip(),
"brief": body.brief,
"agents": [a.model_dump() for a in body.agents],
"messages": [],
},
)
return TaskResponse(**row)
@router.get("/{task_id}", response_model=TaskResponse)
async def get_task(request: Request, task_id: str) -> TaskResponse:
store = _get_store(request)
@@ -276,6 +276,13 @@ def _build_task_message(task_name: str, brief: str) -> str:
"调度对象 / 分配给『…』的任务 / agent_name」之类调度内容,严禁罗列或转派其他席位的任务,严禁调用"
"任何派活 / 调度类工具,也不要用脚本(bash / python)去调用内部接口或翻找派活脚本。"
)
# 澄清护栏:要向用户确认时,必须用 ask_clarification 工具发起(前端据此渲染可点击的协作
# 卡片),不能只把问题写在正文里 —— 否则用户看不到卡片、无法回应。能合理假设就先假设并标注。
parts.append(
"【需要向用户确认时】如果确实缺少完成分析所必需的关键信息,请**调用 `ask_clarification` 工具**"
"发起确认(这样用户会看到一张可点击的协作卡片来回答);**不要只把问题写在正文里**,否则用户无法回应。"
"能基于已有信息合理假设的,就先假设并在正文中标注你的假设;只有当不同假设会显著改变结论时,才发起确认。"
)
return "\n\n".join(parts)