Skip to content

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

Draft
patrick-chinchill wants to merge 4 commits intomainfrom
claude/sync-upstream-release-J7S7H
Draft

sync: upstream v4.27.0 (alpha 1)#83
patrick-chinchill wants to merge 4 commits intomainfrom
claude/sync-upstream-release-J7S7H

Conversation

@patrick-chinchill
Copy link
Copy Markdown
Collaborator

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

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

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 297341d8-b224-4ca2-89be-aeaeeef7c5fa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/sync-upstream-release-J7S7H

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

@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

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.

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
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