@bitbaum/chatkit 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +162 -1
  2. package/dist/conversations.d.ts +99 -0
  3. package/dist/conversations.d.ts.map +1 -0
  4. package/dist/conversations.js +146 -0
  5. package/dist/conversations.js.map +1 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/react/ChatApp.d.ts +123 -0
  11. package/dist/react/ChatApp.d.ts.map +1 -0
  12. package/dist/react/ChatApp.js +215 -0
  13. package/dist/react/ChatApp.js.map +1 -0
  14. package/dist/react/ChatHistory.d.ts +28 -0
  15. package/dist/react/ChatHistory.d.ts.map +1 -0
  16. package/dist/react/ChatHistory.js +58 -0
  17. package/dist/react/ChatHistory.js.map +1 -0
  18. package/dist/react/Composer.d.ts +4 -1
  19. package/dist/react/Composer.d.ts.map +1 -1
  20. package/dist/react/Composer.js +3 -3
  21. package/dist/react/Composer.js.map +1 -1
  22. package/dist/react/Thread.d.ts +4 -0
  23. package/dist/react/Thread.d.ts.map +1 -1
  24. package/dist/react/Thread.js +4 -4
  25. package/dist/react/Thread.js.map +1 -1
  26. package/dist/react/hooks.d.ts +6 -7
  27. package/dist/react/hooks.d.ts.map +1 -1
  28. package/dist/react/hooks.js +155 -43
  29. package/dist/react/hooks.js.map +1 -1
  30. package/dist/react/icons.d.ts +7 -0
  31. package/dist/react/icons.d.ts.map +1 -1
  32. package/dist/react/icons.js +8 -0
  33. package/dist/react/icons.js.map +1 -1
  34. package/dist/react/index.d.ts +6 -0
  35. package/dist/react/index.d.ts.map +1 -1
  36. package/dist/react/index.js +3 -0
  37. package/dist/react/index.js.map +1 -1
  38. package/dist/react/use-chat-app.d.ts +81 -0
  39. package/dist/react/use-chat-app.d.ts.map +1 -0
  40. package/dist/react/use-chat-app.js +380 -0
  41. package/dist/react/use-chat-app.js.map +1 -0
  42. package/dist/stores.d.ts +63 -0
  43. package/dist/stores.d.ts.map +1 -0
  44. package/dist/stores.js +291 -0
  45. package/dist/stores.js.map +1 -0
  46. package/package.json +2 -2
  47. package/styles.css +420 -1
@@ -0,0 +1,380 @@
1
+ "use client";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { deriveTitle, newId, pickRestored, } from "../conversations.js";
4
+ const TEMP = "tmp";
5
+ export const isTemporaryId = (id) => !!id && id.startsWith(`${TEMP}-`);
6
+ function messageAttachments(list) {
7
+ if (list.length === 0)
8
+ return undefined;
9
+ return list.map((a) => a.kind === "image"
10
+ ? { kind: "image", name: a.name, previewUrl: `data:${a.mimeType};base64,${a.dataBase64}` }
11
+ : { kind: "text", name: a.name });
12
+ }
13
+ function readRemembered(key) {
14
+ if (!key)
15
+ return null;
16
+ try {
17
+ return globalThis.localStorage?.getItem(key) ?? null;
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ function writeRemembered(key, id) {
24
+ if (!key)
25
+ return;
26
+ try {
27
+ if (id)
28
+ globalThis.localStorage?.setItem(key, id);
29
+ else
30
+ globalThis.localStorage?.removeItem(key);
31
+ }
32
+ catch {
33
+ /* private mode: the chat simply does not reopen after a reload */
34
+ }
35
+ }
36
+ /**
37
+ * Everything ChatApp does that is not drawing: the list, the open chat, new
38
+ * and temporary chats, turns (one per conversation, each running on when the
39
+ * person opens another chat), the queue, titles and the reopen-on-reload.
40
+ */
41
+ export function useChatApp({ store, transport, makeTitle, conversationId, onConversationChange, rememberKey, }) {
42
+ const [list, setList] = useState([]);
43
+ const [listState, setListState] = useState("loading");
44
+ const [activeId, setActiveId] = useState(null);
45
+ const [temporary, setTemporary] = useState(false);
46
+ const [threads, setThreads] = useState({});
47
+ const [loadingId, setLoadingId] = useState(null);
48
+ const [live, setLive] = useState({});
49
+ const [stopped, setStopped] = useState({});
50
+ const [queue, setQueue] = useState([]);
51
+ const [problem, setProblem] = useState(null);
52
+ const [reload, setReload] = useState(0);
53
+ // Async work reads the CURRENT state through these, never a stale closure.
54
+ const threadsRef = useRef(threads);
55
+ const queueRef = useRef(queue);
56
+ const activeRef = useRef(activeId);
57
+ const temporaryRef = useRef(temporary);
58
+ const controllers = useRef(new Map());
59
+ const restored = useRef(false);
60
+ const transportRef = useRef(transport);
61
+ const titleRef = useRef(makeTitle);
62
+ useEffect(() => {
63
+ transportRef.current = transport;
64
+ titleRef.current = makeTitle;
65
+ });
66
+ const setThreadsNow = (fn) => {
67
+ threadsRef.current = fn(threadsRef.current);
68
+ setThreads(threadsRef.current);
69
+ };
70
+ const setQueueNow = (fn) => {
71
+ queueRef.current = fn(queueRef.current);
72
+ setQueue(queueRef.current);
73
+ };
74
+ const select = (id, temp) => {
75
+ activeRef.current = id;
76
+ temporaryRef.current = temp;
77
+ setActiveId(id);
78
+ setTemporary(temp);
79
+ };
80
+ /** Leaving a temporary chat ends it: its turn stops, its words are gone. */
81
+ const leaveTemporary = () => {
82
+ const id = activeRef.current;
83
+ if (!isTemporaryId(id))
84
+ return;
85
+ controllers.current.get(id)?.abort();
86
+ setThreadsNow((t) => {
87
+ const next = { ...t };
88
+ delete next[id];
89
+ return next;
90
+ });
91
+ setQueueNow((q) => q.filter((item) => item.conversation !== id));
92
+ };
93
+ const open = (id) => {
94
+ if (id === activeRef.current)
95
+ return;
96
+ leaveTemporary();
97
+ select(id, false);
98
+ if (threadsRef.current[id])
99
+ return;
100
+ setLoadingId(id);
101
+ store
102
+ .get(id)
103
+ .then((c) => {
104
+ if (c) {
105
+ setThreadsNow((t) => ({ ...t, [id]: c.messages }));
106
+ }
107
+ else {
108
+ // Deleted elsewhere: drop the row and land on a new chat.
109
+ setList((l) => l.filter((row) => row.id !== id));
110
+ if (activeRef.current === id)
111
+ select(null, false);
112
+ }
113
+ })
114
+ .catch(() => setProblem("open"))
115
+ .finally(() => setLoadingId((cur) => (cur === id ? null : cur)));
116
+ };
117
+ // The list, and on the first load the chat that was open before the reload.
118
+ useEffect(() => {
119
+ let alive = true;
120
+ setListState("loading");
121
+ store
122
+ .list()
123
+ .then((rows) => {
124
+ if (!alive)
125
+ return;
126
+ setList(rows);
127
+ setListState("ready");
128
+ if (!restored.current) {
129
+ restored.current = true;
130
+ const id = pickRestored(rows, conversationId, readRemembered(rememberKey));
131
+ if (id)
132
+ open(id);
133
+ }
134
+ })
135
+ .catch(() => {
136
+ if (!alive)
137
+ return;
138
+ restored.current = true;
139
+ setListState("error");
140
+ });
141
+ return () => {
142
+ alive = false;
143
+ };
144
+ // `open` and the ids are read once, at load; a store change reloads.
145
+ }, [store, reload]);
146
+ // A product that keeps the open chat in its URL drives it from there.
147
+ useEffect(() => {
148
+ if (conversationId === undefined || !restored.current)
149
+ return;
150
+ if (conversationId === null) {
151
+ if (activeRef.current && !isTemporaryId(activeRef.current))
152
+ select(null, false);
153
+ }
154
+ else if (conversationId !== activeRef.current)
155
+ open(conversationId);
156
+ }, [conversationId]);
157
+ // Remember the open chat (never a temporary one) and tell the product.
158
+ const stored = isTemporaryId(activeId) ? null : activeId;
159
+ useEffect(() => {
160
+ if (!restored.current)
161
+ return;
162
+ writeRemembered(rememberKey, stored);
163
+ onConversationChange?.(stored);
164
+ }, [stored]);
165
+ const save = (id, message) => {
166
+ if (isTemporaryId(id))
167
+ return;
168
+ store.append(id, message).catch(() => setProblem("save"));
169
+ const at = new Date().toISOString();
170
+ setList((l) => {
171
+ const row = l.find((c) => c.id === id);
172
+ return row ? [{ ...row, updatedAt: at }, ...l.filter((c) => c.id !== id)] : l;
173
+ });
174
+ };
175
+ const push = (id, message) => setThreadsNow((t) => ({ ...t, [id]: [...(t[id] ?? []), message] }));
176
+ const runTurn = async (id, text, attachments, history) => {
177
+ const temp = isTemporaryId(id);
178
+ const controller = new AbortController();
179
+ controllers.current.set(id, controller);
180
+ setStopped((s) => ({ ...s, [id]: false }));
181
+ setLive((l) => ({ ...l, [id]: {} }));
182
+ let soFar = {};
183
+ let ok = false;
184
+ try {
185
+ const result = await transportRef.current({
186
+ conversationId: temp ? null : id,
187
+ temporary: temp,
188
+ text,
189
+ attachments,
190
+ history,
191
+ signal: controller.signal,
192
+ update: (next) => {
193
+ soFar = { ...soFar, ...next };
194
+ if (!controller.signal.aborted)
195
+ setLive((l) => (id in l ? { ...l, [id]: soFar } : l));
196
+ },
197
+ });
198
+ if (controller.signal.aborted)
199
+ throw new DOMException("stopped", "AbortError");
200
+ const answer = typeof result === "string" ? { content: result } : result;
201
+ const message = { ...answer, id: newId("m"), role: "assistant" };
202
+ push(id, message);
203
+ save(id, message);
204
+ ok = true;
205
+ if (!temp && history.length === 0 && titleRef.current) {
206
+ void Promise.resolve(titleRef.current({ text, answer: answer.content }))
207
+ .then((title) => (title?.trim() ? rename(id, title.trim()) : undefined))
208
+ .catch(() => {
209
+ /* the derived title stays */
210
+ });
211
+ }
212
+ }
213
+ catch {
214
+ if (controller.signal.aborted) {
215
+ // Stopped: what had arrived is kept, as the apps keep a half answer.
216
+ if (soFar.text?.trim()) {
217
+ const message = {
218
+ id: newId("m"),
219
+ role: "assistant",
220
+ content: soFar.text,
221
+ };
222
+ push(id, message);
223
+ save(id, message);
224
+ }
225
+ else
226
+ setStopped((s) => ({ ...s, [id]: true }));
227
+ }
228
+ else {
229
+ push(id, { id: newId("m"), role: "assistant", content: "", failed: true });
230
+ }
231
+ }
232
+ finally {
233
+ controllers.current.delete(id);
234
+ setLive((l) => {
235
+ const next = { ...l };
236
+ delete next[id];
237
+ return next;
238
+ });
239
+ }
240
+ // The next queued message goes once a turn lands; a failed or stopped
241
+ // turn leaves the queue standing behind it, to be sent or removed.
242
+ if (ok) {
243
+ const next = queueRef.current.find((q) => q.conversation === id);
244
+ if (next) {
245
+ setQueueNow((q) => q.filter((item) => item.id !== next.id));
246
+ void sendIn(id, next.text, next.attachments);
247
+ }
248
+ }
249
+ };
250
+ const sendIn = async (id, text, attachments) => {
251
+ const history = (threadsRef.current[id] ?? []).filter((m) => !m.failed);
252
+ const message = {
253
+ id: newId("m"),
254
+ role: "user",
255
+ content: text,
256
+ ...(attachments.length ? { attachments: messageAttachments(attachments) } : {}),
257
+ };
258
+ push(id, message);
259
+ save(id, message);
260
+ await runTurn(id, text, attachments, history);
261
+ };
262
+ /** Composer's onSend. Resolves false to keep the draft (nothing was sent). */
263
+ const send = async (text, attachments = []) => {
264
+ let id = activeRef.current;
265
+ if (id && controllers.current.has(id)) {
266
+ setQueueNow((q) => [...q, { id: newId("q"), conversation: id, text, attachments }]);
267
+ return true;
268
+ }
269
+ if (!id) {
270
+ if (temporaryRef.current) {
271
+ id = newId(TEMP);
272
+ }
273
+ else {
274
+ try {
275
+ const created = await store.create({ title: deriveTitle(text) ?? "" });
276
+ id = created.id;
277
+ setList((l) => [created, ...l.filter((c) => c.id !== created.id)]);
278
+ }
279
+ catch {
280
+ setProblem("save");
281
+ return false;
282
+ }
283
+ }
284
+ setThreadsNow((t) => ({ ...t, [id]: [] }));
285
+ select(id, temporaryRef.current);
286
+ }
287
+ void sendIn(id, text, attachments);
288
+ return true;
289
+ };
290
+ const stop = () => {
291
+ const id = activeRef.current;
292
+ if (id)
293
+ controllers.current.get(id)?.abort();
294
+ };
295
+ /** Retry after a failed or stopped turn: the last message goes again. */
296
+ const retry = () => {
297
+ const id = activeRef.current;
298
+ if (!id || controllers.current.has(id))
299
+ return;
300
+ const thread = threadsRef.current[id] ?? [];
301
+ const kept = thread.filter((m) => !m.failed);
302
+ const lastUser = [...kept].reverse().find((m) => m.role === "user");
303
+ if (!lastUser)
304
+ return;
305
+ setThreadsNow((t) => ({ ...t, [id]: kept }));
306
+ const history = kept.slice(0, kept.indexOf(lastUser));
307
+ void runTurn(id, lastUser.content, [], history);
308
+ };
309
+ const newChat = () => {
310
+ leaveTemporary();
311
+ select(null, false);
312
+ };
313
+ /** In an empty new chat, switch it to temporary and back; in a chat with
314
+ * words in it, start a new temporary one. */
315
+ const toggleTemporary = () => {
316
+ const id = activeRef.current;
317
+ if (!id) {
318
+ select(null, !temporaryRef.current);
319
+ return;
320
+ }
321
+ leaveTemporary();
322
+ select(null, !isTemporaryId(id));
323
+ };
324
+ const rename = async (id, title) => {
325
+ setList((l) => l.map((c) => (c.id === id ? { ...c, title } : c)));
326
+ try {
327
+ await store.rename(id, title);
328
+ }
329
+ catch {
330
+ setProblem("save");
331
+ }
332
+ };
333
+ const remove = async (id) => {
334
+ controllers.current.get(id)?.abort();
335
+ setList((l) => l.filter((c) => c.id !== id));
336
+ setThreadsNow((t) => {
337
+ const next = { ...t };
338
+ delete next[id];
339
+ return next;
340
+ });
341
+ setQueueNow((q) => q.filter((item) => item.conversation !== id));
342
+ if (activeRef.current === id)
343
+ select(null, false);
344
+ try {
345
+ await store.remove(id);
346
+ }
347
+ catch {
348
+ setProblem("save");
349
+ setReload((n) => n + 1);
350
+ }
351
+ };
352
+ const key = activeId ?? "";
353
+ return {
354
+ list,
355
+ listState,
356
+ reloadList: () => setReload((n) => n + 1),
357
+ activeId,
358
+ stored,
359
+ temporary,
360
+ messages: threads[key] ?? [],
361
+ loading: loadingId !== null && loadingId === activeId,
362
+ live: live[key] ?? null,
363
+ busy: key in live,
364
+ busyIds: new Set(Object.keys(live)),
365
+ stopped: !!stopped[key],
366
+ queued: queue.filter((q) => q.conversation === activeId),
367
+ unqueue: (qid) => setQueueNow((q) => q.filter((item) => item.id !== qid)),
368
+ problem,
369
+ clearProblem: () => setProblem(null),
370
+ send,
371
+ stop,
372
+ retry,
373
+ open,
374
+ newChat,
375
+ toggleTemporary,
376
+ rename,
377
+ remove,
378
+ };
379
+ }
380
+ //# sourceMappingURL=use-chat-app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-chat-app.js","sourceRoot":"","sources":["../../src/react/use-chat-app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Where a ChatApp keeps its conversations. Storage is an ADAPTER: the screen
3
+ * reads and writes through `ConversationStore` and never knows whether the
4
+ * chats are on the device or on a server. Two reference adapters:
5
+ *
6
+ * localConversationStore({ key }) the device — signed-out chats
7
+ * httpConversationStore({ baseUrl }) the product's server — signed-in chats
8
+ */
9
+ import { type ConversationStore } from "./conversations.js";
10
+ type KeyValue = Pick<Storage, "getItem" | "setItem" | "removeItem">;
11
+ /** Bumped when the stored shape changes; an older shape is read as empty
12
+ * rather than misread. */
13
+ export declare const LOCAL_STORE_VERSION = 1;
14
+ /** A store in memory: a temporary chat, a test, a page with no storage. */
15
+ export declare function memoryConversationStore(): ConversationStore;
16
+ /**
17
+ * Conversations on the device. Never throws: storage that is missing, full,
18
+ * blocked or holding something unreadable degrades to memory for this page,
19
+ * so the chat still works and simply is not there after a reload.
20
+ *
21
+ * Layout (versioned): `<key>:v1` holds the list, `<key>:v1:<id>` each chat's
22
+ * messages — so one long chat can be evicted without losing the others. When
23
+ * the quota is reached the OLDEST chats are dropped until the write fits.
24
+ */
25
+ export declare function localConversationStore({ key, storage, limit, }?: {
26
+ /** Namespace on the device. One per product (and per signed-out person, if
27
+ * the device is shared and the product can tell them apart). */
28
+ key?: string;
29
+ /** Defaults to localStorage. `null` keeps everything in memory. */
30
+ storage?: KeyValue | null;
31
+ /** Most chats kept; the oldest go first. */
32
+ limit?: number;
33
+ }): ConversationStore;
34
+ export type HttpConversationStoreOptions = {
35
+ /** The collection, e.g. "/api/conversations". */
36
+ baseUrl: string;
37
+ /** Headers on every request (an auth token), or a function returning them. */
38
+ headers?: Record<string, string> | (() => Record<string, string>);
39
+ /** Defaults to the global fetch. */
40
+ fetch?: typeof fetch;
41
+ /**
42
+ * The product's own chat route already writes every turn (Heidi's
43
+ * `/messages`, Loki's `/api/loki`): then `append` sends nothing, so a turn
44
+ * is never stored twice.
45
+ */
46
+ serverWritesTurns?: boolean;
47
+ };
48
+ /**
49
+ * Conversations on the product's server, over this REST shape (Heidi's
50
+ * `/api/conversations`, generalised):
51
+ *
52
+ * GET {base} → { conversations: [{ id, title, updatedAt }] }
53
+ * POST {base} { title } → { conversation: { id, title, updatedAt } }
54
+ * GET {base}/{id} → { conversation, messages: [...] } 404 = gone
55
+ * POST {base}/{id}/messages { message } → 2xx
56
+ * PATCH {base}/{id} { title } → 2xx
57
+ * DELETE {base}/{id} → 2xx
58
+ *
59
+ * A failed request throws an Error naming the call; ChatApp shows it in words.
60
+ */
61
+ export declare function httpConversationStore({ baseUrl, headers, fetch: fetchImpl, serverWritesTurns, }: HttpConversationStoreOptions): ConversationStore;
62
+ export {};
63
+ //# sourceMappingURL=stores.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stores.d.ts","sourceRoot":"","sources":["../src/stores.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAIL,KAAK,iBAAiB,EAGvB,MAAM,oBAAoB,CAAC;AAE5B,KAAK,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC,CAAC;AAEpE;2BAC2B;AAC3B,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,2EAA2E;AAC3E,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D;AA4BD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,GAAe,EACf,OAAO,EACP,KAAW,GACZ,GAAE;IACD;qEACiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,OAAO,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;CACX,GAAG,iBAAiB,CAkJzB;AAED,MAAM,MAAM,4BAA4B,GAAG;IACzC,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,oCAAoC;IACpC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,OAAO,EACP,OAAO,EACP,KAAK,EAAE,SAAS,EAChB,iBAAyB,GAC1B,EAAE,4BAA4B,GAAG,iBAAiB,CA0ElD"}