-
Notifications
You must be signed in to change notification settings - Fork 0
Store API Reference
Mosaic uses Zustand v5 for state management with seven stores. This page documents every store's state shape, actions, and persistence strategy.
Mosaic uses several Zustand patterns to keep state management clean and predictable:
// No middleware, no persistence — simple and fast
import { create } from 'zustand';
interface SimpleStore {
count: number;
increment: () => void;
}
const useSimpleStore = create<SimpleStore>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}));This pattern is used for toastStore and pruneStore (in-memory, no persistence).
// Subscribe to changes and save manually
const usePersistedStore = create<PersistedStore>((set, get) => ({
...defaultState,
// Load on initialization:
...loadFromStorage(),
}));
// Save on changes:
usePersistedStore.subscribe((state) => {
saveToStorage(state);
});This pattern is used for all persistent stores. The persistence is manual (not using Zustand's persist middleware) because:
- More control over what fields persist (some fields are transient)
- Custom validation on load
- Debouncing for canvas data
// canvasStore uses debounced saves
let saveTimer: number | null = null;
const useCanvasStore = create<CanvasStore>((set, get) => ({
// ... state and actions
updateNodePosition: (id, pos) => {
set((state) => ({
nodes: state.nodes.map((n) =>
n.id === id ? { ...n, position: pos } : n
),
}));
// Debounce save (300ms)
if (saveTimer) clearTimeout(saveTimer);
saveTimer = setTimeout(() => {
saveToManagerStore(get());
}, 300);
},
}));This prevents excessive localStorage writes during rapid operations (like dragging a node).
File: src/store/canvasStore.ts
Persistence: Debounced save (300ms) to canvasManagerStore per canvas
interface CanvasState {
nodes: Node[]; // React Flow nodes
edges: Edge[]; // React Flow edges
activeNodeId: string | null; // Currently selected node
viewport: { x: number; y: number; zoom: number }; // Canvas viewport
positionHistory: CanvasSnapshot[]; // Undo history (max 50)
bookmarkedIds: string[]; // IDs of bookmarked nodes
currentNodeIndex: number; // Auto-incrementing node ID counter
}Creates a new node as a child of parentId. Automatically generates position based on existing children. Returns the new node's ID.
const nodeId = canvasStore.getState().addNode('root-1', 'Hello world', 'branch');Removes a node and all its descendants. Shows a confirmation dialog if the node has children. Root nodes cannot be deleted.
canvasStore.getState().removeCascade('node-5');Updates a node's data fields (label, confidence, error state, etc.).
canvasStore.getState().updateNode('node-5', { label: 'Updated message', confidence: 92 });Updates a node's position and captures a snapshot in positionHistory for undo.
canvasStore.getState().updateNodePosition('node-5', { x: 100, y: 200 });Pops the last position snapshot from positionHistory and restores nodes/edges.
canvasStore.getState().undo();Removes all nodes and edges except the root node. Captures undo snapshot.
Toggles the collapsed state of a node. When collapsed, descendant nodes are hidden.
Toggles the bookmarked state of a node. Adds/removes from bookmarkedIds.
Runs BFS radial tree auto-layout. If startNodeId is provided, layouts from that node; otherwise from root.
Returns all descendant node IDs recursively. Used for cascade deletion.
Walks up parent edges to return the complete conversation path from root to the given node. Used for streaming context.
Replaces all nodes and edges with imported data. Validates before importing.
Loads a canvas's data from canvasManagerStore. Called when switching tabs.
Immediately saves the current canvas state to canvasManagerStore (bypasses debounce).
File: src/store/canvasManagerStore.ts
Persistence: localStorage (mosaic-canvases, mosaic-canvas-data-*)
interface CanvasManagerState {
canvases: CanvasMeta[]; // Array of { id, name, createdAt }
activeCanvasId: string | null; // Currently active canvas
}Creates a new canvas with an optional name. Returns the new canvas ID.
Deletes a canvas and its stored data. Auto-switches to another canvas if the active one is deleted.
Renames a canvas (double-click on tab to trigger).
Switches to a different canvas. Saves current canvas state before switching.
Duplicates a canvas with all its data. Returns the new canvas ID.
Saves canvas data to localStorage. Key: mosaic-canvas-data-{id}.
Loads canvas data from localStorage. Validates with validateCanvasData before returning.
File: src/store/uiStore.ts
Persistence: localStorage (mosaic-ui)
interface UIState {
theme: 'void' | 'dusk' | 'sand' | 'snow' | 'sunrise';
zoom: number; // Current zoom level
showMiniMap: boolean;
showWelcome: boolean;
settingsOpen: boolean;
systemPrompt: string;
temperature: number; // 0.0 - 2.0
model: string; // Selected model ID
searchQuery: string;
searchOpen: boolean;
showBookmarksOnly: boolean;
confidenceEnabled: boolean;
tendrilsEnabled: boolean;
debateModels: string[]; // Models for parallel debate
ollamaConnected: boolean;
ollamaModels: string[];
ollamaUrl: string;
}Each state field has a corresponding setter:
setTheme(theme: string): void
setZoom(zoom: number): void
setShowMiniMap(show: boolean): void
setSettingsOpen(open: boolean): void
setSystemPrompt(prompt: string): void
setTemperature(temp: number): void
setModel(model: string): void
setSearchQuery(query: string): void
setSearchOpen(open: boolean): void
setShowBookmarksOnly(show: boolean): void
setConfidenceEnabled(enabled: boolean): void
setTendrilsEnabled(enabled: boolean): void
setDebateModels(models: string[]): void
setOllamaConnected(connected: boolean): void
setOllamaModels(models: string[]): void
setOllamaUrl(url: string): voidReturns the full model info for the currently selected model.
Returns all available models across all configured providers, including auto-detected Ollama models. Groups by provider with color indicators.
Returns the provider name for the currently selected model.
Returns whether the API key is configured for the currently selected provider.
When setTheme() is called, the store sets document.documentElement.classList to theme-{name}. On initialization, it auto-detects OS dark/light preference.
File: src/store/analyticsStore.ts
Persistence: localStorage (mosaic-analytics)
interface AnalyticsState {
stats: Record<string, CanvasStats>; // Keyed by canvas ID
}interface CanvasStats {
totalTokens: number;
totalCost: number;
modelBreakdown: Record<string, ModelStats>;
completions: CompletionRecord[]; // Last 100
}interface ModelStats {
tokens: number;
cost: number;
count: number;
}interface CompletionRecord {
model: string;
tokens: number;
cost: number;
timestamp: number;
}const PRICING: Record<string, { input: number; output: number }> = {
'mistral-large-latest': { input: 2.00, output: 6.00 },
'mistral-small-latest': { input: 0.20, output: 0.60 },
// Other models use sensible defaults
};Records a completion event. Estimates tokens as Math.ceil(text.length / 4). Calculates cost from pricing table.
analyticsStore.getState().recordCompletion('canvas-1', 'mistral-large-latest', 'Hello world');Computes canvas statistics from the current node/edge data:
interface NodeStats {
totalNodes: number;
branchNodes: number;
responseNodes: number;
rootNodes: number;
totalMessages: number;
depth: number; // Maximum tree depth
branchCount: number; // Number of branching points
}Resets all analytics for a given canvas.
File: src/store/ragStore.ts
Persistence: localStorage (mosaic-rag)
interface RAGState {
documents: RagDocument[];
enabled: boolean;
}interface RagDocument {
id: string;
filename: string;
size: number;
chunks: RagChunk[];
}interface RagChunk {
id: string;
text: string;
embedding?: number[]; // Optional embedding vector
metadata: {
documentId: string;
chunkIndex: number;
};
}Adds a document. Enforces limits (50 docs, 50MB total, 10MB per file).
Removes a document and all its chunks.
Removes all documents.
Toggles RAG on/off.
Searches for the most relevant chunks. Uses embedding cosine similarity if available, otherwise TF-IDF cosine similarity. Returns topK chunks (default 3).
File: src/store/toastStore.ts
Persistence: In-memory only (not persisted)
interface ToastState {
toasts: Toast[];
}interface Toast {
id: string;
type: 'info' | 'success' | 'error';
message: string;
}Adds a toast notification. Auto-dismisses after animation.
Manually removes a toast.
File: src/store/pruneStore.ts
Persistence: In-memory only (transient)
interface PruneState {
pruneActive: boolean;
pruneGoal: string;
isPruning: boolean;
}setPruneActive(active: boolean): void
setPruneGoal(goal: string): void
setIsPruning(pruning: boolean): voidThis store is intentionally simple — it only tracks the current pruning operation's state. The actual pruning logic (scoring branches) lives in useBranchPruning hook.
canvasManagerStore (persistent)
│
├── canvasStore (debounced save → canvasManagerStore)
│
uiStore (persistent, independent)
│
analyticsStore (persistent, independent)
│
ragStore (persistent, independent)
│
toastStore (transient, independent)
│
pruneStore (transient, independent)
Stores are independent — they do not subscribe to each other. Cross-store communication happens at the component/hook level (e.g., useStreamMessage reads from ragStore and writes to canvasStore and analyticsStore).
| Store | localStorage Key | Serialization | Validation |
|---|---|---|---|
| canvasManager | mosaic-canvases |
JSON | validateCanvasData |
| canvas data | mosaic-canvas-data-{id} |
JSON | validateCanvasData |
| uiStore | mosaic-ui |
JSON | validateUIState |
| analyticsStore | mosaic-analytics |
JSON | None |
| ragStore | mosaic-rag |
JSON | validateRagDocs |
All persisted stores validate their data on load using the validation utilities in src/utils/validation.ts. Invalid data is reset to defaults.
- Hook API Reference — All custom hooks with parameters and return types
- Component API Reference — All component props and usage
- State Management and Persistence — Architecture deep-dive
Mosaic — Branch, explore, and run code inline — an infinite canvas for AI conversations.
Built with Tauri, React, and Mistral AI.
GitHub Repository |
Report an Issue |
Releases
- Canvas and Node System
- LLM Provider Integration
- RAG System Guide
- Advanced AI Features
- Keyboard Shortcuts and UI Reference
- Tutorial - Branching and Parallel Exploration
- Tutorial - Using RAG with Documents
- Tutorial - Advanced Features in Practice
- Tutorial - Customizing Mosaic