@uvi01/rag-stage
v0.1.1
Published
A Backstage **frontend** plugin that provides an AI-powered chat interface with real-time streaming responses, conversation management, file uploads, and configurable LLM models and RAG sources.
Maintainers
Readme
@uvi01/rag-stage
A Backstage frontend plugin that provides an AI-powered chat interface with real-time streaming responses, conversation management, file uploads, and configurable LLM models and RAG sources.
Requires @uvi01/rag-stage-backend to be installed and running.
Installation
yarn --cwd packages/app add @uvi01/rag-stageThe plugin is available at /rag-stage.
Frontend-readable configuration
Only ragChat.permission and ragChat.sources are exposed to the frontend plugin. Provider, chat model, embedding model, API base URL, API token, and temperature values are intentionally excluded from the frontend config schema. The Settings panel displays sanitized provider metadata returned by the backend /config endpoint.
# app-config.yaml
ragChat:
# Controls whether Backstage permission checks are enforced.
# false (default) — all authenticated users have full access.
# true — ragChatChatPermission gates chat/upload;
# ragChatAdminPermission gates model/source management in Settings.
permission:
enabled: false
# Source display metadata used by the Settings panel.
# Custom source targets are consumed by the backend when indexing content.
sources:
- id: catalog
name: Software Catalog
type: catalog
description: Query entities from the Backstage software catalog
- id: techdocs
name: TechDocs
type: techdocs
description: Query documentation from TechDocs
- id: my-docs
name: runbook
type: custom
description: External doc
target: https://example.com/runbooksConfigure ragChat.providers in the backend config only; see the backend README. Do not expose provider configuration through the frontend config schema.
Runtime model configuration displayed in Settings
The frontend does not read ragChat.providers directly from Backstage frontend config. Instead, ChatInterface.tsx calls the backend GET /api/rag-stage/config endpoint. The backend returns a sanitized response shaped like:
{
"models": [
{
"id": "gpt-4",
"name": "GPT-4",
"provider": "openai",
"apiBaseUrl": "https://api.openai.com/v1",
"temperature": 0.7,
"readOnly": true
}
],
"embedding": {
"provider": "openai",
"model": "text-embedding-3-small",
"apiBaseUrl": "https://api.openai.com/v1"
}
}This response must never include apiToken. Temperature is configured on the backend under ragChat.providers.chatModel[].temperature.
Implemented Features
Chat Interface
- Rich Messaging: Markdown rendering via
react-markdownwith GFM support and syntax highlighting for code blocks. - Citations: Source citations derived from RAG context are rendered as interactive cards below assistant responses.
- Real-time Streaming: SSE streaming with a typing indicator and auto-scroll.
- Conversation Management: Multi-conversation sidebar with search, inline renaming, and export (Markdown/JSON).
- Usage Tracking: Per-message token counts and estimated cost indicators.
File Uploads
- Attach files (TXT, PDF, DOCX) directly to a conversation.
- Upload progress bar and optimistic UI updates.
- Scoped indexing ensures uploaded files are only retrieved for the specific conversation.
Settings Panel
- Backend-config-driven AI settings: Provider, chat model, embedding model, and temperature are displayed as read-only values from a backend-safe config response.
- Secure credential handling: API tokens are excluded from the frontend config and are never sent to the browser.
- Appearance: Toggles for auto-scroll and notification sounds.
Files
| File | Purpose |
|------|---------|
| src/plugin.tsx | Plugin registration, PageBlueprint, ApiBlueprint |
| src/api.ts | RagChatConfigApi — reads only frontend-safe permission and sources keys from ragChat: config |
| src/permissions.ts | Permission definitions (shared with backend) |
| src/components/ChatUI/ChatInterface.tsx | Main layout, SSE stream consumer, identity fetch |
| src/components/ChatUI/ChatMessage.tsx | Message bubble with Markdown and Citation rendering |
| src/components/ChatUI/ChatInput.tsx | Text input with file attachment and keyboard shortcuts |
| src/components/ChatUI/ChatSidebar.tsx | Conversation list with search and filter |
| src/components/ChatUI/SettingsPanel.tsx | Settings dialog with permission-aware controls |
How the two plugins relate
Both plugins share a single ragChat: config block in app-config.yaml, but each reads a different subset of it:
| Config key | Read by | Purpose |
|---|---|---|
| ragChat.permission.enabled | Frontend + Backend | Toggles permission enforcement in both plugins |
| ragChat.providers.type | Backend only; sanitized via /config | Provider type (openai, anthropic, google, custom) |
| ragChat.providers.apiToken | Backend only ⚠️ | Shared provider token — never sent to the browser |
| ragChat.providers.apiBaseUrl | Backend only; sanitized via /config | Optional provider API base URL |
| ragChat.providers.chatModel[] | Backend only; sanitized via /config | Configured chat models and per-model temperature |
| ragChat.providers.chatModel[].temperature | Backend only; sanitized via /config | Chat completion temperature for that model |
| ragChat.providers.embedding.model | Backend only; sanitized via /config | Embedding model used for RAG vector search |
| ragChat.sources[].id/name/target | Frontend + Backend | Source identity and display; target is shown for configured/user sources |
| ragChat.sources[].target | Backend only | URL or file path for custom sources |
Security rule:
providersis excluded from the frontend config declaration. The backend may return sanitized provider metadata from/config, but it never includesapiToken. Always use environment variable substitution for backend secrets (for example${OPENAI_API_TOKEN}) and never hardcode real tokens.
Development
cd plugins/rag-stage
yarn start
yarn test
yarn lintTODO
- [ ] Image Generation Support
- Integrate with DALL-E or Stable Diffusion for image generation responses.
- [ ] Voice Input
- Add Web Speech API integration for hands-free queries.
