fix(fsapp): rollover oversized Feishu task cards (#209)

This commit is contained in:
hanshou101 authored and GitHub committed 2026-05-02 14:54:46 +08:00
1 parent 74831f83f7
commit bf002e5bcc
1 file changed
+45 -9
+45 -9
View File
@@ -268,13 +268,18 @@ def _send_raw(receive_id, payload, msg_type, rtype):
def _patch_card(message_id, card_json): def _patch_card(message_id, card_json):
return _patch_card_result(message_id, card_json)[0]
def _patch_card_result(message_id, card_json):
body = PatchMessageRequest.builder().message_id(message_id).request_body( body = PatchMessageRequest.builder().message_id(message_id).request_body(
PatchMessageRequestBody.builder().content(card_json).build() PatchMessageRequestBody.builder().content(card_json).build()
).build() ).build()
r = client.im.v1.message.patch(body) r = client.im.v1.message.patch(body)
if not r.success(): if not r.success():
print(f"[ERROR] patch_card 失败: {r.code}, {r.msg}") print(f"[ERROR] patch_card 失败: {r.code}, {r.msg}")
return r.success() msg = f"{getattr(r, 'code', '')} {getattr(r, 'msg', '')}".lower()
return r.success(), ("230099" in msg or "11310" in msg or "element exceeds the limit" in msg)
def send_message(receive_id, content, msg_type="text", use_card=False, receive_id_type="open_id"): def send_message(receive_id, content, msg_type="text", use_card=False, receive_id_type="open_id"):
@@ -467,6 +472,7 @@ def _build_step_detail(resp, tool_calls):
class _TaskCard: class _TaskCard:
"""飞书任务卡片:单卡片持续 patch;每步一个独立折叠面板(header 显示 summary,展开看详情)。""" """飞书任务卡片:单卡片持续 patch;每步一个独立折叠面板(header 显示 summary,展开看详情)。"""
_DETAIL_LIMIT = 8000 _DETAIL_LIMIT = 8000
_FINAL_LIMIT = 6000
def __init__(self, receive_id, rid_type): def __init__(self, receive_id, rid_type):
self.rid, self.rtype = receive_id, rid_type self.rid, self.rtype = receive_id, rid_type
@@ -474,6 +480,10 @@ class _TaskCard:
self.status = "🤔 思考中..." self.status = "🤔 思考中..."
self.final = None self.final = None
self.msg_id = None self.msg_id = None
self.page_no = 1
self.turn_no = 0
self.turn_base = 1
self.note = None
def _step_panel(self, idx, summary, detail): def _step_panel(self, idx, summary, detail):
detail = detail or "_(无输出)_" detail = detail or "_(无输出)_"
@@ -486,8 +496,13 @@ class _TaskCard:
} }
def _build(self): def _build(self):
els = [{"tag": "markdown", "content": f"**{self.status}**"}] header = f"**{self.status}**"
for i, (s, d) in enumerate(self.steps, 1): if self.page_no > 1:
header += f"\n\n📄 工作卡片 {self.page_no}"
els = [{"tag": "markdown", "content": header}]
if self.note:
els.append({"tag": "markdown", "content": self.note})
for i, (s, d) in enumerate(self.steps, self.turn_base):
els.append(self._step_panel(i, s, d)) els.append(self._step_panel(i, s, d))
if self.final: if self.final:
els += [{"tag": "hr"}, {"tag": "markdown", "content": self.final}] els += [{"tag": "hr"}, {"tag": "markdown", "content": self.final}]
@@ -496,9 +511,16 @@ class _TaskCard:
def _push(self): def _push(self):
card = self._build() card = self._build()
if self.msg_id: if self.msg_id:
_patch_card(self.msg_id, card) return _patch_card_result(self.msg_id, card)
else: else:
self.msg_id = _send_raw(self.rid, card, "interactive", self.rtype) self.msg_id = _send_raw(self.rid, card, "interactive", self.rtype)
return bool(self.msg_id), False
def _rollover(self):
self.page_no += 1
self.msg_id = None
self.final = None
self.note = "⚠️ 上一张工作卡片达到飞书限制,本页继续展示后续进展。"
# ── 公开接口 ── # ── 公开接口 ──
@@ -506,14 +528,28 @@ class _TaskCard:
self._push() self._push()
def step(self, summary, detail=""): def step(self, summary, detail=""):
self.steps.append((summary, detail)) self.turn_no += 1
self.status = f"⏳ 工作中 · Turn {len(self.steps)}" step = (summary, detail)
self._push() self.steps.append(step)
self.status = f"⏳ 工作中 · Turn {self.turn_no}"
ok, limit = self._push()
if limit:
self.steps.pop()
self._rollover()
self.turn_base = self.turn_no
self.steps = [step]
self._push()
def done(self, text): def done(self, text):
self.status = "✅ 已完成" self.status = "✅ 已完成"
self.final = text or "_(无文本输出)_" self.final = (text or "_(无文本输出)_")[:self._FINAL_LIMIT]
self._push() ok, limit = self._push()
if limit:
self._rollover()
self.steps = []
self.turn_base = self.turn_no + 1
self.final = (text or "_(无文本输出)_")[:self._FINAL_LIMIT]
self._push()
def fail(self, msg): def fail(self, msg):
self.status = f"❌ {msg}" self.status = f"❌ {msg}"