Skip to content

Next Release - #3987

Merged
isekovanic merged 4 commits into
mainfrom
develop
Nov 12, 2026
Merged

isekovanic merged 4 commits into
mainfrom
develop

Conversation

@isekovanic

Copy link
Copy Markdown
Contributor

🎯 Goal

πŸ›  Implementation details

🎨 UI Changes

iOS
Before After
Android
Before After

πŸ§ͺ Testing

β˜‘οΈ Checklist

  • I have signed the Stream CLA (required)
  • PR targets the develop branch
  • Documentation is updated
  • New code is tested in main example apps, including all possible scenarios
    • SampleApp iOS and Android
    • Expo iOS and Android

testableapple and others added 3 commits November 12, 2026 16:30
Ticket: https://linear.app/stream/issue/RN-513

## 🎯 Goal

Run the 9 `GiphyTests` cases on Android again. They became iOS-only
(`itOnIOS`) because loading giphy media sometimes took the whole Android
CI emulator down.

## πŸ›  Implementation details

- RN-513 was recorded with `-gpu swiftshader_indirect`. CI has used
`-gpu swangle_indirect` since #3965, and the giphy tests no longer take
the emulator down with it (see Testing).
- `GiphyTests`: `itOnIOS` β†’ `it`. This removes `itOnIOS`, which only
these tests used, and its mentions in the e2e README and the Fastfile's
test-id regex.
- `assertMessageDeliveryStatus(NIL)` now looks only inside the list's
message cells. Since RN-493, a thread shows its parent message's
delivery status, and the parent renders outside any cell
(`ThreadFooterComponent`). The old whole-list check failed
`test_deliveryStatusHidden_whenEphemeralMessageShownInThread` on Android
every time, on the parent's βœ“, not the giphy's. The same cause likely
explains its occasional iOS failures (nightly 42943115860). Checks that
expect a status still see the parent.

## πŸ§ͺ Testing

