Skip to content

fix(feishu): proactively update approval card via API to avoid 220340 callback failure#13929

Open
HiddenPuppy wants to merge 7 commits into
NousResearch:mainfrom
HiddenPuppy:fix/feishu-approval-card-220340
Open

fix(feishu): proactively update approval card via API to avoid 220340 callback failure#13929
HiddenPuppy wants to merge 7 commits into
NousResearch:mainfrom
HiddenPuppy:fix/feishu-approval-card-220340

Conversation

@HiddenPuppy

Copy link
Copy Markdown
Contributor

Summary

Fixes #13924

Problem

When a user clicks an approval button (Allow Once, Session, Always, Deny) on a Feishu interactive card, the action returns error:

"出错了,请稍后再试 code: 220340"

The approval is never processed — the agent remains blocked.

Root Cause

The _handle_approval_card_action() method returns a P2CardActionTriggerResponse with a CallBackCard containing the resolved card. Feishu is supposed to update the card inline using this response, but over some transports this callback response path fails with error 220340.

Meanwhile, _resolve_approval() is scheduled asynchronously and correctly calls resolve_gateway_approval(), but the card is never updated to show the resolution.

Fix

In _resolve_approval(), proactively call im.v1.message.update with the resolved card BEFORE calling resolve_gateway_approval(). This uses the stored message_id from _approval_state, so it doesn't depend on the callback response path at all.

  • Card is updated even if approval resolution fails
  • If the API update also fails, we log a warning but still resolve the approval so the agent isn't blocked
  • The callback response is still returned for clients where it works

Changes

  • gateway/platforms/feishu.py: _resolve_approval() — added proactive card update via im.v1.message.update

Verification

  • Trigger a dangerous command in Feishu
  • Click an approval button
  • Card updates to show "✅ Approved by " or "❌ Denied by "
  • Agent unblocks and continues

Checklist

  • Bug fix (non-breaking change which fixes an issue)
  • New feature
  • Breaking change
  • Requires documentation update

Jerome added 7 commits April 22, 2026 15:18
…call messages for Kimi /coding

Fixes NousResearch#13848

Kimi's /coding endpoint speaks the Anthropic Messages protocol but has its
own thinking semantics: when thinking is enabled, Kimi validates message
history and requires every prior assistant tool-call message to carry
OpenAI-style reasoning_content.

The Anthropic path never populated that field, and
convert_messages_to_anthropic strips all Anthropic thinking blocks on
third-party endpoints — so the request failed with HTTP 400:
  "thinking is enabled but reasoning_content is missing in assistant
tool call message at index N"

Now, when an assistant message contains tool_calls and a
reasoning_content string, we append a {"type": "thinking", ...} block
to the Anthropic content so Kimi can validate the history.  This only
affects assistant messages with tool_calls + reasoning_content; plain
text assistant messages are unchanged.
Map tsuijinglei@gmail.com → hiddenpuppy.
…t exhaustion for fallback

Fixes NousResearch#13887

OpenRouter returns HTTP 403 (not 402) for key-limit and spend-limit
errors.  The existing _is_payment_error() only checked 402/429/None,
so these 403s were not classified as payment exhaustion and auxiliary
calls would fail immediately instead of falling back to the next provider.

Now _is_payment_error() also checks status == 403 and looks for
OpenRouter-specific keywords: key limit, spending limit, spend limit,
total limit, credit limit, quota exceeded.

This keeps the fix scoped: only 403s with these specific phrases are
treated as payment errors.  Other 403s (auth, forbidden, etc.) still
raise normally.

The fallback path already skips the failed provider via
_try_payment_fallback(), so no changes are needed there.
Map jerome@clawwork.ai → HiddenPuppy.
…H/tunnels

Fixes NousResearch#13870

prompt_toolkit sends \x1b[6n (Device Status Report) to query cursor
position; the terminal replies with \x1b[row;colR. Over SSH/cloudflared
tunnels these CPR responses leak as raw text (e.g. 20
…sections

Fixes NousResearch#13396

PUT /api/config was calling save_config() with only the payload from the
client, which replaced the entire ~/.hermes/config.yaml file. If a dashboard
UI sent only the sections it manages (agent, display), everything else
(model, custom_providers, compression, auxiliary, fallback_model, etc.) was
silently deleted.

Now update_config() loads the existing config, deep-merges the incoming
payload into it, and saves the merged result. Keys present in the payload
overwrite existing values; keys absent from the payload are preserved.

This matches the behavior third-party clients already assume and prevents
accidental data loss.
… callback failure

Fixes NousResearch#13924

When a user clicks an approval button on a Feishu interactive card, the
synchronous callback response (P2CardActionTriggerResponse with CallBackCard)
sometimes fails with error 220340, leaving the card unchanged and the user
confused about whether the action worked.

Root cause: Feishu's card-action callback response path is unreliable over
some transports. The card update in the callback response may be rejected
while the approval resolution (scheduled asynchronously) succeeds.

Fix: In _resolve_approval(), proactively call im.v1.message.update with the
resolved card BEFORE calling resolve_gateway_approval(). This uses the stored
message_id from _approval_state, so it doesn't depend on the callback response
path at all.

- Card is updated even if approval resolution fails
- If the API update also fails, we log a warning but still resolve the
  approval so the agent isn't blocked
- The callback response is still returned for clients where it works
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery platform/feishu Feishu / Lark adapter labels Apr 22, 2026
@xxzzzEkko

Copy link
Copy Markdown

建议合并改进方案

我在 #35090 中实现了更完善的修复方案(已关闭,本 PR 更早),核心改进:

1. 主动 API 更新回退

2. 通用卡片更新模板

新增 方法,将蓝色⏳卡片自动更新为绿色✅状态。

3. 自然语言审批命令别名

在 中添加别名映射,支持 等自然语言输入。

4. 完整测试覆盖

  • — 6 个新测试
  • — 别名测试

建议:将这些改进合并到 PR 中,可以更全面地解决飞书卡片交互问题。

仓库:https://github.com/xxzzzEkko/hermes-agent/tree/fix/feishu-approval-card-update

@xxzzzEkko

Copy link
Copy Markdown

建议合并改进方案

我在 #35090 中实现了更完善的修复方案(已关闭,本 PR 更早),核心改进:

1. 主动 API 更新回退

_handle_card_action_event 中主动调用 PATCH API 更新卡片:

  • 提取 message_id 从事件上下文
  • 构建更新后的卡片内容
  • 通过 _update_card_message() 调用飞书 PATCH API

2. 通用卡片更新模板

新增 _build_generic_processed_card() 方法,将蓝色⏳卡片自动更新为绿色✅状态,显示操作类型、操作人等信息。

3. 自然语言审批命令别名

gateway/run.py 中添加别名映射,支持自然语言输入:

  • yes/ok/approve/once → approve once
  • session/approve session → approve session
  • always/approve always → approve always
  • deny/no/cancel → deny

4. 完整测试覆盖

  • test_feishu_approval_buttons.py — 6 个新测试
  • test_approve_deny_commands.py — 别名测试

建议:将这些改进合并到 PR 中,可以更全面地解决飞书卡片交互问题。

仓库:https://github.com/xxzzzEkko/hermes-agent/tree/fix/feishu-approval-card-update

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/feishu Feishu / Lark adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feishu: Command Approval buttons return "出错了,请稍后再试 code: 220340" when clicked

3 participants