diff --git a/apps/api/src/services/telegram_gateway.py b/apps/api/src/services/telegram_gateway.py index 32b7f212..9f28f5de 100644 --- a/apps/api/src/services/telegram_gateway.py +++ b/apps/api/src/services/telegram_gateway.py @@ -2100,26 +2100,44 @@ class TelegramGateway: }) return - _lines = [f"📊 完整 Drift Diff{html.escape(report_id)}"] - _lines.append(f"Namespace: {html.escape(_rpt.namespace)}") - _lines.append(f"HIGH×{_rpt.high_count} MEDIUM×{_rpt.medium_count} INFO×{_rpt.info_count}") - _lines.append("━" * 20) - for i, _item in enumerate(_rpt.items[:50], 1): + # 2026-04-19 ogt + Claude Opus 4.7: 修 HTTP 400 真因 + # 原邏輯: _full[:3950] 切在 HTML tag/entity 中間 → Telegram parse_mode HTML 拒絕 + # 修法: item-by-item 累計長度,超過 3800 就停,確保完整 HTML 結構 + # (3800 留 250 buffer 給 header + 截斷提示) + _MAX_LEN = 3800 + + _header = [ + f"📊 完整 Drift Diff{html.escape(report_id)}", + f"Namespace: {html.escape(_rpt.namespace)}", + 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)) _emoji = "🔴" if _level == "high" else ("🟡" if _level == "medium" else "⚪") _field = (_item.field_path or "")[:80] _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 "(未設)" - _lines.append(f"{_emoji} {html.escape(_field)}") - _lines.append(f" Git: {html.escape(_git)}") - _lines.append(f" K8s: {html.escape(_k8s)}") - if len(_rpt.items) > 50: - _lines.append(f"… 還有 {len(_rpt.items) - 50} 項未顯示") + _block = ( + f"{_emoji} {html.escape(_field)}\n" + f" Git: {html.escape(_git)}\n" + f" K8s: {html.escape(_k8s)}" + ) + 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) - # Telegram 訊息上限 4096 字元 - if len(_full) > 4000: - _full = _full[:3950] + "\n… (截斷)" await self._send_request("sendMessage", { "chat_id": settings.OPENCLAW_TG_CHAT_ID,