Skip to content

fix(channels): support display cards (send_card) in Chat SDK bridge#2265

Merged
glifocat merged 4 commits intoqwibitai:mainfrom
glifocat:fix/send-card-bridge
May 5, 2026
Merged

fix(channels): support display cards (send_card) in Chat SDK bridge#2265
glifocat merged 4 commits intoqwibitai:mainfrom
glifocat:fix/send-card-bridge

Conversation

@glifocat
Copy link
Copy Markdown
Collaborator

@glifocat glifocat commented May 4, 2026

Type of Change

  • Fix - bug fix or security fix to source code

Description

send_card (the MCP tool exposed by container/agent-runner/src/mcp-tools/interactive.ts) was a silent no-op on every Chat SDK channel because chat-sdk-bridge.ts:deliver() had no branch for content.type === 'card'. The payload fell through to the text fallback, where text was undefined and the function returned without calling the adapter. delivery.ts then marked the message delivered with platformMsgId=undefined and the user saw nothing.

This PR adds the missing branch, mirroring the structure of the existing ask_question branch.

How it works

When a chat-sdk outbound row has content.type === 'card':

  • Build a Card from card.title, card.description, and card.children (string or { text } shapes both supported)
  • For card.actions, render only entries with a url as LinkButtons inside an Actions row. Non-URL actions are dropped because send_card is fire-and-forget per its tool docstring ("renders a structured card and returns immediately — it does not pause your turn or collect a response"); a callback button would have nowhere to land
  • Empty cards (no title, no body) are dropped with a warn log instead of posting a blank message
  • Fallback text falls through content.fallbackTextcard.descriptioncard.title → empty

How it was tested

  • pnpm exec vitest run src/channels/chat-sdk-bridge.test.ts → 12/12 passing (5 new + 7 existing)
  • pnpm run typecheck → clean
  • Manually reproduced on Discord and Telegram with a running install: cards now render; notifications still work

Backward compatibility

No risk. Pre-fix card payloads in existing outbound DBs were already marked delivered (the bridge returned undefined, which delivery.ts treats as success). They will not be re-delivered after the fix.

Scope

Affects every Chat SDK adapter that goes through the bridge: Discord, Telegram, Slack, Teams, GChat, GitHub, Linear, WhatsApp Cloud, iMessage, Matrix, Webex, Resend.

Closes #2263

The send_card MCP tool wrote outbound rows with type='card' but the
chat-sdk-bridge deliver() had no branch for them, so the payload fell
through to the text fallback (where text is undefined) and silently
returned without calling the adapter. delivery.ts then marked the
message delivered with platformMsgId=undefined and the user saw nothing.

Add a dedicated card branch mirroring the ask_question structure:
- Build Card from title, description, and string-or-{text} children
- Render only URL actions as LinkButtons (send_card is fire-and-forget
  per its docstring, so callback buttons would have nowhere to land)
- Drop empty cards with a warn log instead of posting blank
- Fall back text: content.fallbackText > description > title

Affects every Chat SDK adapter that goes through the bridge: Discord,
Telegram, Slack, Teams, GChat, GitHub, Linear, WhatsApp Cloud, iMessage,
Matrix, Webex, Resend.

Tests: adds five cases covering normal render, action filtering,
link-button rendering, empty-card skip, and a regression check that
non-card chat-sdk payloads still flow through the text branch.

Closes qwibitai#2263
@github-actions github-actions Bot added follows-guidelines PR was created using the current contributing template PR: Fix Bug fix labels May 4, 2026
@glifocat
Copy link
Copy Markdown
Collaborator Author

glifocat commented May 4, 2026

Format check now passes after a57bb8f. The remaining CI failure is the same unrelated pre-existing flake in src/host-sweep.test.ts (resetStuckProcessingRows — orphan claim cleanup, both cases) — reproduces on a clean checkout of upstream main at 1404f7f with pnpm exec vitest run src/host-sweep.test.ts2 failed | 12 passed. The fix is in flight as #2209 ("fix(host-sweep): orphan-claim delete missed in tests (regression from #2183)").

This PR's own tests pass: pnpm exec vitest run src/channels/chat-sdk-bridge.test.ts12 passed (12), including 5 new cases covering the card branch.

@glifocat glifocat merged commit 644ad2f into qwibitai:main May 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

follows-guidelines PR was created using the current contributing template PR: Fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: send_card MCP tool silently no-ops on every Chat SDK channel

2 participants