IPC Bridge
useAgent hook
Section titled “useAgent hook”src/hooks/useAgent.ts is the single source of truth for all agent communication. It:
- Listens on the
agent://streamTauri event — each event payload is one NDJSON line from the sidecar stdout - Routes each message type to state updates or terminal writes
- Exposes command dispatchers as stable
useCallbackrefs
Returned values
Section titled “Returned values”// StateagentPhase: "idle" | "thinking" | "tool_running"modelStatus: { backend, loaded, vramUsedMb, modelSizeMb, kvCacheMb }loadProgress: { pct, backend } | nullgenerationStats: { totalTokens, tokensPerSec }pendingPermission: { id, tool, input } | nulldownloadProgress: DownloadProgress | nulldownloadedModelPath: string | nullmodelCatalog: ModelCatalogEntry[]
// Refs for terminal writeswriteToTerminal: React.RefObject<(text: string) => void>
// CommandssendInput(text: string): Promise<void>interrupt(): voidresetSession(): voidsetWorkingDirectory(path: string, silent?: boolean): Promise<void>loadModel(modelPath: string, backend?: string): Promise<void>fetchCatalog(): Promise<void>startDownload(modelId, destDir?, hfToken?): Promise<void>cancelDownload(): Promise<void>resolvePermission(id: string, approved: boolean): voidcheckInstalledModels(dir: string): Promise<Set<string>>Model loading flow
Section titled “Model loading flow”loadModel() sets modelLoadingRef.current = true before invoking Tauri. The sidecar sends model_progress events (pct 0–100) which update loadProgress. When the sidecar sends model_status with loaded: true, useAgent checks modelLoadingRef — if true, it sets loadProgress to pct: 100 and clears the ref. This prevents the periodic status poll (every 10s) from re-triggering the progress bar.
useConfig hook
Section titled “useConfig hook”src/hooks/useConfig.ts — persists the AppConfig to two layers:
localStorage(synchronous) — ensuresconfig.model_pathis available on the very first render, before any async work- Tauri
set_configinvoke (async, fire-and-forget) — backup persistence viatauri-plugin-store
interface AppConfig { working_directory: string; model_path: string; // persisted for startup auto-load; not editable in UI context_size: number; // 0 = auto-calculate from RAM max_new_tokens: number; auto_context: boolean; auto_max_tokens: boolean; permission_mode: "ask" | "auto_read" | "auto_all"; network_enabled: boolean;}Tauri commands
Section titled “Tauri commands”The Rust core exposes these commands to the frontend via invoke():
| Command | Description |
|---|---|
send_input | Forward user text to sidecar stdin |
set_working_directory | Send cd message to sidecar |
get_config | Read persisted config |
set_config | Write config to Tauri store |
load_model | Send load_model message to sidecar |
get_model_status | Send status_request to sidecar |
interrupt | Send interrupt to sidecar |
get_download_catalog | Send download_catalog request |
start_model_download | Send download_start to sidecar |
cancel_model_download | Send download_cancel to sidecar |
Tauri capabilities
Section titled “Tauri capabilities”Permissions granted to the WebView (in src-tauri/capabilities/default.json):
| Permission | Used for |
|---|---|
core:default | Core Tauri APIs |
core:window:* | Window controls (minimize, maximize, close) |
shell:allow-execute | Running the sidecar |
shell:allow-open | Opening URLs in the system browser |
dialog:default | File/directory picker dialogs |
fs:default | App-specific directory access |
fs:allow-read-dir | readDir for installed model detection |
fs:scope-home-recursive | Access to ~/CyberPaw/models/ |
store:default | Config persistence via tauri-plugin-store |