Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 45 additions & 9 deletions frontends/fsapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"):
Expand Down Expand Up @@ -467,13 +472,18 @@ 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
self.steps = [] # [(summary, detail), ...]
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 "_(无输出)_"
Expand All @@ -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}]
Expand All @@ -496,24 +511,45 @@ 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 = "⚠️ 上一张工作卡片达到飞书限制,本页继续展示后续进展。"

# ── 公开接口 ──

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}"
Expand Down