Raw
1 // Typed wrappers around the Siti on-device chat backend (Rust/Tauri commands
2 // and events). Keeping the IPC surface in one place means components never
3 // touch raw command-name strings.
4
5 import { invoke } from "@tauri-apps/api/core";
6 import { listen, type UnlistenFn } from "@tauri-apps/api/event";
7 import { getVersion } from "@tauri-apps/api/app";
8
9 export type ChatStatus =
10 | "unloaded"
11 | "loading"
12 | "ready"
13 | "generating"
14 | "error";
15
16 export interface ModelInfo {
17 id: string;
18 name: string;
19 org: string;
20 description: string;
21 approx_memory: string;
22 size_bytes: number | null;
23 is_downloaded: boolean;
24 is_selected: boolean;
25 }
26
27 /** Snapshot of the engine, from `chat_get_status` (Ed's `EngineInfo`). */
28 export interface EngineInfo {
29 status: ChatStatus;
30 model_name: string | null;
31 approx_memory: string | null;
32 history_length: number;
33 }
34
35 export interface ChatStatusPayload {
36 status: ChatStatus;
37 model_name: string | null;
38 error: string | null;
39 }
40
41 /** `chat_reply`: the whole reply once generation ends. `id` matches the
42 * `chat_text_delta` events of the same turn. */
43 export interface ChatReplyPayload {
44 id: string;
45 session: string;
46 reply: string | null;
47 duration: string | null;
48 error: string | null;
49 }
50
51 /** `chat_text_delta`: one piece of the reply as it is generated. */
52 export interface ChatTextDeltaPayload {
53 id: string;
54 session: string;
55 delta: string;
56 }
57
58 export interface ChatMessagePayload {
59 role: "system" | "user" | "assistant";
60 content: string;
61 }
62
63 // ── Commands ────────────────────────────────────────────────────────────────
64
65 export const listModels = () => invoke<ModelInfo[]>("chat_list_models");
66
67 export const setModel = (modelId: string) =>
68 invoke<void>("chat_set_model", { modelId });
69
70 export const removeModel = (modelId: string) =>
71 invoke<string>("chat_remove_model", { modelId });
72
73 export const sendMessage = (message: string) =>
74 invoke<void>("chat_send_message", { message });
75
76 export const getStatus = () => invoke<EngineInfo>("chat_get_status");
77
78 export const getHistory = () =>
79 invoke<ChatMessagePayload[]>("chat_get_history");
80
81 /** Resolves to how many messages were dropped. */
82 export const clearHistory = () => invoke<number>("chat_clear_history");
83
84 /**
85 * Bytes of a model's weights on disk so far, including a download still in
86 * flight. Poll while the model is loading and compare against the model's
87 * `size_bytes` to render real progress.
88 */
89 export const getDownloadProgress = (modelId: string) =>
90 invoke<number>("chat_download_progress", { modelId });
91
92 // ── App metadata ──────────────────────────────────────────────────────────
93
94 /** Marketing version (CFBundleShortVersionString) from tauri.conf.json. */
95 export const getAppVersion = () => getVersion();
96
97 /** Native build number (Apple CFBundleVersion); `null` when unavailable. */
98 export const getBuildVersion = () =>
99 invoke<string | null>("app_build_version");
100
101 // ── Events ──────────────────────────────────────────────────────────────────
102
103 export const onStatusChanged = (cb: (p: ChatStatusPayload) => void): Promise<UnlistenFn> =>
104 listen<ChatStatusPayload>("chat_status_changed", (e) => cb(e.payload));
105
106 export const onReply = (cb: (p: ChatReplyPayload) => void): Promise<UnlistenFn> =>
107 listen<ChatReplyPayload>("chat_reply", (e) => cb(e.payload));
108
109 export const onTextDelta = (
110 cb: (p: ChatTextDeltaPayload) => void
111 ): Promise<UnlistenFn> =>
112 listen<ChatTextDeltaPayload>("chat_text_delta", (e) => cb(e.payload));
113
114 // ── Helpers ───────────────────────────────────────────────────────────────
115
116 /** Format a byte count as a compact "1.9 GB" / "941 MB" string. */
117 export function formatSize(bytes: number | null): string {
118 if (!bytes) return "";
119 const gb = bytes / 1e9;
120 if (gb >= 1) return `${gb.toFixed(gb >= 10 ? 0 : 1)} GB`;
121 return `${Math.round(bytes / 1e6)} MB`;
122 }