ai-chat-demo
MargeloChat
A ChatGPT-style mobile chat app with a twist: it knows about Margelo. You talk to a streaming AI assistant that renders replies as live markdown, shows its reasoning, and answers any question about Margelo (the company, its people, and its open-source libraries) by searching a real knowledge base instead of guessing.
Ask it anything. For general questions it just replies; for Margelo questions it calls a retrieval tool, pulls matching facts from a vector database, and answers only from what it found.
[!NOTE] Read the full blog post about building a ChatGPT-Style AI Chat App in React Native here: https://blog.margelo.com/building-native-llm-chat-app-with-rag
How it works
- Brain - OpenAI's Responses API, streamed over a WebSocket (
react-native-nitro-websockets) rather than HTTP. The socket is prewarmed natively at app start, before the JS bundle loads, so it's already open by the first message. Reply text and reasoning summaries stream token-by-token; turns are chained withprevious_response_idso the model remembers the conversation. - Knowledge base (RAG) - the model can call a
search_margelo_kbtool, which queries a Pinecone index (integrated embedding, so raw text goes up and Pinecone embeds it server-side) overreact-native-nitro-fetch. Margelo questions are answered from the retrieved context, never from the model's memory. - Rendering - replies render as native markdown with a streaming animation and tappable links (
react-native-enriched-markdown). The collapsible "thought process" opens in a bottom sheet (react-native-true-sheet). - List - a keyboard-aware
@legendapp/listwith anchored end-space, for ChatGPT-style scroll and anchor behavior while a reply streams in. - Look - real Liquid Glass surfaces on iOS 26+ (
@callstack/liquid-glass) with plain fallbacks everywhere else, a Skia shimmer "Thinking" label (@shopify/react-native-skia), and SF Symbols that fall back to Material Design Icons on Android. - Attachments - pick images (
react-native-image-picker), sent to the model as base64 data URLs and shown as thumbnails (react-native-nitro-image).
Requirements
Runs on iOS and Android (New Architecture). Liquid Glass needs iOS 26+; on older iOS and on Android those surfaces fall back to a plain rounded style.
- Xcode + CocoaPods, Node
>= 22.11, and the React Native environment. - An OpenAI API key and a populated Pinecone index for the knowledge-base tool.
Note: this is a demo. The API keys live in the app bundle, which is fine locally but unsafe for production - anyone can extract them. For anything real, put a relay server in front and keep the keys server-side.
Setup
cd app
npm install
cp src/config.example.ts src/config.ts # then fill in your keys
cd ios && pod install && cd ..
Open src/config.ts and add your OpenAI key, Pinecone key, and index host. This file is gitignored and never committed.
Run
cd app
npm start # Metro
npm run ios # build + launch on the iOS simulator/device
npm run android # build + launch on the Android emulator/device
Other scripts (also run in CI):
npm run lint # eslint
npm run typecheck # tsc --noEmit
npm run format # prettier --write
npm run format:check # prettier --check
npm run react-compiler-check # react-compiler healthcheck
npm test # jest
Project structure
app/
src/
config.ts # API keys (gitignored; copy from config.example.ts)
theme.ts # dark theme + shared markdown design tokens
markdownStyle.ts # maps the theme onto the markdown renderer
notImplemented.ts # "demo only" alert for stubbed controls
state/
chatStore.ts # zustand store: chat state, streaming, tool-call loop
openai/
protocol.ts # builds Responses API requests, parses server events
connectionManager.ts # module-level WebSocket lifecycle + reconnect with backoff
rag/
searchKnowledgeBase.ts # Pinecone knowledge-base search (the model's tool)
hooks/
useAttachments.ts # image picking
screens/
RootDrawer.tsx # pager: recents <-> chat
ChatScreen.tsx # the conversation, list, and composer wiring
RecentsScreen.tsx # chat history (mocked for the UI pass)
components/
ChatMessages.tsx # subscription boundary: only re-renders on message changes
Composer.tsx # the input pill (grow/shrink, attachment thumbnails)
AttachmentMenu.tsx # the "+" dropdown for picking attachments
MessageBubble.tsx # user bubble / assistant markdown + reasoning trace
ReasoningSheet.tsx # bottom sheet showing the thinking trace
ShimmerText.tsx # Skia shimmer "Thinking" label
Header.tsx # top bar
Glass.tsx # Liquid Glass wrapper with a plain fallback
Icon.tsx # SF Symbol with a Material Design Icon fallback
EmptyState.tsx # centered logo before the first message
ScrollToBottomButton.tsx
Open-source libraries
This app stands on the shoulders of these projects (thank you to their authors):
- react-native & react - Meta
- react-native-nitro-modules - Marc Rousavy / Margelo
- react-native-nitro-websockets - Marc Rousavy / Margelo
- react-native-nitro-image - Marc Rousavy / Margelo
- react-native-nitro-fetch & react-native-nitro-text-decoder - Szymon Kapała / Margelo
- react-native-nitro-symbols - Dave Mkpa Eke / Margelo
- react-native-reanimated & react-native-worklets - Software Mansion
- react-native-keyboard-controller - Kiryl Ziusko / Margelo
- @legendapp/list - LegendApp
- react-native-enriched-markdown - Software Mansion
- react-native-true-sheet - Jovanni Lo
- @shopify/react-native-skia - Shopify
- @callstack/liquid-glass - Callstack
- react-native-pager-view - Callstack
- zeego - Fernando Rojo
- @react-native-menu/menu - Jesse Katsumata
- @react-native-vector-icons/material-design-icons - Joel Arvidsson
- react-native-image-picker - community
- react-native-safe-area-context - Janic Duplessis
- react-native-bootsplash & react-native-edge-to-edge - Mathieu Acthernoene
- Vector database: Pinecone · Model API: OpenAI
