diff --git a/frontends/fsapp.py b/frontends/fsapp.py index c7f9fa1d..9dcabfe4 100644 --- a/frontends/fsapp.py +++ b/frontends/fsapp.py @@ -268,13 +268,18 @@ def _send_raw(receive_id, payload, msg_type, rtype): 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( PatchMessageRequestBody.builder().content(card_json).build() ).build() r = client.im.v1.message.patch(body) if not r.success(): 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"): @@ -467,6 +472,7 @@ def _build_step_detail(resp, tool_calls): class _TaskCard: """飞书任务卡片:单卡片持续 patch;每步一个独立折叠面板(header 显示 summary,展开看详情)。""" _DETAIL_LIMIT = 8000 + _FINAL_LIMIT = 6000 def __init__(self, receive_id, rid_type): self.rid, self.rtype = receive_id, rid_type @@ -474,6 +480,10 @@ def __init__(self, receive_id, rid_type): self.status = "🤔 思考中..." self.final = 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): detail = detail or "_(无输出)_" @@ -486,8 +496,13 @@ def _step_panel(self, idx, summary, detail): } def _build(self): - els = [{"tag": "markdown", "content": f"**{self.status}**"}] - for i, (s, d) in enumerate(self.steps, 1): + header = f"**{self.status}**" + 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)) if self.final: els += [{"tag": "hr"}, {"tag": "markdown", "content": self.final}] @@ -496,9 +511,16 @@ def _build(self): def _push(self): card = self._build() if self.msg_id: - _patch_card(self.msg_id, card) + return _patch_card_result(self.msg_id, card) else: 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 @@ def start(self): self._push() def step(self, summary, detail=""): - self.steps.append((summary, detail)) - self.status = f"⏳ 工作中 · Turn {len(self.steps)}" - self._push() + self.turn_no += 1 + step = (summary, detail) + 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): self.status = "✅ 已完成" - self.final = text or "_(无文本输出)_" - self._push() + self.final = (text or "_(无文本输出)_")[:self._FINAL_LIMIT] + 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): self.status = f"❌ {msg}"