Skip to content

fix(slack): surface files_upload_v2 confirmation in SentMessage.raw#117

Merged
patrick-chinchill merged 2 commits into
mainfrom
fix/slack-surface-upload-confirmation
May 29, 2026
Merged

fix(slack): surface files_upload_v2 confirmation in SentMessage.raw#117
patrick-chinchill merged 2 commits into
mainfrom
fix/slack-surface-upload-confirmation

Conversation

@patrick-chinchill
Copy link
Copy Markdown
Collaborator

@patrick-chinchill patrick-chinchill commented May 29, 2026

Problem — consistency gap

Slack is the only file-capable adapter that discards upload confirmation. SlackAdapter._upload_files calls files_upload_v2 separately and already computes the list of Slack-confirmed file IDs, but post_message threw that return away, and ThreadImpl._create_sent_message hardcoded raw=None — so the confirmation never reached the SentMessage returned to callers.

discord and telegram don't have this gap: they upload inline, so their RawMessage.raw is the real platform response and flows through naturally. SentMessage already has a raw field; it was simply never populated on the post() path.

Changes

src/chat_sdk/adapters/slack/adapter.pypost_message:

  • Capture _upload_files' return (uploaded_file_ids).
  • New _augment_raw_with_uploads helper adds an "uploaded_file_ids" key to RawMessage.raw on every return path that can carry files (file-only early return, card, table, text). The Slack response dict is augmented, never replaced — Slack never returns that key, so it's additive and non-breaking.
  • None = no upload occurred; an empty list = Slack confirmed zero attachments (a real signal, preserved by guarding on is not None).

src/chat_sdk/thread.py:

  • _create_sent_message gains a raw: Any = None parameter and sets raw=raw on the returned SentMessage (was hardcoded None).
  • The post() call site passes raw_msg.raw through. Platform-agnostic — discord/telegram real platform responses now flow through to SentMessage.raw too, which is the intended use of the field.

Why now

Unblocks a chinchill consumer that needs to gate UX on actual Slack delivery success (how many files Slack confirmed attaching), not just how many were requested.

An upstream vercel/chat issue is being filed in parallel for convergence (same gap exists in packages/adapter-slack/src/index.ts).

Test plan

  • uv run pytest tests/ -q4046 passed, 3 skipped (was ~4042; +4 new).
  • New tests (verified load-bearing — each fails when its corresponding change is reverted):
    • tests/test_slack_api.py: file-only post surfaces confirmed IDs; text+files augments the chat_postMessage raw; text-only does not add the key.
    • tests/test_thread_faithful.py: end-to-end post() propagates RawMessage.rawSentMessage.raw.
  • uv run ruff format + uv run ruff check clean.
  • Version bumped 0.4.29a10.4.29a2; CHANGELOG entry added.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Release

    • v0.4.29a2 released (2026-05-28)
  • Bug Fixes

    • Slack file-upload confirmations are now surfaced in post responses, with confirmed file IDs captured and included.
    • Adapter raw payload data is propagated through to sent messages, preserving platform metadata for consumers.
  • Tests

    • Added tests covering file-upload scenarios and message metadata propagation.

Review Change Stack

SlackAdapter._upload_files already returns the list of Slack-confirmed
file IDs, but post_message discarded the return and
ThreadImpl._create_sent_message hardcoded raw=None, so the confirmation
never reached SentMessage.raw. Slack was the only file-capable adapter to
drop upload confirmation; discord/telegram upload inline and expose the
platform response naturally.

- post_message: capture _upload_files' return and augment RawMessage.raw
  with "uploaded_file_ids" on every return path that can carry files
  (file-only, card, table, text), via a new _augment_raw_with_uploads
  helper. None means no upload; empty list means Slack confirmed zero
  attachments. raw is augmented, not replaced — non-breaking.
- thread.py: _create_sent_message accepts and propagates a raw parameter;
  the post() call site passes raw_msg.raw through. Platform-agnostic, so
  discord/telegram real platform responses now flow through too.

Tests: 3 in test_slack_api.py (file-only, text+files, text-only no-augment)
and 1 end-to-end in test_thread_faithful.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e4b6a7ea-16da-4680-ac7b-1ab5fe9aa60e

📥 Commits

Reviewing files that changed from the base of the PR and between d4ad726 and 823dbd4.

📒 Files selected for processing (1)
  • src/chat_sdk/chat.py
✅ Files skipped from review due to trivial changes (1)
  • src/chat_sdk/chat.py

📝 Walkthrough

Walkthrough

This PR captures Slack-uploaded file IDs in the Slack adapter, augments adapter RawMessage.raw with that data when present, propagates the adapter raw through ThreadImpl into SentMessage.raw, updates message-history persistence to null raw, and adds tests and changelog/version bump.

Changes

Upload confirmation metadata propagation

Layer / File(s) Summary
Slack adapter raw payload augmentation with file uploads
src/chat_sdk/adapters/slack/adapter.py, tests/test_slack_api.py
SlackAdapter.post_message captures uploaded_file_ids from _upload_files and conditionally merges them into RawMessage.raw across file-only, text+files, card/table blocks, and regular text posting paths; tests assert augmentation behavior.
Thread raw payload propagation to SentMessage
src/chat_sdk/thread.py, tests/test_thread_faithful.py
ThreadImpl.post() forwards raw_msg.raw into _create_sent_message(raw=...); _create_sent_message accepts an optional raw and assigns it to SentMessage.raw. End-to-end test verifies adapter raw reaches the returned SentMessage.
Message history cache raw clearing
src/chat_sdk/chat.py
_MessageHistoryCache.append sets the serialized raw field to None on the JSON stored to state.
Version and changelog
pyproject.toml, CHANGELOG.md
Package version bumped from 0.4.29a1 to 0.4.29a2 and changelog documents the raw propagation fix and added tests.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through adapters, files in a line,

I caught uploaded IDs, each one a sign,
I carried their raw through thread and through send,
So SentMessage knows what Slack did in the end,
Hooray—now confirmations and history align!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title concisely summarizes the main change: enabling Slack file-upload confirmations to surface through SentMessage.raw, which aligns with the core objective of propagating adapter raw payloads.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a fix to surface Slack-confirmed file IDs through the post() method. Previously, SlackAdapter._upload_files computed these IDs but they were discarded, and ThreadImpl._create_sent_message hardcoded raw=None. The changes update post_message in the Slack adapter to augment RawMessage.raw with "uploaded_file_ids", and update ThreadImpl._create_sent_message to accept and propagate the adapter's raw payload into SentMessage.raw. Corresponding unit and integration tests have been added to verify this behavior. There are no review comments, and I have no additional feedback to provide.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/chat_sdk/thread.py (1)

1125-1136: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Preserve SentMessage.raw across sent.edit() calls.

post() now correctly sets raw, but _edit() rebuilds a new SentMessage without forwarding it, so raw is lost after the first edit.

Suggested fix
         async def _edit(new_content: Any) -> SentMessage:
             await adapter.edit_message(thread_id, message_id, new_content)
-            return thread_impl._create_sent_message(message_id, new_content)
+            return thread_impl._create_sent_message(message_id, new_content, thread_id, raw=raw)

Also applies to: 1164-1164

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/chat_sdk/thread.py` around lines 1125 - 1136, The edit helper _edit
currently rebuilds a SentMessage via thread_impl._create_sent_message without
preserving the original SentMessage.raw, so ensure the raw payload is forwarded:
capture the existing raw value from the surrounding scope (the raw parameter)
and pass it into thread_impl._create_sent_message when returning the edited
SentMessage in _edit; apply the same change to the other edit helper at the
second occurrence (around the _edit at 1164) so SentMessage.raw is preserved
across sent.edit() calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/chat_sdk/thread.py`:
- Around line 1125-1136: The edit helper _edit currently rebuilds a SentMessage
via thread_impl._create_sent_message without preserving the original
SentMessage.raw, so ensure the raw payload is forwarded: capture the existing
raw value from the surrounding scope (the raw parameter) and pass it into
thread_impl._create_sent_message when returning the edited SentMessage in _edit;
apply the same change to the other edit helper at the second occurrence (around
the _edit at 1164) so SentMessage.raw is preserved across sent.edit() calls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e086b0a5-d494-4e60-8f66-d5d31f9b1435

📥 Commits

Reviewing files that changed from the base of the PR and between f0d7f1c and d4ad726.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • pyproject.toml
  • src/chat_sdk/adapters/slack/adapter.py
  • src/chat_sdk/thread.py
  • tests/test_slack_api.py
  • tests/test_thread_faithful.py

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d4ad7267ac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

files = extract_files(message)
if files:
await self._upload_files(files, channel, thread_ts or None)
uploaded_file_ids = await self._upload_files(files, channel, thread_ts or None)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Read Slack file IDs from the actual response shape

When this new path surfaces _upload_files()'s return value, real slack_sdk uploads will usually report uploaded_file_ids: []: the SDK's files_upload_v2 returns the files.completeUploadExternal response and puts uploaded files at completion["files"][i]["id"] (plus completion.data["file"] for a singleton), while _upload_files() only scans a nested uploaded["files"] list at lines 4069-4070. In production Slack uploads, consumers gating on this confirmation will see “zero attachments confirmed” even after successful uploads.

Useful? React with 👍 / 👎.

Post-merge review of PR #117 caught that _MessageHistoryCache.append
in chat.py did not null out raw before persisting (unlike its sibling
MessageHistoryCache.append in message_history.py, which already does).

Without this, the platform raw payload (Slack team_id/user_id,
Discord guild IDs, etc.) that #117 now correctly populates on
SentMessage.raw would persist to Redis/Postgres-backed state on
every reply, inflating storage size and PII surface.

Mirrors the null-out in message_history.py:62.
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.

2 participants