Skip to content

feat(whatsapp-adapter): Add typing indicator support#320

Merged
dancer merged 2 commits into
vercel:mainfrom
grundmanise:feat/whatsapp-typing-indicator
May 29, 2026
Merged

feat(whatsapp-adapter): Add typing indicator support#320
dancer merged 2 commits into
vercel:mainfrom
grundmanise:feat/whatsapp-typing-indicator

Conversation

@grundmanise

Copy link
Copy Markdown
Contributor

Summary

Adds typing indicator support for WhatsApp and also bumps the API version to the latest v25.0.

Good to know: There is a limitation with typing indicator API: it has a 25-second cooldown and rqeuires a recent incoming message. This means if you try to display the typing indicator before the cooldown period has passed, it won’t show up, but the message will still be marked with a red check mark.

Test plan

Verified end-to-end on a real WhatsApp Business profile

@vercel

vercel Bot commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

@grundmanise is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

Comment thread packages/adapter-whatsapp/src/index.ts Outdated
@grundmanise

grundmanise commented Apr 7, 2026

Copy link
Copy Markdown
Contributor Author

I understand this isn’t the only contribution here, nor your only job or project, but seeing the number of PRs keep growing, I have a question: is this project still interested in contributions?

cc @cramforce, @haydenbleasel

@grundmanise grundmanise force-pushed the feat/whatsapp-typing-indicator branch 2 times, most recently from b0d9707 to 104df5e Compare April 22, 2026 22:29
@Mecrano

Mecrano commented May 28, 2026

Copy link
Copy Markdown

@dancer Can you maybe help us with this? this will be a really good feature pls

@dancer dancer requested a review from a team as a code owner May 29, 2026 17:52
@dancer dancer force-pushed the feat/whatsapp-typing-indicator branch from 9108129 to 2f2ad7f Compare May 29, 2026 18:03
@dancer dancer merged commit ffc43fc into vercel:main May 29, 2026
3 of 5 checks passed
@dancer

dancer commented May 29, 2026

Copy link
Copy Markdown
Collaborator

ty for pr @grundmanise sorry for delay
@Mecrano ty for the ping

will be released on monday

patrick-chinchill pushed a commit to Chinchill-AI/chat-sdk-python that referenced this pull request Jun 18, 2026
Port of upstream ffc43fc:
- start_typing resolves the latest inbound message ID from the
  ThreadHistoryCache and posts a typing_indicator payload (which also
  marks the referenced message as read); no-ops with a warning when no
  inbound message context exists
- Graph API default version bumped v21.0 -> v25.0
- _graph_api_request and the typing-indicator failure path raise
  AdapterError instead of RuntimeError/plain Error
- new WhatsAppTypingIndicatorResponse TypedDict

https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64
patrick-chinchill added a commit to Chinchill-AI/chat-sdk-python that referenced this pull request Jun 18, 2026
,523,553,573) (#141)

* feat(whatsapp): typing indicator support (vercel/chat#320)

Port of upstream ffc43fc:
- start_typing resolves the latest inbound message ID from the
  ThreadHistoryCache and posts a typing_indicator payload (which also
  marks the referenced message as read); no-ops with a warning when no
  inbound message context exists
- Graph API default version bumped v21.0 -> v25.0
- _graph_api_request and the typing-indicator failure path raise
  AdapterError instead of RuntimeError/plain Error
- new WhatsAppTypingIndicatorResponse TypedDict

https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64

* fix(gchat): collapse redundant autolink formatting for email links (vercel/chat#553)

Port of upstream 177735a: when a link node's visible label equals its
URL minus a mailto:/tel: scheme (e.g. an autolinked email address),
from_ast emits the bare value as plain text instead of the verbose
<url|text> form. Labels differing from the address keep <url|text>.

The collapse sits between the linkText==url shortcut and this port's
documented divergent branches (empty-label bare-URL emit and the
text-(url) fallback for unsafe labels/URLs), matching upstream's
check order; when it fires the output is plain text, so it never
produces the malformed forms those divergences guard against. Our
subset parser does not autolink bare emails/URLs (Known Limitations),
so the ported collapse tests build the autolink-shaped node via the
explicit markdown form, plus a Python-only round-trip test through the
divergent <url|text> to_ast path.

https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64

* fix(slack): resolve reaction user display names (vercel/chat#523)

Port of upstream b63c042: reaction events now resolve
event.user.user_name / full_name / is_bot from the cached
_lookup_user() (users.info) path instead of echoing the raw Slack user
ID, falling back to the user ID (and is_bot=False) when lookup fails.

Also completes the dispatch-key test's mock client/state contract
(users_info + async state methods), mirroring the upstream test update
- a bare AsyncMock's auto-children made users.info results async and
leaked an orphaned coroutine through the new lookup.

https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64

* fix(slack): pass token through native stream stop (vercel/chat#573)

Port of upstream 999d268: SlackAdapter.stream() now passes the resolved
bot token on every streamer.append() (markdown deltas and structured
chunks) and on streamer.stop(), instead of only on the first append.
Fixes not_authed from chat.startStream/chat.stopStream when a stream
reaches stop() before a token-bearing append has flushed (e.g. fully
buffered markdown).

Composes with the existing multi-workspace plumbing: token is resolved
once at stream entry via _get_token() (request-context installation
token -> per-request resolved default -> static cache), then threaded
through all streamer calls; a Python-only regression test locks the
request-context token flowing through append and stop.

https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64

* fix(slack): emit uploadedFileIds (camelCase) on raw to match upstream chat@4.30.0

Our Python-only "file-ids" surface (Slack-confirmed upload IDs exposed on
RawMessage.raw so consumers can gate on actual delivery) was adopted
upstream in chat@4.30.0, which emits the synthetic key as camelCase
`uploadedFileIds`. We were emitting snake_case `uploaded_file_ids`,
leaving a divergence at the serialization boundary.

Rename the emitted dict key to `uploadedFileIds` so consumers reading the
raw payload match the upstream/TS surface. The local variable stays
snake_case (`uploaded_file_ids`) per the "snake_case internal, camelCase
at boundary" rule; only the key merged into `raw` changes. Behavior is
otherwise identical (None -> raw unchanged; empty list preserved as the
zero-attachments signal).

Updates the three Python-only tests that asserted the old key name
(test_slack_api file-upload tests and the test_thread_faithful raw-
propagation test, which uses Slack's surface as its example payload).

https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants