Skip to content

sync: upstream v4.27.0 (alpha 1)#83

Merged
patrick-chinchill merged 5 commits into
mainfrom
claude/sync-upstream-release-J7S7H
May 28, 2026
Merged

sync: upstream v4.27.0 (alpha 1)#83
patrick-chinchill merged 5 commits into
mainfrom
claude/sync-upstream-release-J7S7H

Conversation

@patrick-chinchill
Copy link
Copy Markdown
Collaborator

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

Summary

Sync starter for upstream vercel/chat@4.27.0 (release commit f55378a, Apr 30 2026). No feature ports in this PR — this is the alpha bump that establishes the sync branch and lays out the porting plan. Each of the 22 substantive commits will land as its own PR, matching the cadence used during the 4.26.0 sync (#64, #66, #67, #74, …).

  • Bumps version0.4.27a1
  • Bumps UPSTREAM_PARITY"4.27.0"
  • Updates README.md, CLAUDE.md, CHANGELOG.md with the in-flight status and full sync plan

Upstream tagging note

Upstream cut the entire monorepo on Apr 30 2026 (commit f55378a), bumping packages/chat/package.json from 4.26.0 to 4.27.0. As of this writing only @chat-adapter/shared@4.27.0 got a git tag — no chat@4.27.0 tag was published. Therefore:

  • .github/workflows/lint.yml stays pinned to --branch chat@4.26.0 for now.
  • scripts/fidelity_baseline.json stays pinned to chat@4.26.0. Local devs running fidelity in baseline mode will see a parity mismatch (chat@4.26.0 vs chat@4.27.0) — that's the intended in-flight signal.
  • The pin moves either when upstream publishes a chat@4.27.0 tag, or when the first feature port lands and we point the clone at commit f55378a directly.

Sync scope

22 substantive upstream commits between chat@4.26.0..f55378a. See CHANGELOG.md for the full breakdown by package and per-commit decision (port / already addressed / out of scope).

Highlights:

  • Core: chat.getUser(), ExternalSelect.initialOption + option_groups, thread.post() streaming options, Slack streaming team-ID fix, bundled guides/templates resources.
  • Slack: Socket Mode, dynamic bot_token resolver + webhookVerifier, external-select Block Kit, link-preview unfurl enrichment, email-safe @mention regex, empty-threadTs guard.
  • Teams: native streaming for DMs, DM Graph API conversation-ID resolution, Teams SDK 2.0.8 + User-Agent.
  • Telegram: MarkdownV2 rendering fixes.
  • Discord: dedupe text on card posts.
  • Already addressed in the Python port (existing divergence): concurrency.maxConcurrent honored in concurrent strategy — upstream has caught up to our existing asyncio.Semaphore enforcement.
  • Out of scope: @chat-adapter/web (browser UI; no browser runtime in chat-sdk-python).

Test plan

  • uv run ruff check src/ tests/ scripts/ — passes
  • uv run ruff format --check src/ tests/ scripts/ — 193 files already formatted
  • uv run python scripts/audit_test_quality.py — 0 hard failures, 39 pre-existing warnings
  • TS_ROOT=/tmp/vercel-chat (chat@4.26.0) uv run python scripts/verify_test_fidelity.py --strict — 0 missing (564/564 matched)
  • uv run pytest tests/ — 3,668 pass, 1 pre-existing failure (test_github_webhook.py::TestGitHubAdapterConstructor::test_throws_when_no_auth) unrelated to this PR
  • Lint workflow doesn't run on draft PRs (if: "!github.event.pull_request.draft"); will run when this is marked ready or as feature ports start landing.

For the new upstream HEAD, fidelity reports 22 missing tests — that's the expected sync work captured in the plan above.

https://claude.ai/code/session_01FyMxQn2BEAzmwKS1GZczKj


Generated by Claude Code

Summary by CodeRabbit

  • Documentation

    • Added release notes and sync plan for alpha 0.4.27a1 targeting upstream 4.27.0; updated status badge and version mapping; documented known non-parity items and fidelity expectations.
  • Tests

    • Updated concurrency/throttling tests to match upstream naming and test patterns; added a per-thread slot test (skipped) and adjusted validation/warning semantics.
  • Chores

    • Bumped package/version and declared upstream parity to 4.27.0 for the alpha release.

Review Change Stack

Establish the sync branch for upstream Vercel Chat 4.27.0 (release commit
f55378a, Apr 30 2026). No feature ports yet — this bumps version to
0.4.27a1, sets UPSTREAM_PARITY = "4.27.0", and lays out the 22-commit port
plan in CHANGELOG.md.

Each substantive commit will land as its own PR matching the cadence used
during the 4.26.0 sync (#64, #66, #67, #74, etc.). The fidelity workflow
stays pinned to chat@4.26.0 until the first feature port lands or upstream
publishes a chat@4.27.0 tag (only @chat-adapter/shared@4.27.0 was tagged
on Apr 30; the chat package version was bumped via package.json only).

Local fidelity against chat@4.26.0 still reports 0 missing. Against the
new upstream there are 22 missing tests — the expected sync work.

https://claude.ai/code/session_01FyMxQn2BEAzmwKS1GZczKj
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 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: 525f2c38-2ee5-46c0-b19e-ce05e680d115

📥 Commits

Reviewing files that changed from the base of the PR and between d6b267f and 36a3f84.

📒 Files selected for processing (2)
  • src/chat_sdk/__init__.py
  • tests/test_chat_faithful.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/chat_sdk/init.py

📝 Walkthrough

Walkthrough

This PR prepares the chat-sdk-python repository for an alpha release (0.4.27a1) targeting upstream Vercel Chat 4.27.0. Version constants and metadata are bumped, release notes and sync documentation are created, known non-parity items with upstream are documented, and test names are aligned to upstream conventions.

Changes

Alpha Release 0.4.27a1 Sync Preparation

Layer / File(s) Summary
Version and SDK constant updates
pyproject.toml, src/chat_sdk/__init__.py, README.md
Package version, SDK UPSTREAM_PARITY constant, and README status badge are updated to reflect 0.4.27a1 targeting upstream 4.27.0.
Changelog and sync documentation
CHANGELOG.md, CLAUDE.md
CHANGELOG.md documents the 0.4.27a1 release with 22 upstream commits across adapters, scope notes, and workflow instructions. CLAUDE.md expands version mapping and fidelity-check guidance, clarifying that baseline mode may report parity mismatch during this in-flight sync cycle.
Documented non-parity items
docs/UPSTREAM_SYNC.md
Non-parity table entries clarify that ConcurrencyConfig.max_concurrent should be per-thread (with a skipped test pending refactor) and that Teams adapter does not set the User-Agent: Vercel.ChatSDK header on aiohttp calls.
Test naming and upstream alignment
tests/test_chat_faithful.py
Concurrency tests are renamed to match upstream nomenclature; a per-thread slot tracking test is added but marked skipped; non-concurrent strategy validation test is renamed with updated documentation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • Chinchill-AI/chat-sdk-python#60: Updates to concurrency faithful tests and upstream parity docs around ConcurrencyConfig.max_concurrent, related to semaphore-based enforcement.
  • Chinchill-AI/chat-sdk-python#72: Changes to UPSTREAM_PARITY and CI fidelity checks that interact with parity verification tooling and baseline pin behavior.

Poem

🐰 I nudge the version, hop to 0.4.27a1,

Docs and tests align beneath the sun,
A skipped test waits for thread-wise light,
Changelog sings the sync and nightly fight,
Hooray — an alpha hops into the run!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 'sync: upstream v4.27.0 (alpha 1)' clearly and concisely summarizes the main objective of the PR: establishing an alpha sync to upstream version 4.27.0.
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 initiates the sync with upstream version 4.27.0 by bumping the package version to 0.4.27a1 and updating the UPSTREAM_PARITY constant. It includes a detailed porting plan in the changelog and updates documentation in README.md and CLAUDE.md to reflect the new sync status. Feedback was provided to use full repository references for upstream pull requests in the changelog to ensure they link correctly to the vercel/chat repository instead of local PRs.

Comment thread CHANGELOG.md Outdated
Comment on lines +29 to +58
- [ ] **`chat.getUser(adapter, userId)`** for cross-platform user lookups (#391, upstream commit `a520797`). Adapter-side: each adapter exposes `getUser`. Touches `chat.py`, `types.py` (`User` type extension), and every adapter (`slack`, `teams`, `gchat`, `telegram`, `discord`, `whatsapp`, `github`, `linear`).
- [ ] **`ExternalSelect.initial_option` + `option_groups`** (#410, `70281dc`). Type extension in `types.py`; Slack adapter must serialize `option_groups` to Block Kit.
- [ ] **`thread.post()` streaming options** (#388, `9093292`). New params plumb through `Thread.post` → `chat.py` orchestrator.
- [ ] **Slack streaming team ID fix for interactive payloads** (#330, `8a0c7b3`). Bug fix in the Slack streaming path; check `adapters/slack/adapter.py` request-context plumbing.
- [ ] **Bundled guide markdown + templates manifest** (#423, `b0ab804`). Decision: skip or copy `packages/chat/resources/guides/*.md` and `templates.json` verbatim. Probably skip — these are TS-monorepo authoring resources, not runtime behavior.
- [x] **`concurrency.maxConcurrent` honored in `concurrent` strategy** (#419, `d630e6c`). Already addressed in the Python port — see the existing `ConcurrencyConfig.max_concurrent` row in `docs/UPSTREAM_SYNC.md` (we enforce via `asyncio.Semaphore` and reject misconfiguration). Upstream has now caught up; on this sync the divergence row downgrades from "silent correctness bug upstream" to "behavior parity restored".

#### Slack (`packages/adapter-slack/` → `src/chat_sdk/adapters/slack/`)

- [ ] **Slack Socket Mode support** (#162, `7e9d0fc`). Big — adds a persistent WebSocket transport alongside HTTP webhooks. Decision: in scope or follow-up? Mirrors the Discord Gateway gap already documented in non-parity ("HTTP interactions only").
- [ ] **Dynamic `bot_token` resolver + custom `webhookVerifier`** (#421, `2531e9c`). Multi-workspace pattern; touches `SlackAdapter.__init__` and request handling.
- [ ] **External-select Block Kit support** (#397, `a179b29`). Pairs with the core `option_groups` change above.
- [ ] **Native `markdown_text` for outgoing messages** (#440, post-release — Apr 17). NOTE: this commit is post-`f55378a` so technically out of `4.27.0` scope, but listed here because the team often picks up post-release fixes.
- [ ] **Link-preview unfurl metadata enrichment** (#395, `ded6f78`).
- [ ] **`@mention` regex preserves email addresses** (#394, `c26ee6c`).
- [ ] **Guard against empty `threadTs` (`invalid_thread_ts` fix)** (#292, `53c6b68`).

#### Teams (`packages/adapter-teams/` → `src/chat_sdk/adapters/teams/`)

- [ ] **Native streaming for DMs via `emit`** (#416, `ed46bae`). Currently the Python port falls back to `_fallback_stream` for Teams; native streaming would lift that.
- [ ] **DM conversation ID resolution for Graph API** (#403, `4c24c94`). Bug fix.
- [ ] **Teams SDK 2.0.8 + `User-Agent` header** (#415, `885a471`). TS-side dependency bump; Python equivalent is to verify our `botbuilder` pin and propagate `User-Agent` if not already.

#### Telegram

- [ ] **MarkdownV2 rendering fixes** (#407, `b9a1961`). Pairs with the streaming-chunk safety trim in #446 (post-`f55378a`).

#### Discord

- [ ] **Don't duplicate text when posting card messages** (#256, `7e5b447`). Confirm Python port's `discord/cards.py` doesn't have the same bug.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The pull request references in the sync scope section (e.g., #391, #410, #388) refer to upstream vercel/chat PRs. Without the repository prefix, GitHub will attempt to link these to pull requests within this repository, which is confusing given that local PR numbers (like #64 in line 10) are also mentioned. Please use the full reference format (e.g., vercel/chat#391) to ensure they link correctly to the upstream source.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Addressed in commit f88a272 (docs(changelog): qualify upstream PR refs with vercel/chat# prefix), which landed shortly after this review and qualified all 14 upstream PR refs in CHANGELOG.md with the vercel/chat# prefix. The thread is now is_outdated: true against the current CHANGELOG.md (head d6b267f); local PR refs (#64, #74, #82, plus the in-flight #84#90) remain bare so GitHub still cross-links them within this repo. Marking as resolved.


Generated by Claude Code

claude added 3 commits May 7, 2026 08:19
Per gemini-code-assist review on PR #83. Without the repo prefix, GitHub
auto-links the upstream PR numbers to local PRs in chat-sdk-python, which
collides with the local refs (#64, #66, #67, #74, #82) elsewhere in the
file. Use vercel/chat#NNN so the upstream refs link correctly.

https://claude.ai/code/session_01FyMxQn2BEAzmwKS1GZczKj
Final upstream-coverage audit before merging the 7 sync PRs (#84-#90)
identified one undocumented N/A item:

vercel/chat#415 (Teams SDK 2.0.8 + User-Agent) is a JS-only botbuilder
dependency bump. The Python Teams adapter uses raw aiohttp (no
botbuilder), so there is no equivalent dependency to bump. The optional
User-Agent: Vercel.ChatSDK header on the ~9 outbound aiohttp call sites
is a defense-in-depth nice-to-have; deferred as a follow-up rather than
landed in this sync.

Updates:
- CHANGELOG.md: tick all completed items and link them to their PRs
  (#84, #85, #86, #87, #88, #89, #90, plus already-merged PR #74).
  Document #415 inline as N/A.
- docs/UPSTREAM_SYNC.md non-parity table: add row for Teams User-Agent
  header divergence so future syncers don't try to "port" the JS bump.

Item #6 (concurrency.maxConcurrent) is already implementation-covered
in the Python port (existing divergence row at L492). The 4 new TS
concurrency tests in chat.test.ts have Python-specific equivalents at
test_chat_faithful.py L2969-3055 that don't name-match — leaving as
deferred fidelity-baseline polish since the behavior is verified.

Verdict from the coverage audit: all 18 substantive ports across PRs
#84-#90 are upstream-verified. No commits in chat@4.26.0..f55378a were
missed. Ready to start merging.

https://claude.ai/code/session_01FyMxQn2BEAzmwKS1GZczKj
Final upstream-coverage audit identified 4 chat.test.ts tests in the
[concurrency: concurrent] block whose Python equivalents existed but
didn't name-match the fidelity script's TS-name conversion. Rename 3 in
place and add the 4th, plus document a divergence the new test exposed.

Renames (no semantic change):
- test_max_concurrent_bounds_in_flight_handlers
  → test_should_cap_inflight_handlers_at_maxconcurrent_per_thread
- test_max_concurrent_zero_or_negative_raises
  → test_should_throw_when_maxconcurrent_is_less_than_1
- test_max_concurrent_with_non_concurrent_strategy_raises
  → test_should_warn_when_maxconcurrent_is_set_with_a_nonconcurrent_strategy
  (Note: TS warns; Python raises — divergence already documented at
  docs/UPSTREAM_SYNC.md L492. Test name aligns regardless.)

New test: test_should_track_slots_per_thread_independently. The
implementation surprised me — it currently uses a single global
asyncio.Semaphore (src/chat_sdk/chat.py:352), but upstream's
acquireConcurrentSlot keys the in-flight counter by threadId. So
max_concurrent=2 with 100 threads serializes everything globally on
Python (peak 2 across all threads) but allows 200 concurrent on TS
(2 per thread). Test marked pytest.mark.skip with a clear reason
pointing at the non-parity row, until the implementation is restructured
to a dict[thread_id, asyncio.Semaphore] (with cleanup-on-empty to
avoid unbounded growth). Tracked as a follow-up.

docs/UPSTREAM_SYNC.md: new row in the by-design non-parity table
documenting the global-vs-per-thread slot scope divergence with the
production-impact framing.

Tests: 7 passed + 1 skipped (the per-thread independence test).
Fidelity check: chat.test.ts now matches all concurrency entries; the
remaining 2 chat.test.ts gaps are getUser tests closed by PR #90.

https://claude.ai/code/session_01FyMxQn2BEAzmwKS1GZczKj
@patrick-chinchill patrick-chinchill marked this pull request as ready for review May 21, 2026 20:38
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.

🧹 Nitpick comments (1)
tests/test_chat_faithful.py (1)

2959-2965: ⚡ Quick win

Minor documentation reference update.

The comment at line 2961 references docs/UPSTREAM_SYNC.md L492, but the current ConcurrencyConfig.max_concurrent non-parity entry in UPSTREAM_SYNC.md is at line 493 (after the new per-thread slot-scope entry was added above it). Update the comment to point to the correct line.

📝 Suggested fix
-    # Aligned with upstream `chat.test.ts > should throw when maxConcurrent
-    # is less than 1`. Python rejects 0 and negatives at construction time
-    # with `ValueError` rather than silently falling back to unbounded.
+    # Aligned with upstream `chat.test.ts > should warn when maxConcurrent
+    # is set with a non-concurrent strategy`. Behavior divergence: TS warns
+    # and continues; Python raises (see docs/UPSTREAM_SYNC.md L493 — the
+    # field is only honored under `"concurrent"`, so silently allocating an
+    # unused semaphore is misleading). The TS test name is preserved so the
+    # fidelity script picks up the equivalent test.

Wait, I see the issue - I misread the code. Let me re-check. Lines 2959-2965 show the function definition and its comment. The comment at 2960-2964 says L492. But looking at the file changes, the new per-thread entry was added at line 493, which would push the existing entry down. Actually, looking more carefully at UPSTREAM_SYNC.md, line 493 starts with "| ConcurrencyConfig.max_concurrent slot scope" and line 492 has the previous entry about enforcement. So the comment should reference L493 for the slot-scope divergence, not L492 which is about enforcement.

Actually wait, let me re-read the comment. The comment at line 2961 says "see docs/UPSTREAM_SYNC.md L492". But the test is about warning when max_concurrent is used with non-concurrent strategy. Looking at UPSTREAM_SYNC.md line 492 in the annotated code:

Line 492: | ConcurrencyConfig.max_concurrent | Enforced via asyncio.Semaphore in the "concurrent" strategy path...

And line 493 starts the new slot scope entry.

So the comment is referencing the enforcement row (L492), not the slot scope row (L493). That seems correct since this test is about enforcement validation, not slot scope.

Let me re-read to be sure... The test function is test_should_warn_when_maxconcurrent_is_set_with_a_nonconcurrent_strategy. The comment says it checks that Python raises when max_concurrent is paired with queue/debounce/drop strategies. The docs reference would be to the enforcement row that says "rejects any non-None max_concurrent paired with a non-concurrent strategy".

Actually, looking at line 492 in the provided UPSTREAM_SYNC.md:

| `ConcurrencyConfig.max_concurrent` | Enforced via `asyncio.Semaphore` in the `"concurrent"` strategy path; rejects non-integer or `<= 0` values, and rejects any non-`None` `max_concurrent` paired with a non-`"concurrent"` strategy |

That matches! The test validates rejection of max_concurrent with non-concurrent strategies. The comment reference to L492 is correct.

So actually, no issue here. The comment is accurate.

🤖 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 `@tests/test_chat_faithful.py` around lines 2959 - 2965, The docs line
reference is already correct — leave the comment in the test function
test_should_warn_when_maxconcurrent_is_set_with_a_nonconcurrent_strategy as-is
pointing to docs/UPSTREAM_SYNC.md L492 (it documents enforcement/rejection of
max_concurrent with non-"concurrent" strategies); do not change it to L493.
🤖 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.

Nitpick comments:
In `@tests/test_chat_faithful.py`:
- Around line 2959-2965: The docs line reference is already correct — leave the
comment in the test function
test_should_warn_when_maxconcurrent_is_set_with_a_nonconcurrent_strategy as-is
pointing to docs/UPSTREAM_SYNC.md L492 (it documents enforcement/rejection of
max_concurrent with non-"concurrent" strategies); do not change it to L493.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 58440d3d-d821-4fca-84d6-939de70abf85

📥 Commits

Reviewing files that changed from the base of the PR and between 04c0658 and d6b267f.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • CLAUDE.md
  • README.md
  • docs/UPSTREAM_SYNC.md
  • pyproject.toml
  • src/chat_sdk/__init__.py
  • tests/test_chat_faithful.py

Copy link
Copy Markdown
Collaborator Author

@codex review

Sync-starter PR for the 4.27.0 wave (version bump to 0.4.27a1, UPSTREAM_PARITY"4.27.0", CHANGELOG/README/CLAUDE.md updates, no feature ports). Requesting a pass for completeness — main things to sanity-check are the version-mapping consistency (pyproject.toml / __init__.py / README.md / CLAUDE.md all agree), the lint-workflow pin staying at chat@4.26.0 (intentional — upstream hasn't tagged chat@4.27.0), and the CHANGELOG sync-plan accuracy.


Generated by Claude Code

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

ℹ️ 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".

@patrick-chinchill patrick-chinchill merged commit 332ae8e into main May 28, 2026
10 checks passed
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