feat(slack): add webhook primitives subpath#538
Merged
Conversation
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
visyat
approved these changes
May 21, 2026
visyat
left a comment
Collaborator
There was a problem hiding this comment.
Minor NIT: Can we move webhook-* into src/webhook/* instead?
19 tasks
patrick-chinchill
added a commit
to Chinchill-AI/chat-sdk-python
that referenced
this pull request
Jun 18, 2026
…559) (#139) * feat(slack): webhook primitives subpath (vercel/chat#538) Port of upstream b332a03 — adds chat_sdk.adapters.slack.webhook, a lightweight runtime-free subpath for lower-level Slack webhook handling: verifying Slack requests (HMAC v0 + custom verifiers), reading signed webhook bodies, parsing Events API callbacks, slash commands, and interactive payloads into typed dataclasses with provider-native continuation data. The adapter now verifies through the shared verify_slack_request / verify_slack_signature primitives (single implementation — the inline _verify_signature method is removed, matching upstream), reads bodies via the shared read_slack_request_body helper, and sources SlackWebhookVerifier from webhook/types.py. The slack package __init__ is now lazy (PEP 562) so importing the webhook subpath does not pull in the full adapter runtime — the Python analog of upstream's package subpath export boundary. Python-specific notes: verify_slack_signature is sync (no WebCrypto); verify helpers accept a pre-read body= for non-re-readable framework requests; now() returns epoch seconds. https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64 * feat(slack): format primitives subpath (vercel/chat#547) Port of upstream 4c46c26 — adds chat_sdk.adapters.slack.format, a runtime-free subpath for Slack formatting helpers: plain_text/mrkdwn text objects, mrkdwn escaping/unescaping, user/channel/user-group/special mentions, links, localized date tokens, mrkdwn-to-Markdown normalization, Markdown-bold conversion, and ID-based bare-mention linking — without the full Slack adapter, slack_sdk, or the chat runtime. Python-specific notes: option objects (SlackTextOptions, SlackDateOptions) become keyword-only arguments; format_slack_date accepts datetime or an integer unix timestamp (TS Date | number) and the TypeError message says 'datetime' instead of 'Date'. https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64 * feat(slack): api primitives subpath (vercel/chat#548, #559) Port of upstream aba6aa9 (api/client.ts) and 6ed4a43 (api/extra.ts) — adds chat_sdk.adapters.slack.api, a runtime-free subpath exposed upstream as @chat-adapter/slack/api. Provides fetch-based primitives for calling Slack Web API methods (call_slack_api), posting/updating/deleting messages (post_slack_message, post_slack_ephemeral, update_slack_message, delete_slack_message), sending interaction response_url payloads (send_slack_response_url), uploading files through Slack's external upload flow (upload_slack_files), fetching private Slack file URLs with bearer auth (fetch_slack_file), fetching thread replies with cursor pagination (fetch_slack_thread_replies), and opening modal views (open_slack_view) — without the full Slack adapter, slack_sdk, Socket Mode, or the chat runtime. Importing this subpath never imports an HTTP client: the default fetch lazily imports httpx only when a request is actually made (matching the high-level adapter's optional-httpx pattern), and any async HTTP stack can be injected via the fetch= parameter. SlackBotToken is declared locally rather than imported from the adapter's types module, so the subpath stays self-contained and runtime-free — mirroring upstream's independent declaration in api/client.ts. Python-specific notes: option objects become keyword-only arguments; camelCase request fields are emitted at the Slack serialization boundary (markdown_text, reply_broadcast, thread_ts, ...) while the API is snake_case. Python-specific hardening (divergences, see docs/UPSTREAM_SYNC.md Known Non-Parity): send_slack_response_url requires an https://*.slack.com URL and fetch_slack_file requires a Slack-owned file host before forwarding the bearer token (SSRF / token-leak guards mirroring the high-level adapter); upstream validates neither. Tests port api/index.test.ts and api/boundary.test.ts with injected AsyncMock fetches (no network), plus the two divergence guards. https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64 * feat(slack): block kit primitives subpath (vercel/chat#555, #559) Port of upstream dbd8dc5 (blocks/index.ts, types.ts, limits.ts, errors.ts) and 6ed4a43 (blocks/input.ts) — adds chat_sdk.adapters.slack.blocks, a runtime-free subpath exposed upstream as @chat-adapter/slack/blocks. Converts Chat SDK-style card objects into Slack Block Kit blocks (card_to_slack_blocks / card_to_block_kit), a Markdown fallback (card_to_slack_fallback_text / card_to_fallback_text), and emoji-placeholder codes (convert_slack_emoji_placeholders), enforcing docs-backed Slack size limits (LIMITS) for headers, images, actions, select options, fields, and tables. Also ports the generic input-request helpers: input_request_to_slack_blocks (buttons / select / radio / freeform), parse_slack_input_response, build_slack_freeform_view, parse_slack_freeform_value, and answered_slack_input_blocks — without the full Slack adapter, slack_sdk, or the chat runtime. The only cross-module dependency is the sibling format subpath (markdown_bold_to_slack_mrkdwn), which is itself runtime-free. Python-specific notes: the card-input shapes (SlackCardElement and children) are self-contained TypedDicts declared here rather than imported from chat_sdk.cards, keeping the subpath runtime-free. Input field names are snake_case (image_url, initial_option, request_id, allow_freeform, selected_option_value, action_id, block_id), matching chat_sdk.cards and the Python port convention — upstream uses camelCase. Emitted Block Kit dicts keep Slack's API field names verbatim (alt_text, action_id, block_id, static_select, column_settings, raw_text, private_metadata), which is the Slack serialization boundary. Discriminated-union dispatch on the literal type key uses per-branch casts / arg-type ignores, mirroring the high-level adapter's cards.py. Tests port blocks/index.test.ts and blocks/boundary.test.ts with full output equality, plus extra coverage of the parse-None and string-metadata paths. https://claude.ai/code/session_013zwTcMek5rNqBTQvs2oF64 * fix(slack): port dropped parse fields + fix select-action label (4.30 fidelity) Port the SlackFile/SlackUser/SlackViewStateValue primitives and the helpers (parseFiles/inferFileType/parseUser/findPromptBlock/ readPromptText/parseViewValues) that the webhook parse.py port dropped vs upstream chat@4.30.0 packages/adapter-slack/src/webhook/parse.ts: - files[]: populated on every message-like event via _parse_files (mimetype-inferred type, raw retained). - SlackAction.label: now prefers the selected option's text and falls back to the element text (parse.ts:276); surface selected_option_label. - SlackUser: attached as the user object on block_actions / view_submission / view_closed payloads and on each parsed action. - block_actions: restore message_blocks / message_prompt_block / message_prompt_text; view_submission: restore callback_id / private_metadata / values (parseViewValues). Extend webhook primitive tests to lock in every newly-ported field; add Known-Non-Parity rows for the slack/api SSRF + token-leak guards. --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
summary
adds a lightweight
@chat-adapter/slack/webhooksubpath for lower-level Slack webhook handling without pulling in the full Slack adapter runtimethis exposes primitives for verifying Slack requests, reading signed webhook bodies, parsing Events API callbacks, slash commands, and interactive payloads, and returning provider-native continuation data for message-like payloads
this gives framework and infrastructure integrations a small Slack-owned surface they can use directly while keeping
chat, Slack SDK clients, adapter state, dedupe, locks, and subscriptions out of the primitive path