A Motia workflow that implements intelligent form triage using RAG (Retrieval Augmented Generation) with vector similarity search and LLM processing.
This workflow processes public form submissions through an automated triage system that:
- Receives form submissions via webhook
- Processes and embeds text content
- Stores vectors in Supabase for similarity search
- Uses RAG with Claude AI to generate intelligent triage responses
- Logs results to Google Sheets
- Sends error alerts to Slack when issues occur
┌─────────────────┐
│ Webhook Trigger │ (API)
│ POST /public- │
│ form-auto- │
│ triage │
└────────┬────────┘
│ emits: form.submitted
▼
┌─────────────────┐
│ Process Text │ (Event)
│ - Split text │
│ - Generate │
│ embeddings │
│ - Store in │
│ Supabase │
└────────┬────────┘
│ emits: text.processed
▼
┌─────────────────┐
│ RAG Agent │ (Event)
│ - Query vectors│
│ - Generate AI │
│ response │
└────────┬────────┘
│ Success: processing.complete
│ Error: processing.failed
▼
┌────┴────┐
│ │
▼ ▼
┌────────┐ ┌────────┐
│ Log to │ │ Slack │
│ Sheets │ │ Alert │
└────────┘ └────────┘
- form.submitted: Triggered when webhook receives form data
- text.processed: Triggered after text is split and embedded
- processing.complete: Triggered when RAG processing succeeds
- processing.failed: Triggered on any processing error
npm installCreate a .env file with the following variables:
# Cohere API Configuration
COHERE_API_KEY=your_cohere_api_key
# Supabase Configuration
SUPABASE_URL=your_supabase_url
SUPABASE_KEY=your_supabase_anon_key
# Anthropic API Configuration
ANTHROPIC_API_KEY=your_anthropic_api_key
# Google Sheets Configuration
GOOGLE_SHEETS_CLIENT_EMAIL=your_service_account_email
GOOGLE_SHEETS_PRIVATE_KEY=your_private_key
GOOGLE_SHEET_ID=your_sheet_id
# Slack Configuration
SLACK_BOT_TOKEN=xoxb-your-bot-token
SLACK_ALERT_CHANNEL=#alertsRun the following SQL in your Supabase SQL editor to set up the vector store:
-- Enable the pgvector extension
CREATE EXTENSION IF NOT EXISTS vector;
-- Create the vector store table
CREATE TABLE IF NOT EXISTS public_form_auto_triage (
id BIGSERIAL PRIMARY KEY,
content TEXT,
embedding VECTOR(1024),
metadata JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Create the matching function for similarity search
CREATE OR REPLACE FUNCTION match_documents (
query_embedding VECTOR(1024),
match_threshold FLOAT,
match_count INT,
index_name TEXT DEFAULT 'public_form_auto_triage'
)
RETURNS TABLE (
content TEXT,
similarity FLOAT,
metadata JSONB
)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
EXECUTE format(
'SELECT content, 1 - (embedding <=> $1) AS similarity, metadata
FROM %I
WHERE 1 - (embedding <=> $1) > $2
ORDER BY embedding <=> $1
LIMIT $3',
index_name
)
USING query_embedding, match_threshold, match_count;
END;
$$;
-- Create index for faster similarity search
CREATE INDEX ON public_form_auto_triage USING ivfflat (embedding vector_cosine_ops);- Create a new Google Sheet
- Create a sheet named "Log" (or update the sheet name in the code)
- Add headers:
Timestamp,Status,Input,Additional Data - Create a Google Cloud Service Account and download credentials
- Share the sheet with the service account email
- Create a Slack App in your workspace
- Add the
chat:writebot scope - Install the app to your workspace
- Copy the Bot User OAuth Token
- Invite the bot to your alerts channel
npm run devnpm run build
npm startPOST /public-form-auto-triage
Content-Type: application/json
{
"content": "I need help with my account access. I can't log in and have tried resetting my password multiple times.",
"metadata": {
"source": "contact-form",
"page": "/support"
},
"userInfo": {
"email": "user@example.com",
"name": "John Doe"
}
}{
"success": true,
"message": "Form submitted successfully and queued for processing",
"requestId": "req_1234567890_abc123"
}The workflow uses Motia's state management to store data across steps:
- form-submissions: Raw form submissions indexed by requestId
- processed-texts: Processing results (chunk counts, embeddings)
- triage-results: Final RAG responses with metadata
- alert-history: Error alert history
- Text splitting with configurable chunk size and overlap
- Embedding generation using Cohere's embed-english-v3.0 model
- Vector storage and retrieval
- Similarity search using cosine distance
- RAG response generation using Claude
- Conversation history support
- Context-aware responses
- Logging triage results
- Batch operations support
- Error alerts with formatted messages
- Success notifications
The workflow implements comprehensive error handling:
- Input Validation: Zod schemas validate all inputs
- Error Propagation: Errors emit
processing.failedevents - Slack Alerts: Automatic notifications for failures
- Graceful Degradation: Logging/alert failures don't crash the workflow
- State Preservation: Failed requests remain in state for debugging
Monitor your workflow through:
- Motia Workbench: Visual flow representation
- Logs: Structured logging at each step
- State: Inspect stored data using state manager
- Google Sheets: Historical log of all processed requests
- Slack: Real-time error notifications
Modify services/cohere.service.ts:
export function splitText(text: string, chunkSize: number = 400, overlap: number = 40)Update services/cohere.service.ts:
model: 'embed-english-v3.0' // Change to other Cohere modelsEdit steps/ragAgent/ragAgent.step.ts:
const systemMessage = 'Your custom system prompt here';Update services/supabase.service.ts:
match_threshold: 0.7 // Adjust between 0 and 1- Check Supabase connection and credentials
- Verify table and function creation
- Check embedding dimensions match (1024 for Cohere v3)
- Increase chunk overlap for better context
- Adjust similarity threshold
- Add more diverse training documents
- Refine system prompt
- Verify bot token and scopes
- Check channel name includes #
- Ensure bot is invited to channel
- Verify service account credentials
- Check sheet is shared with service account
- Confirm sheet name matches code
MIT