- **Stress runs (Android, `GiphyTests` only, 8 batches each, so every
batch starts with a giphy test):** 6 runs, **48 batches, 0 emulator
losses**. With SwiftShader, 1–2 of 8 batches per run lost the emulator.
- Before the assertion fix:
[43078664001](https://github.com/GetStream/stream-chat-react-native/actions/runs/43078664001),
[43082371465](https://github.com/GetStream/stream-chat-react-native/actions/runs/43082371465),
[43083731094](https://github.com/GetStream/stream-chat-react-native/actions/runs/43083731094),
[43084926869](https://github.com/GetStream/stream-chat-react-native/actions/runs/43084926869).
Only the in-thread test failed.
- After the fix:
[43086749991](https://github.com/GetStream/stream-chat-react-native/actions/runs/43086749991),
[43087759886](https://github.com/GetStream/stream-chat-react-native/actions/runs/43087759886).
Everything passed.
- Full suite on this PR:
[43086744717](https://github.com/GetStream/stream-chat-react-native/actions/runs/43086744717),
all 8 Android batches green.
- The stress selection was a temporary commit, reverted in the last
commit, so the net diff doesn't touch it.
- `yarn typecheck` (E2ETestApp), eslint and prettier pass on the changed
files.

## β˜‘οΈ Checklist

- [x] I have signed the [Stream
CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform)
(required)
- [x] PR targets the `develop` branch
- [ ] Documentation is updated
- [ ] New code is tested in main example apps, including all possible
scenarios
  - [ ] SampleApp iOS and Android
  - [ ] Expo iOS and Android
Ticket: https://linear.app/stream/issue/RN-485

## 🎯 Goal

Bring the AI agent work we shipped on `v9-release` to V10: the same
components, APIs and sample apps, adapted to stream-chat 10 and the V10
i18n.

The long-press Copy/Edit menu on the person's own messages isn't here.
It isn't on v9 either, and it comes later as a V10 feature.

## πŸ›  Implementation details

The branch is one commit per v9 PR, in merge order, then the V10-only
changes, so it can be reviewed commit by commit.

**Ported from v9**
- #3920 parse agent reply steps from message attachments
- #3921 AI translations through the chat SDK, sample on the agents
router
- #3924 agent reply steps: reasoning, tool calls, approvals
- #3926 native `AIAgent` module for the install id and tool-call sign-in
- #3928 message views, reply actions and icon overrides
- #3929 `AIConversation` on LegendList
- #3931 chat options, suggestions and attachment preview fixes
- #3933 client tool runner
- #3934 polish of agent conversations
- #3936 generated UI with an A2UI renderer
- #3944 follow-up polish of agent conversations
- #3958 A2UI list-row secrets and malformed messages
- #3957 conversation state with `AIConversationController`
- #3960 `AIConversation` in its own entry point
- #3963 the crew assistant demo app
- #3974 alignment with the other SDKs
- #3975 StrictMode-safe controller lifecycle and `custom.uiAction` docs
- #3976 crew drawer layout
- #3978 the samples on `@stream-io/stream-agents` 0.4.2, in place of
calypso and their own chat layer

Where `develop` had already changed the same lines (comment cleanups,
the i18n move, a11y docs), `develop`'s version wins.

**What's different on V10**
- **Fields under `custom`.** stream-chat 10 keeps `mime_type`,
`file_size`, `ai_generated`, `generating`, `ai_ui` and the step fields
under `custom`. `parseMessageParts` and `fromStreamMessage` lift them
with a small `withCustomFields` helper, as the React SDK does.
- **Translation keys.** The 55 AI and A2UI strings use catalog keys with
their English inline, named after React's
(`aiComponents.replyActions.copy.accessibilityLabel`,
`a2ui.modal.close.label`, …), and `keys.ts` is regenerated.
`useAITranslation` returns core's typed `t`.
- **Entry isolation.** The AI entry points may reach V10's translation
context. `@legendapp/list` and `react-native-keyboard-controller` are
AI-only packages.
- **LegendList stays at 3.7.1**, the version v9 resolves. 3.7.2 keeps
fewer rows mounted after a jump, so the reused-rows test now only
compares rows that stay mounted. It passes on both versions.
- **Sample data layer.** Both samples use stream-agents' `AgentChat`,
whose stream-chat 10 reader reads `channel.messagePaginator`, activates
the channel so the client reloads it after a reconnect, and loads older
pages with `toTail()`. The samples read the reply fields from `custom`,
and the crew sample uploads voice memos with `uploadChannelFile`.
- **Sample dependencies.** Both samples depend on
`@stream-io/state-store` and `use-sync-external-store`, and pin
`@stream-io/state-store` to one copy in `tsconfig` paths. They stay on
stream-chat `^10.0.1`: stream-agents asks for `^10.0.2`, but only when
it builds its own client, and the samples hand it theirs.

## 🎨 UI Changes

None compared with v9. The screenshots are in the v9 PRs above.

## πŸ§ͺ Testing

`yarn lint`, `yarn typecheck`, `test:typecheck`, the unit tests and
`yarn build` pass, and both samples typecheck.

On an Android emulator and an iOS simulator:
- **ChatGPT sample:** reasoning, the device time tool, the generated
Lisbon plan, the drawer, reopening a conversation from history, and
starters on a new one.
- **Crew sample:**
- all eight flows, including the approval cards, the checklist and form
actions, and the agent-first ones;
- the equipment deep link, photo troubleshooting and the team lead view;
  - voice memos, recorded on the simulator with `say` and answered;
  - the clock-out form on iOS.
- **Reconnect:** the network was dropped mid-reply on both samples. The
client recovered the active channel, and the full reply appeared.
- **Older messages:** with the page size briefly set to 3, older pages
loaded until there were none left.

After the move to stream-agents, both samples were checked again on both
platforms: replies, the device time tool, the agent-first Clock in flow,
the drawer, reopening from history, handbook sources, and an approval
card into A2UI. Reconnect, older pages and voice memos were tested on
the samples' previous chat layer, not again since.

Not tested here: voice mode (the simulator's speech recognition doesn't
hear `say`), dictation, Cal.com sign-in, and charts or photos in the
ChatGPT sample.

## β˜‘οΈ Checklist

- [x] I have signed the [Stream
CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform)
(required)
- [x] PR targets the `develop` branch
- [x] Documentation is updated
- [ ] New code is tested in main example apps, including all possible
scenarios
  - [ ] SampleApp iOS and Android
  - [x] Expo iOS and Android
Ticket: https://linear.app/stream/issue/RN-485

## 🎯 Goal

`ExpoChatGPTSample` and `ExpoCrewAssistant` moved to Vision-Agents, next
to the agent backends they use: GetStream/Vision-Agents#1994
(`examples/voice_agents/react_native_assistant` and
`crew_assistant/app`). This removes the copies here.

## πŸ›  Implementation details

- Deletes both sample folders, and drops them from the root workspaces,
the `typecheck` script and `yarn.lock`.
- Drops `@stream-io/stream-agents` from the age-gate preapprovals in
`.yarnrc.yml`; only the samples used it.
- `AGENTS.md` points at the samples' new home.

To work on `ai-components`, run a Vision-Agents app against this
checkout:

```bash
STREAM_CHAT_RN_DIR=~/Projects/stream-chat-react-native npx expo start
```

Metro then reads the SDK from source, and changes reload live. Native
SDK changes still need an install and a rebuild there.

## πŸ§ͺ Testing

- `yarn install --immutable` passes, and `yarn workspaces list` no
longer has the samples.
- The local SDK mode was checked from Vision-Agents on the iOS
simulator: a change to `ai-components` here showed in the crew app and
reloaded live.
@isekovanic
isekovanic requested a review from oliverlaz November 12, 2026 19:59
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Next releases

v10.1.0

10.1.0 (2026-11-12)

Bug Fixes

  • ai-components: use simple-markdown 0.7.3 to stop npm nesting React 18 under core (#3988) (8924a36)

Features

sampleapp@v5.1.0

5.1.0 (2026-11-12)

Features

…ct 18 under core (#3988)

Ticket: https://linear.app/stream/issue/RN-485

## 🎯 Goal

Fix a startup crash for integrators who install with npm on React 19:
"Cannot read property 'useState' of null".

Since 9.10.0, core depends on `@khanacademy/simple-markdown` (`^2.1.0`)
for the AI components' markdown. That package peer-depends on
`react`/`react-dom` `^18.2.0`. Core does not declare `react` itself, so
npm satisfies the peer by nesting React 18.3.1 at
`node_modules/stream-chat-react-native-core/node_modules/react`. Core's
own `import 'react'` then resolves to that copy, and the app runs two
Reacts.

Only npm does this. Yarn 1, Yarn 4, pnpm 10 and bun 1.3 all hand core
the app's React 19, which is why the monorepo never showed it.

## πŸ›  Implementation details

Replace `@khanacademy/simple-markdown` with the original
`simple-markdown` `^0.7.3`. The fork was cut from it at 0.8.0, and 0.7.3
has no peer dependencies. It is already in the tree through
`react-native-markdown-package`, and core's main entry already imported
it (`renderText.tsx`) without declaring it.

- `package/package.json` / `yarn.lock`: swap the dependency (the fork
and `@khanacademy/perseus-utils` drop out).
- `src/ai-components/markdown/*`: import from `simple-markdown`. The API
and type names are the same.
- `bin/validate-entry-isolation.js`: drop the fork from the AI-only
packages list, since the main entry already uses `simple-markdown`.
- `src/ai-components/README.md`: point the `rules` link at the original
repo.

The fork's newer releases don't help. Every version up to 4.0.3, and
Perseus `main`, still declares `react`/`react-dom` `^18.2.0`. Even
though V10 can resolve ESM modules just fine, some changes still need to
be made to the upstream library so that `react-dom` is no longer
enforced. For the time being, we'll revert to the known library that
enforces nothing and we'll take up the markdown topic more seriously in
the near future.

## 🎨 UI Changes

None. Markdown output is identical.

## πŸ§ͺ Testing

- `yarn lint`, `cd package && yarn test:typecheck`, `yarn build` and
`yarn test:unit` (272 suites, 3206 tests) all pass.
- npm proof: `npm install --package-lock-only` next to `react@19.3.0`.
Published 10.0.2 nests `react`/`react-dom` 18.3.1 under core; the packed
fix resolves a single React 19.3.0, with no `@khanacademy` packages.
- Parity between the fork (2.2.3) and 0.7.3, run through our AI markdown
rules on 2,732 markdown files: the parse trees and rendered element
trees are identical. A source diff confirms the parser and regex code is
the same. The only differences are `sanitizeUrl` and the default `hr`
output, and both are code we never run.
- On device: ExpoChatGPTSample on an iOS 27 simulator against a live
agent. Headings, nested and numbered lists, tables, syntax-highlighted
code, bold, italic, inline code and links all render.

## β˜‘οΈ Checklist

- [ ] I have signed the [Stream
CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform)
(required)
- [x] PR targets the `develop` branch
- [x] Documentation is updated
- [ ] New code is tested in main example apps, including all possible
scenarios
  - [ ] SampleApp iOS and Android
  - [ ] Expo iOS and Android
@Stream-SDK-Bot

Copy link
Copy Markdown
Contributor

SDK Size

title develop branch diff status
js_bundle_size 2033 KB 2033 KB 0 B 🟒
ai_components_size 344 KB 344 KB 0 B 🟒
a2ui_size 103 KB 103 KB 0 B 🟒

@isekovanic
isekovanic merged commit 1c9d1a9 into main Nov 12, 2026
30 of 31 checks passed
@ghost

ghost commented Nov 12, 2026

Copy link
Copy Markdown

πŸŽ‰ This PR is included in version 10.1.0 πŸŽ‰

The release is available on:

Your semantic-release bot πŸ“¦πŸš€

@ghost ghost added the released label Nov 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants