Spacerr includes a complete AI workspace, not a small demo chat. It has persistent conversations, projects, files, model selection, streaming controls, realtime sidebar updates, tool rendering, citations, generated images, and a global AI widget.
What It Looks Like
The AI product surface is split into a few user facing areas:
- Dashboard chat at
src/features/ai/chat/components/dashboard-chat.tsx. - Chat session UI under
src/features/ai/chat/components/chat-session. - Chat sidebar under
src/features/ai/chat/components/chat-dashboard-sidebar. - Project workspace under
src/features/ai/chat/components/project-workspace. - Global AI widget under
src/features/ai/widget. - Global realtime bridge at
src/features/ai/chat/components/chat-realtime-events-bridge.tsx.
The main chat route renders the dashboard shell, sidebar, active chat session, and project workspace surfaces. The user can create chats, move chats into projects, upload files, search history, choose a model, stop streams, retry messages, and regenerate assistant responses.
AI Widget
The app also includes a global AI widget for pages that exist outside the dashboard. Many real SaaS products have important public and account surfaces such as the landing page, pricing page, checkout flow, blog, contact page, and legal pages. A widget gives users a way to ask questions and get help from those surfaces without first navigating into the dashboard workspace.
The widget is intentionally extensible. You can keep it as a lightweight assistant entry point, connect it to support workflows, pass page context into prompts, limit where it appears, or reshape it for your own product experience. The route visibility logic lives in src/features/ai/widget/utils/ai-widget-route-visibility.utils.ts, and the UI lives under src/features/ai/widget/components.
Core Features
The workspace includes:
- Persistent chat history with saved messages and older message pagination.
- Auto generated and editable chat titles.
- Chat search across saved conversations.
- Draft persistence per chat, including unsent text and attachments.
- Pending prompt persistence for users who start typing before signing in.
- File upload, drag and drop, paste support, attachment previews, and attachment removal.
- Project workspaces with project chats, project source files, and project aware context.
- Multi model selection through the model picker, with the selected model saved locally.
- Streaming responses with stop, retry, regenerate, retry from a specific assistant message, and resume support.
- Markdown, code blocks, math, Mermaid diagrams, citations, generated image results, timestamps, and model metadata.
- Assistant message actions for copy, like, unlike, removing reactions, and optional unlike feedback.
- User message copy actions.
- Tool status labels that show human readable progress for web search, image generation, and support tools.
- Realtime sidebar state, active stream indicators, unseen indicators, and multi tab updates.
Feature Layout
Most AI code lives under src/features/ai/chat.
src/features/ai/chat
api
components
constants
hooks
providers
repositories
schemas
store
tools
types
utilsUse components for UI, hooks for client behavior, repositories for data access, schemas for request validation, tools for AI tool calls, store for client runtime state, and utils for stream, context, message, and project helpers.
Request Flow
The chat request is validated by src/features/ai/chat/schemas/chat-request.schema.ts.
export const chatRequestSchema = z.object({
chatId: z.string().min(1),
trigger: z.enum(["submit-message", "regenerate-message"]).default("submit-message"),
projectId: z.string().min(1).nullable().optional(),
modelId: z.enum(CHAT_MODEL_IDS).default(DEFAULT_CHAT_MODEL_ID),
message: z.unknown().optional(),
pageUrl: z.url().optional(),
sourceClientId: z.string().min(1).optional(),
})The important fields are:
chatIdidentifies the conversation.triggerdecides whether the user submitted a new message or regenerated an assistant response.projectIdconnects the request to a project workspace.modelIdchooses the active model.messagecarries the incoming user message.pageUrlgives the assistant current page context.sourceClientIdhelps realtime updates ignore events from the same browser client.
Where To Customize
Use these files first:
src/features/ai/chat/constants/chat-model.constants.tsfor model options, context budget, and project source limits.src/features/ai/chat/constants/ai-shared-context.constants.tsfor product context and available pages.src/features/ai/chat/utils/chat-system-prompt.server.tsfor system prompt assembly.src/features/ai/chat/tools/chat-tools.server.tsfor available tool calls.src/features/ai/chat/components/chat-sessionfor the chat UI.src/features/ai/chat/components/chat-dashboard-sidebarfor sidebar behavior.src/features/ai/chat/components/project-workspacefor project files and project chats.src/features/ai/widgetfor the global AI widget.
Keep AI product behavior inside the feature owned AI folders. Shared route strings still belong in ApiRoutes and WebRoutes.