Warike Assistant is a personal, RAG-powered chat application designed to help users find answers in company documentation via natural-language conversation.
In this repo, the initial “knowledge base” is the Davis Instruments Vantage Pro2 Console User Manual, stored as Markdown sources in:
data-ingestion/assets/install.ts(installation / setup content)data-ingestion/assets/usage.ts(console usage / operations content)
The ingestion pipeline converts those manuals into embeddings and stores them in AWS S3 Vectors so the assistant can retrieve relevant passages and answer questions with grounded, manual-based responses. This makes it suitable as a customer-support tool for internal teams and (with the right content scope and permissions) for sharing with Davis Instruments distributors.
This repository contains a multi-package application composed of:
expo/: Expo React Native client app (mobile + web via Expo Router).lambda/: AWS Lambda (container image) providing a streaming/api/chatendpoint backed by a Mastra agent + RAG tool.data-ingestion/: Node/TypeScript ingestion runner that chunks docs, generates embeddings, and upserts vectors into AWS S3 Vectors.infra/: Terraform infrastructure for ECR, Lambda (image), IAM, CloudFront, and related resources.
-
expo/: client applicationexpo/app/: routes (Expo Router)expo/app/_layout.tsx: root layout, Clerk auth provider, route gatingexpo/app/api/chat+api.ts: local Expo API route (Gemini streaming; primarily useful for local/dev)expo/app/api/completion+api.ts: local Expo API route (prompt completion streaming)
expo/components/: UI componentsexpo/components/ChatPage.tsx: chat page usinguseChat+ streaming transportexpo/components/chat/*: chat message rendering and input controls
expo/utils/:expo/utils/api.ts: builds the base API URL fromEXPO_PUBLIC_API_BASE_URLexpo/utils/Database.ts: local SQLite persistence (used byChatPage.tsx)
-
lambda/: AWS Lambda backend (container image)lambda/src/index.ts: Lambda handler (streaming response) and/api/chatroutinglambda/src/auth.ts: Clerk JWT verification (@clerk/backend)lambda/src/env.ts: environment variable parsing/validation (zod + dotenv)lambda/src/mastra/:app.ts: Mastra instance wiring (agent + vector store + observability)agent.ts:basicAgentconfigurationmodel.ts: Google Generative AI model + embedding model selectionprompt.ts: strict RAG system prompttool.ts: vector query tool (@mastra/rag) configured for S3 Vectorsvector.ts: S3 Vectors store (@mastra/s3vectors) configurationobservability.ts: OTEL exporter to Langwatchindex.ts:runAgent(...)helper that streams output to Lambda response
-
data-ingestion/: ingestion runnerdata-ingestion/src/index.ts: runs ingestion and an example querydata-ingestion/src/app.ts: document chunking + embedding + upsert to S3 Vectorsdata-ingestion/src/env.ts: environment variable parsing/validation (zod + dotenv)data-ingestion/src/mastra.ts: Mastra wiring for ingestion/queryingdata-ingestion/src/vector.ts: S3 Vectors store config
-
infra/: Terraform deploymentinfra/provider.tf: Terraform backend + AWS providerinfra/ecr.tf: ECR repo + lifecycle policy (+ local-exec to seed an image)infra/lambda-chat.tf: image-based Lambda deployment with streaming invoke mode + Function URLinfra/lambda-chat.iam.tf: IAM role/policies (CloudWatch logs + S3 Vectors + Bedrock)infra/cloudfront.tf: CloudFront distribution fronting the Lambda Function URL
- The Expo client sends chat messages to the backend URL at
EXPO_PUBLIC_API_BASE_URL(seeexpo/utils/api.ts). - Requests include a Clerk JWT (see
expo/app/_layout.tsxfor Clerk integration andexpo/components/ChatPage.tsxfor auth headers). - AWS Lambda receives requests at
/api/chat(lambda/src/index.ts). - Lambda verifies access using Clerk (
lambda/src/auth.ts). - Lambda runs the Mastra agent (
lambda/src/mastra/*), which:- uses a strict system prompt enforcing RAG grounding (
lambda/src/mastra/prompt.ts) - calls a vector query tool to retrieve context from AWS S3 Vectors (
lambda/src/mastra/tool.ts)
- uses a strict system prompt enforcing RAG grounding (
- Lambda streams tokens back to the client using Lambda response streaming (
invoke_mode = "RESPONSE_STREAM").
data-ingestion/src/app.tsbuilds documents (from local markdown assets) and chunks them.- It generates embeddings for each chunk.
- It upserts vectors + metadata into an S3 Vectors index.
- The runtime query tool (Lambda) searches the same S3 Vectors index to retrieve context at chat time.
- UI + navigation: Expo Router for file-based routing.
- Auth: Clerk (
@clerk/clerk-expo), with token caching viaexpo-secure-store. - Chat:
useChatfrom@ai-sdk/reactwithDefaultChatTransportfor streaming. - Persistence: local SQLite via
expo-sqlite.
Key files:
expo/app/_layout.tsx: root provider setup and route guarding.expo/components/ChatPage.tsx: chat UI, streaming transport, and DB persistence.expo/utils/api.ts: API base URL builder.
- HTTP entrypoint:
lambda/src/index.ts.- Validates auth.
- Routes only
/api/chat. - Parses request body
{ messages }. - Streams agent output back.
- Auth:
lambda/src/auth.tsverifies Clerk token. - Agent runtime: Mastra agent (
lambda/src/mastra/*). - RAG retrieval: vector query tool configured for S3 Vectors.
- Observability: OTEL exporter configured for Langwatch.
- Ingest:
data-ingestion/src/app.ts.- Create documents.
- Chunk documents.
- Embed text.
- Upsert vectors + metadata into S3 Vectors.
- Observability: OTEL exporter configured for Langwatch.
- ECR: container registry for Lambda images.
- Lambda: image-based deployment, response streaming enabled, Function URL created.
- IAM: permissions for logging + vector operations (and Bedrock invoke permissions).
- CloudFront: optional edge distribution in front of the Lambda Function URL.
- Path:
/api/chat - Method:
POST - Auth: Clerk JWT in either:
Authorization: Bearer <token>orX-Clerk-Token: <token>
- Body: JSON
{ "messages": [...] }- Message format is the UI message format used by the
ai/@ai-sdk/reactstack.
- Message format is the UI message format used by the
- Response: streaming (token stream) from the agent.
Notes:
- The Lambda handler currently rejects non-matching paths with
404 Not Found.
Set via .env / EAS / CI:
EXPO_PUBLIC_API_BASE_URL: Base URL where/api/chatis hosted (e.g., CloudFront domain).EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY: Clerk publishable key.
Validated in lambda/src/env.ts:
NODE_ENV:development|test|productionAWS_REGIONGOOGLE_GENERATIVE_AI_API_KEYGOOGLE_LANGUAGE_MODEL(defaultgemini-2.5-flash)GOOGLE_EMBEDDING_MODEL(defaulttext-embedding-004)AWS_S3_VECTORS_BUCKET_NAMEAWS_S3_VECTORS_INDEX_NAMELANGWATCH_API_KEYCLERK_SECRET_KEY
Validated in data-ingestion/src/env.ts:
NODE_ENVAWS_REGIONAWS_PROFILEAWS_S3_VECTORS_BUCKET_NAMEAWS_S3_VECTORS_INDEX_NAMEGOOGLE_GENERATIVE_AI_API_KEYLANGWATCH_API_KEY
See infra/README.md for the expected terraform.tfvars-style values (project name, region/profile, model keys, vector index/bucket, Clerk secret, Langwatch key, and domain settings).
- Node.js (Expo + Lambda + ingestion are Node/TypeScript)
- pnpm (the packages use
pnpm-lock.yaml) - AWS CLI (for S3 Vectors and deployment)
- Docker (for building/pushing the Lambda image)
- GNU Make (to use the repo
Makefiletargets)
This repo includes a root Makefile to coordinate setup and common workflows.
Show available commands:
make helpcd expo
pnpm install
pnpm startThe app expects EXPO_PUBLIC_API_BASE_URL to be set so it can call /api/chat.
The Lambda package is TypeScript and compiles to dist/.
cd lambda
pnpm install
pnpm build
pnpm startNote: running the Lambda container locally vs. running node dist/index.js are different modes; the deployed runtime uses the AWS Lambda container entrypoint (CMD ["index.handler"] in lambda/Dockerfile).
make ingest(Equivalent to running pnpm start inside data-ingestion/.)
Create/reuse the S3 Vectors bucket + index:
make setup-vectorsYou can override defaults via environment variables:
AWS_PROFILE=default AWS_REGION=us-east-1 VECTOR_BUCKET_NAME=bucket-vector-s3-lambda INDEX_NAME=documents make setup-vectorsTo delete the index + bucket:
make cleanup-vectorsmake infra-init
make infra-plan
make infra-applyThis creates:
- ECR repository
- Lambda (image-based) with Function URL and response streaming
- CloudFront distribution (if configured)
Build, push, update infra/lambda-chat.tf to the new tag, and (optionally) deploy via Terraform apply:
make push-imageNotes:
- By default it prompts before
terraform apply. - To push + update the TF file but skip apply:
NO_TERRAFORM_APPLY=1 make push-image- Lambda uses response streaming (
awslambda.streamifyResponse(...)). - Auth failures return
Unauthorized. - Non-
/api/chatpaths return404 Not Found. - The agent uses a strict RAG prompt that constrains answers to retrieved context.
setup.sh: create/reuse S3 Vectors bucket + indexcleanup_vector_store.sh: delete S3 Vectors index + bucketsetup_vector_store.sh: deprecated wrapper (callssetup.sh)run_data_ingestion.sh: rundata-ingestionpipeline (pnpm start)push_chat_image.sh: build/push Lambda image to ECR, update Terraform tag, and (optionally) deploytest_stream.sh: test streaming chat endpoint using Terraform outputs (app_domain_name-> CloudFront -> Lambda URL)
Common targets:
make setup-vectorsmake ingestmake infra-applymake push-imagemake test-stream
Run make help for the full list.
