Zen — Financial AI Chat
Conversational AI for wealth management with RAG and web search
Zen — Financial AI Chat
Zen is Sentinel’s conversational AI engine built for wealth management professionals. Ask questions about markets, portfolios, regulations, and financial products. Upload documents for contextual Q&A powered by RAG (Retrieval-Augmented Generation). Toggle web search for real-time market data, stock prices, and mutual fund NAVs.
Zen uses a non-streaming synchronous architecture — each message gets a complete response in a single API call. No SSE, no WebSockets, no partial rendering. The backend processes the query through intelligent agents, applies guardrail checks, and returns the full response with metadata.
Chat Flow
sequenceDiagram
participant U as User
participant FE as Frontend
participant BFF as Studio BFF
participant ZEN as Zen Backend
U->>FE: Click "Start New Chat"
FE->>BFF: POST /api/v1/zen/chat/
BFF-->>FE: Session UUID
FE->>FE: Navigate to /zen/chat/{uuid}
U->>FE: Type message + send
FE->>BFF: POST /api/v1/zen/chat/invoke (FormData)
Note over FE,BFF: session_id, query, web_search,<br/>agent_id, skip_guardrail
BFF->>ZEN: Forward to Zen Backend
ZEN-->>BFF: {response, meta, guardrail}
BFF-->>FE: ResponseEnvelope
FE->>FE: Render markdown response
Step-by-step:
- Create Session — User clicks “Start New Chat” in the sidebar. The frontend sends
POST /api/v1/zen/chat/to create a new session. The backend returns a UUID. - Navigate — The frontend navigates to
/zen/chat/{uuid}. The chat interface loads with an empty conversation. - Send Message — User types a question and hits send. The frontend packages the message as
FormDataand sends it to the invoke endpoint. - Process — The Studio BFF forwards the request to the Zen backend. The backend routes the query through the appropriate agent, optionally performs web search, applies guardrails, and generates a response.
- Render — The frontend receives the complete response and renders it as financial-aware markdown with tables, currency formatting, and color-coded metrics.
Key Features
Web Search
Toggle web search directly in the chat input area. When enabled, the AI queries the web for real-time information before generating a response.
What it provides:
- Live stock prices and index levels
- Latest mutual fund NAVs and returns
- Recent market news and regulatory updates
- Fund performance comparisons with current data
How it works:
- The
web_searchfield in the invoke request is a string:"True"or"False" - The response
meta.web_searchfield indicates whether web search was actually used - Web search adds latency (typically 2-5 seconds) but provides current data instead of training cutoff data
When to use it:
- Current prices, NAVs, or index levels
- Recent regulatory changes or SEBI circulars
- Fund performance over specific recent periods
- Any question where “as of today” matters
Nexus Document Integration
Zen sessions can now receive documents sourced directly from the Nexus pipeline. When a Nexus-processed financial document is attached to a session, the chat page shows a NexusProcessingIndicator — a live status banner that tracks the document through the 10-stage pipeline.
How it works:
- A Nexus document is linked to the session (via
SessionDocument.source = 'nexus'). - The frontend polls
GET /zen/chat/{sessionId}/documents/{docId}/statusevery few seconds. - The indicator shows the current pipeline stage (
current_stage) and percentage complete (progress_pct). - Once
statusreaches'completed', the indicator dismisses and the document is available for RAG queries.
The status endpoint is polled with suppressAuthEvent: true, so 401 responses from background polling do not trigger the global session-expired modal.
Session document fields (SessionDocument):
| Field | Description |
|---|---|
doc_id |
Unique document identifier |
filename |
Original file name |
source |
'upload', 'nexus', or 's3_url' |
status |
Current processing state |
nexus_process_id |
Nexus V2 process ID for progress polling |
nexus_job_id |
Nexus job ID |
RAG Document Upload
Upload documents directly into a chat session for contextual Q&A. The uploaded files are processed and indexed, allowing the AI to answer questions specifically about the document content.
Supported flow:
- Click the attachment icon in the chat input
- Select PDF or document files
- Files are uploaded via
POST /api/v1/zen/uploads/ - Ask questions about the uploaded content
- The AI retrieves relevant sections from the document to ground its answers
Use cases:
- Upload a CAS and ask “What is my total equity exposure?”
- Upload a scheme document and ask “What are the exit load conditions?”
- Upload a regulatory circular and ask “What are the key compliance changes?”
Guardrails
Every response passes through a safety guardrail system. Guardrails ensure responses stay within appropriate boundaries for financial advice.
Response behavior:
guardrail: null— No guardrail was triggered. The response is clean.guardrail: { passed: true, reason: null }— Guardrail evaluated and passed.guardrail: { passed: false, reason: "..." }— Guardrail triggered. The reason explains why the response was flagged. The UI may display a warning alongside the response.
The skip_guardrail field in the invoke request is always set to "false" in production. It exists for development testing only.
Agent Invocation
The Zen backend uses specialized agents to handle different types of queries. The meta.agents_invoked array in the response reveals which agents processed the query.
Agents are selected automatically based on query intent. The default agent handles general financial questions. Specialized agents handle portfolio analysis, regulatory queries, and market data requests.
Default agent_id: 6989c8987e0f5c816015fd18
The agent ID is sent with every invoke request. The backend may invoke additional agents internally based on the query content.
Agent Invocation Flow
The following diagram illustrates how the Zen backend routes an incoming query through its agent system. The default agent acts as the entry point and may delegate to specialized agents depending on query intent.
flowchart TD
Q["User Query"]:::primary --> GR{"Guardrail<br/>Check"}:::warning
GR -->|Blocked| WARN["Return guardrail<br/>warning"]:::danger
GR -->|Passed| ROUTER["Agent Router"]:::secondary
ROUTER --> DEFAULT["Default Agent<br/>General Q&A"]:::highlight
ROUTER --> PORTFOLIO["Portfolio Agent<br/>Holdings analysis"]:::highlight
ROUTER --> REGULATORY["Regulatory Agent<br/>SEBI & compliance"]:::highlight
ROUTER --> MARKET["Market Agent<br/>Prices & NAVs"]:::highlight
DEFAULT --> WS{"Web Search<br/>enabled?"}:::warning
PORTFOLIO --> WS
REGULATORY --> WS
MARKET --> WS
WS -->|Yes| SEARCH["Web Search<br/>Fetch live data"]:::neutral
WS -->|No| RAG{"Documents<br/>uploaded?"}:::warning
SEARCH --> GEN["Generate Response"]:::secondary
RAG -->|Yes| RETRIEVE["RAG Retrieval<br/>Doc chunks"]:::neutral
RAG -->|No| GEN
RETRIEVE --> GEN
GEN --> RESP["Return response<br/>+ meta + guardrail"]:::success
classDef primary fill:#dbeafe,stroke:#3b82f6,color:#1e293b
classDef secondary fill:#e0e7ff,stroke:#6366f1,color:#1e293b
classDef success fill:#d1fae5,stroke:#10b981,color:#1e293b
classDef warning fill:#fef3c7,stroke:#f59e0b,color:#1e293b
classDef danger fill:#fee2e2,stroke:#ef4444,color:#1e293b
classDef neutral fill:#f1f5f9,stroke:#64748b,color:#1e293b
classDef highlight fill:#fae8ff,stroke:#a855f7,color:#1e293b
classDef dark fill:#1e293b,stroke:#334155,color:#f8fafc
Web Search vs RAG Query Paths
When a user sends a message, the query follows one of two enrichment paths depending on the toggle states — web search for live external data, or RAG retrieval for uploaded document context. These paths are mutually exclusive in practice.
flowchart LR
subgraph Input
MSG["User Message"]:::primary
end
MSG --> CHECK{"web_search<br/>= true?"}:::warning
CHECK -->|Yes| WEB_PATH
CHECK -->|No| DOC_CHECK{"Documents<br/>in session?"}:::warning
subgraph WEB_PATH["Web Search Path"]
W1["Query search engine<br/>for live data"]:::danger --> W2["Inject results<br/>into context"]:::danger
end
DOC_CHECK -->|Yes| RAG_PATH
DOC_CHECK -->|No| DIRECT["Direct LLM query<br/>training data only"]:::neutral
subgraph RAG_PATH["RAG Path"]
R1["Embed query &<br/>vector search"]:::highlight --> R2["Retrieve top-k<br/>doc chunks"]:::highlight --> R3["Inject chunks<br/>into context"]:::highlight
end
WEB_PATH --> LLM["LLM generates<br/>grounded response"]:::success
RAG_PATH --> LLM
DIRECT --> LLM
classDef primary fill:#dbeafe,stroke:#3b82f6,color:#1e293b
classDef secondary fill:#e0e7ff,stroke:#6366f1,color:#1e293b
classDef success fill:#d1fae5,stroke:#10b981,color:#1e293b
classDef warning fill:#fef3c7,stroke:#f59e0b,color:#1e293b
classDef danger fill:#fee2e2,stroke:#ef4444,color:#1e293b
classDef neutral fill:#f1f5f9,stroke:#64748b,color:#1e293b
classDef highlight fill:#fae8ff,stroke:#a855f7,color:#1e293b
classDef dark fill:#1e293b,stroke:#334155,color:#f8fafc
The Web Search Path fetches real-time data from the internet (stock prices, NAVs, news). The RAG Path retrieves relevant sections from documents the user uploaded into the session. If neither is active, the LLM answers from its training knowledge alone.
Suggested Query Categories
Market Intelligence (web_search = true)
These queries benefit from real-time web data:
- “What are the latest NAV updates for SBI Bluechip Fund?”
- “Compare Nifty 50 vs Sensex performance this year”
- “What is the current yield on 10-year government bonds?”
- “Show me the top performing large cap mutual funds this quarter”
- “What did SEBI announce about mutual fund fee structures recently?”
- “What is the current AUM of HDFC AMC?”
Portfolio Analysis (web_search = false)
These queries work best with uploaded documents or prior context:
- “Analyze my portfolio’s asset allocation”
- “What is the total invested value across all holdings?”
- “Which funds in my portfolio have the highest expense ratio?”
- “Show me all holdings with negative returns”
- “What percentage of my portfolio is in mid-cap funds?”
- “Summarize the capital gains from this statement”
Regulatory and Product Knowledge
- “Explain the difference between direct and regular mutual fund plans”
- “What are the LTCG tax rules for equity mutual funds?”
- “How does SWP (Systematic Withdrawal Plan) work?”
- “What is the lock-in period for ELSS funds?”
Session Management
Chat sessions are listed in the left sidebar, organized by date groups.
Session Lifecycle
A chat session moves through several states from creation to deletion. The diagram below captures the full lifecycle including file uploads, auto-renaming, and termination.
stateDiagram-v2
[*] --> Created: POST /zen/chat/
Created --> Active: First message sent
Active --> Active: More messages
Active --> WithDocs: File uploaded
WithDocs --> Active: Query with RAG context
Active --> Renamed: Auto-title after first response
Renamed --> Active: Continue chatting
Active --> Deleted: User deletes
Deleted --> [*]
Sessions are auto-titled after the first assistant response based on the conversation content. The user can also manually rename a session at any time by double-clicking the title in the sidebar.
Date Grouping
Sessions are grouped into time-based categories:
| Group | Rule |
|---|---|
| Today | Sessions created or last active today |
| Yesterday | Sessions from yesterday |
| This Week | Sessions from the current week (excluding today/yesterday) |
| Earlier | All older sessions |
Session Actions
- Rename — Double-click the session title in the sidebar to enter edit mode. Type a new name and press Enter to save, or Escape to cancel.
- Delete — Click the delete icon on a session. A confirmation dialog appears. Deletion is permanent and removes all messages in the session.
- Switch — Click any session in the sidebar to load its conversation history.
Session Persistence
All messages within a session are persisted on the backend. Navigating away and returning loads the full conversation history. Session history is fetched via GET /api/v1/zen/chat/{session_id}/history.
Chat Message Rendering
Zen responses are rendered with financial-aware markdown processing optimized for wealth management content.
Currency Formatting
Monetary values are detected and formatted with proper Indian numbering (lakhs, crores) or international formatting based on context:
- Rs. 1,23,456.78 (Indian format)
- $1,234,567.89 (International format)
Percentage Coloring
Return percentages are color-coded for instant visual feedback:
- Green — Positive returns (gains)
- Red — Negative returns (losses)
- Neutral — Zero or informational percentages
Table Rendering
Financial tables are rendered with:
- Right-aligned numeric columns
- Proper decimal alignment for currency and percentage values
- Sortable headers where applicable
- Responsive horizontal scrolling for wide tables
Callout Detection
Special response sections are detected and rendered as styled callouts:
- Warning — Risk disclaimers, compliance notes
- Info — Educational explanations, definitions
- Tip — Actionable suggestions, best practices
API Contract
Create Session
POST /api/v1/zen/chat/
Response:
{
"status": "success",
"data": {
"session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}
Invoke (Send Message)
POST /api/v1/zen/chat/invoke
Content-Type: multipart/form-data
FormData Fields:
| Field | Type | Required | Description |
|---|---|---|---|
session_id |
string | Yes | UUID of the chat session |
query |
string | Yes | The user’s message text |
skip_guardrail |
string | Yes | Always "false" in production |
web_search |
string | Yes | "true" or "false" — whether to search the web |
agent_id |
string | Yes | Agent identifier. Default: "6989c8987e0f5c816015fd18" |
Response:
{
"status": "success",
"data": {
"message_id": "msg-uuid-user",
"response_message_id": "msg-uuid-assistant",
"response": "Markdown formatted response text...",
"meta": {
"web_search": "True",
"agents_invoked": ["agent-name"],
"processing_time_ms": 3200
},
"guardrail": null,
"error": null
}
}
Fetch Session History
GET /api/v1/zen/chat/{session_id}/history
Returns all messages in the session, ordered chronologically. Each message includes role (user, assistant, or system), content, timestamp, and metadata.
System messages: The backend may inject
role: 'system'messages for pipeline status notifications (e.g., when a Nexus document finishes processing). These are rendered as informational banners rather than chat bubbles.
Upload Document
POST /api/v1/zen/uploads/
Content-Type: multipart/form-data
Upload files for RAG-powered contextual Q&A within the session.
List Sessions
GET /api/v1/zen/chat/
Returns all sessions for the authenticated user, ordered by last activity. Used to populate the sidebar.
Delete Session
DELETE /api/v1/zen/chat/{session_id}
Permanently removes the session and all its messages. Supports keepalive: true to ensure the request completes even when called during page navigation (e.g., on tab close).
Frontend Routes
| Route | Description |
|---|---|
/zen |
Landing page. Shows the session sidebar and a prompt to start a new chat or select an existing session. |
/zen/chat/[sessionId] |
Active chat interface for a specific session. Displays message history, input bar with web search toggle, and file upload. |
Architecture Notes
- Non-streaming — Zen uses synchronous request-response. The frontend shows a loading indicator while waiting for the complete response. No partial message streaming.
- BFF Proxy — All Zen API calls route through the Studio BFF via a wildcard proxy at
/api/v1/zen/*. Unlike Nexus (which has 32 explicitly defined routes), Zen uses a single wildcard that forwards all paths to the Zen backend. - FormData — The invoke endpoint uses
multipart/form-datarather than JSON. All fields are strings, including booleans ("true"/"false"). - ResponseEnvelope — The Studio API client automatically unwraps the
ResponseEnvelope<T>wrapper, so frontend callers receive the innerdataobject directly.