fix(sub-agent): 深度压缩重建 system 消息包装为 dict,根治压缩后首次模型调用必崩

- _deep_compress_messages 此前把 _rebuild_system_prompt 返回的裸字符串直接
  作为 messages[0],压缩后首次模型调用在 _merge_system_messages 的
  msg.get("role") 处崩溃('str' object has no attribute 'get'),
  任何触发 150k tokens 压缩阈值的子智能体 100% 必崩
- _merge_system_messages 入口增加非 dict 归一防御(包装为 system 消息),
  同时避免下游 sanitizer 静默丢弃导致 system prompt 内容丢失
This commit is contained in:
JOJO 2026-08-28 20:12:44 +08:00
parent f9f9032ce5
commit e04b56d967
2 changed files with 18 additions and 1 deletions

View File

@ -1099,7 +1099,10 @@ class SubAgentTask:
summary_text = "\n".join(summary_lines)
# 重建消息列表:冻结的 system prompt + 压缩摘要 system + 保留的最近消息
frozen_system = self._rebuild_system_prompt()
# 注意_rebuild_system_prompt 返回裸字符串,必须包装为标准消息 dict
# 否则下游 API 客户端_merge_system_messages 的 msg.get("role"))会在
# 压缩后的首次模型调用崩溃('str' object has no attribute 'get')。
frozen_system = {"role": "system", "content": self._rebuild_system_prompt()}
compressed_system = {
"role": "system",
"content": summary_text,

View File

@ -44,6 +44,20 @@ class APIClientMessageMixin:
if not messages:
return messages
# 防御:上游偶发会把裸字符串混进消息列表(如子智能体压缩重建的 system
# prompt 文本),直接 .get() 会崩。统一包装为标准 system 消息,保留内容。
# 下游 sanitizer 对非 dict 是静默丢弃,先行归一也能避免内容丢失。
normalized: List[Dict] = []
for item in messages:
if isinstance(item, dict):
normalized.append(item)
else:
normalized.append({
"role": "system",
"content": item if isinstance(item, str) else json.dumps(item, ensure_ascii=False),
})
messages = normalized
merged_contents: List[str] = []
idx = 0
while idx < len(messages) and messages[idx].get("role") == "system":