Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

expo-resumable-chat

How it works

  • POST /api/chat runs the model and calls chat.makeResumable(...), which appends every chunk to a per-turn S2 stream and serves the client by reading that same stream back as SSE. Each SSE id is the S2 sequence number.
  • On reconnect, useChat({ resume: true }) calls GET /api/chat/:id/stream, which replays the in-flight turn from S2 to completion.
  • Completed messages are stored on a transcript stream and reloaded on open.

Streams are created on first append or read (the basin is configured with --create-stream-on-append --create-stream-on-read). There are two per chat: a transcript stream and a single-use stream per assistant turn.

Streaming tool with retries

Ask for a sales report and the agent calls run_analytics_query, which streams result rows to an S2 stream. The query fails partway through twice before it succeeds. DBOS retries it, and each retry replaces the failed attempt's rows on the stream, so the chat shows one clean result. The retries are part of the resumable chat stream, so they can work with a refresh too.

Code: server/src/durable-query.ts, server/src/fenced-stream.ts.

Needs Postgres for DBOS: run npx dbos postgres start or set DBOS_SYSTEM_DATABASE_URL.

Run

Create a basin:

export S2_ACCESS_TOKEN="..."
s2 create-basin my-basin --create-stream-on-append --create-stream-on-read

Backend (needs Postgres for the durable tool):

npx dbos postgres start   # or point DBOS_SYSTEM_DATABASE_URL at any Postgres
cd server
cp .env.example .env   # set S2_ACCESS_TOKEN, S2_BASIN, OPENAI_API_KEY, DBOS_SYSTEM_DATABASE_URL
npm install
npm run dev            # http://localhost:8080

App:

cd app
cp .env.example .env   # set EXPO_PUBLIC_API_URL
npm install
npm run web            # or: npm run ios | npm run android

Notes

  • Switch model provider with CHAT_PROVIDER=openai|anthropic in server/.env.
  • React Native's built-in fetch buffers responses, which breaks streaming SSE. The app uses expo/fetch, which streams, and passes it to the AI SDK transport. See app/src/app/index.tsx.
  • Deploy the backend to Cloud Run with the included server/Dockerfile.

Local S2

To run without a cloud token, use s2 lite (in-memory) and point the backend at it:

s2 lite --port 9000
# server/.env:
#   S2_ACCESS_TOKEN=ignored
#   S2_ACCOUNT_ENDPOINT=http://localhost:9000
#   S2_BASIN_ENDPOINT=http://localhost:9000

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages