fix(drift-card): Drift Diff HTTP 400 — item-by-item 累計長度避免切斷 HTML
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 2m0s
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 2m0s
統帥回報 14:18 點 [查看 Diff] 收到 'Drift Diff 查詢失敗: HTTP error: 400' 真因 (telegram_gateway.py:2087 _send_drift_diff_detail): - report_id=7ffe78ae 有 48 items,單筆 git_value 最長 1794 字 (env array) - 累計 _full 遠超 4096,執行 _full[:3950] 截斷 - 截斷可能切在 HTML tag 中間 (<code>... 或 < entity 中間) - Telegram parse_mode='HTML' 拒絕不完整 HTML → 400 修復: - item-by-item 累計長度,單個 item 算 _block 長度+1 - 預留 3800 上限 (4096 - 250 buffer 給 header + '… 還有 X 項' 提示) - 確保 _full 永遠是完整 HTML 結構 驗證: 下次 drift report 出現 + 統帥點 [查看 Diff] 應正常顯示 (本 session 的下個 cycle) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2100,26 +2100,44 @@ class TelegramGateway:
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|
||||||
_lines = [f"📊 <b>完整 Drift Diff</b> — <code>{html.escape(report_id)}</code>"]
|
# 2026-04-19 ogt + Claude Opus 4.7: 修 HTTP 400 真因
|
||||||
_lines.append(f"Namespace: <code>{html.escape(_rpt.namespace)}</code>")
|
# 原邏輯: _full[:3950] 切在 HTML tag/entity 中間 → Telegram parse_mode HTML 拒絕
|
||||||
_lines.append(f"HIGH×{_rpt.high_count} MEDIUM×{_rpt.medium_count} INFO×{_rpt.info_count}")
|
# 修法: item-by-item 累計長度,超過 3800 就停,確保完整 HTML 結構
|
||||||
_lines.append("━" * 20)
|
# (3800 留 250 buffer 給 header + 截斷提示)
|
||||||
for i, _item in enumerate(_rpt.items[:50], 1):
|
_MAX_LEN = 3800
|
||||||
|
|
||||||
|
_header = [
|
||||||
|
f"📊 <b>完整 Drift Diff</b> — <code>{html.escape(report_id)}</code>",
|
||||||
|
f"Namespace: <code>{html.escape(_rpt.namespace)}</code>",
|
||||||
|
f"HIGH×{_rpt.high_count} MEDIUM×{_rpt.medium_count} INFO×{_rpt.info_count}",
|
||||||
|
"━" * 20,
|
||||||
|
]
|
||||||
|
_lines = list(_header)
|
||||||
|
_used_len = sum(len(s) + 1 for s in _header)
|
||||||
|
_shown = 0
|
||||||
|
|
||||||
|
for _item in _rpt.items:
|
||||||
_level = getattr(_item.drift_level, "value", str(_item.drift_level))
|
_level = getattr(_item.drift_level, "value", str(_item.drift_level))
|
||||||
_emoji = "🔴" if _level == "high" else ("🟡" if _level == "medium" else "⚪")
|
_emoji = "🔴" if _level == "high" else ("🟡" if _level == "medium" else "⚪")
|
||||||
_field = (_item.field_path or "")[:80]
|
_field = (_item.field_path or "")[:80]
|
||||||
_git = str(_item.git_value)[:40] if _item.git_value is not None else "(未設)"
|
_git = str(_item.git_value)[:40] if _item.git_value is not None else "(未設)"
|
||||||
_k8s = str(_item.actual_value)[:40] if _item.actual_value is not None else "(未設)"
|
_k8s = str(_item.actual_value)[:40] if _item.actual_value is not None else "(未設)"
|
||||||
_lines.append(f"{_emoji} <b>{html.escape(_field)}</b>")
|
_block = (
|
||||||
_lines.append(f" Git: <code>{html.escape(_git)}</code>")
|
f"{_emoji} <b>{html.escape(_field)}</b>\n"
|
||||||
_lines.append(f" K8s: <code>{html.escape(_k8s)}</code>")
|
f" Git: <code>{html.escape(_git)}</code>\n"
|
||||||
if len(_rpt.items) > 50:
|
f" K8s: <code>{html.escape(_k8s)}</code>"
|
||||||
_lines.append(f"… 還有 {len(_rpt.items) - 50} 項未顯示")
|
)
|
||||||
|
if _used_len + len(_block) + 1 > _MAX_LEN:
|
||||||
|
break
|
||||||
|
_lines.append(_block)
|
||||||
|
_used_len += len(_block) + 1
|
||||||
|
_shown += 1
|
||||||
|
|
||||||
|
_remaining = len(_rpt.items) - _shown
|
||||||
|
if _remaining > 0:
|
||||||
|
_lines.append(f"… 還有 {_remaining} 項未顯示")
|
||||||
|
|
||||||
_full = "\n".join(_lines)
|
_full = "\n".join(_lines)
|
||||||
# Telegram 訊息上限 4096 字元
|
|
||||||
if len(_full) > 4000:
|
|
||||||
_full = _full[:3950] + "\n… (截斷)"
|
|
||||||
|
|
||||||
await self._send_request("sendMessage", {
|
await self._send_request("sendMessage", {
|
||||||
"chat_id": settings.OPENCLAW_TG_CHAT_ID,
|
"chat_id": settings.OPENCLAW_TG_CHAT_ID,
|
||||||
|
|||||||
Reference in New Issue
Block a user