diff --git a/skills/lark-event/references/lark-event-im.md b/skills/lark-event/references/lark-event-im.md index 4272c001b..2578a90b1 100644 --- a/skills/lark-event/references/lark-event-im.md +++ b/skills/lark-event/references/lark-event-im.md @@ -23,6 +23,8 @@ > **Shape**: All 12 events have a V2-enveloped raw payload. `lark-cli` flattens two of them — `im.message.receive_v1` and `card.action.trigger` — so their consumed output is flat (fields at `.xxx`). The other 10 are passed through as-is; use `.event.xxx` to access their fields. +For long-running CardKit agent replies, do completion re-notification as a same-card update, not as a new message. The detailed constraints are in [`lark-im-card-action-reply.md#same-card-completion-re-notification`](../../lark-im/references/lark-im-card-action-reply.md#same-card-completion-re-notification). + ## Gotchas (`im.message.receive_v1`) **sender_id is open_id only**: the event payload carries no display name. Call the contact API separately if you need the sender's name. @@ -84,4 +86,4 @@ lark-cli event consume im.message.receive_v1 --as bot\ --jq 'select(.sender_id=="ou_xxxxxxxxxxxxxxxxxxxxxxxxxx") | {msg_id: .message_id, text: .content}' ``` -Get your own open_id via `lark-cli contact +get-user --as user`; other users' via `lark-cli contact +search-user`. \ No newline at end of file +Get your own open_id via `lark-cli contact +get-user --as user`; other users' via `lark-cli contact +search-user`. diff --git a/skills/lark-im/SKILL.md b/skills/lark-im/SKILL.md index 76eec0250..f20d7bdb0 100644 --- a/skills/lark-im/SKILL.md +++ b/skills/lark-im/SKILL.md @@ -63,6 +63,8 @@ Card messages (`interactive` type) are not yet supported for compact conversion `interactive` cards support callback events (`card.action.trigger`) — see [`references/lark-im-card-action-reply.md`](references/lark-im-card-action-reply.md). +For long-running CardKit agent replies, completion re-notification should update the same card/message instead of sending a new message. Preserve the original message/thread context, do not duplicate the answer content, and follow the same-card pattern in [`references/lark-im-card-action-reply.md#same-card-completion-re-notification`](references/lark-im-card-action-reply.md#same-card-completion-re-notification). + ### Audio Messages `--audio` sends a voice message and supports only Opus audio files, for example `.opus` files or Ogg Opus (`.ogg`) files. For `mp3`, `wav`, or other non-Opus audio, either convert to `.opus` first and keep using `--audio`, or send the original file as an attachment with `--file`. diff --git a/skills/lark-im/references/lark-im-card-action-reply.md b/skills/lark-im/references/lark-im-card-action-reply.md index 7995cdf0b..3b061e385 100644 --- a/skills/lark-im/references/lark-im-card-action-reply.md +++ b/skills/lark-im/references/lark-im-card-action-reply.md @@ -138,6 +138,25 @@ lark-cli api POST /open-apis/interactive/v1/card/update --as bot \ | `card` | Yes | Complete new card JSON — construct based on `card_content` from the event, modified to reflect the new state | | `card.open_ids` | No | **Card 1.0 only.** Array of `open_id`s defining which users see the updated card. Must contain at least one open_id (e.g. the operator's); passing `[]` or omitting the key both cause "openid empty" (code 300090). | +## Same-card completion re-notification + +Use this pattern for long-running agent replies rendered as streaming CardKit cards when the card already reached a final `Completed` / `已完成` state, but the user may have switched away before noticing it. + +The invariant is: **one chat message, one card identity**. Re-notification is a deliberate refresh of the existing CardKit card/message. Do not send a follow-up text message, do not call `im +messages-send` / `im +messages-reply` for completion, and do not duplicate the answer content. + +Recommended sequence: + +1. Send or reply with one `interactive` CardKit card for the agent response. +2. Stream progress by updating that same card. +3. Complete the card by updating its status/header/footer/body to the final completed state. +4. If completion visibility matters, wait briefly and update the same card once more with a complete card JSON that still represents the completed state. +5. Preserve the original `message_id`, card identity, chat, topic, and thread context. Only change small completion affordances such as status text, header subtitle, footer timestamp, or a "completed" hint. +6. Avoid noisy loops. A completion re-notification should be at most one extra same-card update for a given task completion. + +Treat delayed-update failures as terminal when the token is expired, exhausted, missing, or invalid; the original `message_id` / card is not found or has been recalled/deleted; the bot no longer has permission to update it; or the API reports the card is no longer updatable. In those cases, stop retrying the completion refresh and do not fall back to a new chat message. Return or log that the same-card refresh could not be sent, so the caller can decide whether a separate notification is acceptable for that product flow. + +When implementing from a `card.action.trigger` event, use the delayed-update token and the API above. The API requires the complete new card JSON, so start from `card_content`, keep the answer content stable, and change only the completion affordance fields. For Card 1.0, include `card.open_ids` as described above. + ## Examples ```bash