@frankieai/react 0.1.4 → 0.1.5
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.
- package/dist/frankie.css +1 -1
- package/dist/index.cjs +86 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +87 -18
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/chat/FrankieChatPage.tsx +75 -7
- package/src/hooks/useFrankieChat.ts +33 -15
- package/src/styles/frankie.css +161 -0
package/dist/index.js
CHANGED
|
@@ -354,6 +354,7 @@ function useFrankieChat() {
|
|
|
354
354
|
const [restored, setRestored] = useState2(false);
|
|
355
355
|
const abortRef = useRef(null);
|
|
356
356
|
const mounted = useRef(true);
|
|
357
|
+
const messagesRef = useRef([]);
|
|
357
358
|
useEffect2(() => {
|
|
358
359
|
mounted.current = true;
|
|
359
360
|
return () => {
|
|
@@ -369,13 +370,20 @@ function useFrankieChat() {
|
|
|
369
370
|
try {
|
|
370
371
|
const raw = window.localStorage.getItem(storageKey);
|
|
371
372
|
const stored = raw ? JSON.parse(raw) : [];
|
|
372
|
-
if (Array.isArray(stored) && stored.length && active)
|
|
373
|
+
if (Array.isArray(stored) && stored.length && active) {
|
|
374
|
+
messagesRef.current = stored;
|
|
375
|
+
setMessages(stored);
|
|
376
|
+
}
|
|
373
377
|
} catch {
|
|
374
378
|
}
|
|
375
379
|
}
|
|
376
380
|
try {
|
|
377
381
|
const remote = await client.resumeConversation();
|
|
378
|
-
if (active && remote?.messages.length)
|
|
382
|
+
if (active && remote?.messages.length) {
|
|
383
|
+
const restoredMessages = remote.messages;
|
|
384
|
+
messagesRef.current = restoredMessages;
|
|
385
|
+
setMessages(restoredMessages);
|
|
386
|
+
}
|
|
379
387
|
} catch {
|
|
380
388
|
} finally {
|
|
381
389
|
if (active) setRestored(true);
|
|
@@ -396,11 +404,11 @@ function useFrankieChat() {
|
|
|
396
404
|
if (messages.length) void client.syncConversation(messages, conversationTitle(messages)).catch(() => void 0);
|
|
397
405
|
}, [messages, busy, client, storageKey, restored]);
|
|
398
406
|
const patchAssistant = useCallback((id, update) => {
|
|
399
|
-
|
|
400
|
-
(
|
|
401
|
-
(message) => message.id === id && message.role === "assistant" ? update(message) : message
|
|
402
|
-
)
|
|
407
|
+
const next = messagesRef.current.map(
|
|
408
|
+
(message) => message.id === id && message.role === "assistant" ? update(message) : message
|
|
403
409
|
);
|
|
410
|
+
messagesRef.current = next;
|
|
411
|
+
setMessages(next);
|
|
404
412
|
}, []);
|
|
405
413
|
const send = useCallback(
|
|
406
414
|
async (text, opts) => {
|
|
@@ -411,15 +419,17 @@ function useFrankieChat() {
|
|
|
411
419
|
const assistantId = nextId("a");
|
|
412
420
|
setError(void 0);
|
|
413
421
|
setBusy(true);
|
|
414
|
-
|
|
415
|
-
...current,
|
|
422
|
+
const next = [
|
|
423
|
+
...messagesRef.current,
|
|
416
424
|
newUserMessage(
|
|
417
425
|
nextId("u"),
|
|
418
426
|
trimmed,
|
|
419
427
|
attachments.map((file) => ({ name: file.name, mimeType: file.mimeType }))
|
|
420
428
|
),
|
|
421
429
|
newAssistantMessage(assistantId)
|
|
422
|
-
]
|
|
430
|
+
];
|
|
431
|
+
messagesRef.current = next;
|
|
432
|
+
setMessages(next);
|
|
423
433
|
const abort = new AbortController();
|
|
424
434
|
abortRef.current = abort;
|
|
425
435
|
try {
|
|
@@ -460,13 +470,15 @@ function useFrankieChat() {
|
|
|
460
470
|
patchAssistant(assistantId, (current) => ({ ...current, status: "error", error: message }));
|
|
461
471
|
}
|
|
462
472
|
} finally {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
473
|
+
patchAssistant(
|
|
474
|
+
assistantId,
|
|
475
|
+
(message) => message.status === "streaming" ? { ...message, status: "done" } : message
|
|
476
|
+
);
|
|
477
|
+
const transcript = messagesRef.current;
|
|
478
|
+
if (transcript.length) {
|
|
479
|
+
await client.syncConversation(transcript, conversationTitle(transcript)).catch(() => void 0);
|
|
469
480
|
}
|
|
481
|
+
if (mounted.current) setBusy(false);
|
|
470
482
|
abortRef.current = null;
|
|
471
483
|
}
|
|
472
484
|
},
|
|
@@ -476,6 +488,7 @@ function useFrankieChat() {
|
|
|
476
488
|
const reset = useCallback(() => {
|
|
477
489
|
abortRef.current?.abort();
|
|
478
490
|
client.resetSession();
|
|
491
|
+
messagesRef.current = [];
|
|
479
492
|
setMessages([]);
|
|
480
493
|
setError(void 0);
|
|
481
494
|
setBusy(false);
|
|
@@ -1244,7 +1257,63 @@ function FrankieInline({ className, style, ...panelProps }) {
|
|
|
1244
1257
|
}
|
|
1245
1258
|
|
|
1246
1259
|
// src/components/chat/FrankieChatPage.tsx
|
|
1247
|
-
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
1260
|
+
import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1261
|
+
function PageEmptyState() {
|
|
1262
|
+
const { config } = useFrankie();
|
|
1263
|
+
const { send, busy } = useFrankieChat();
|
|
1264
|
+
const name = config?.branding.name ?? "Frankie";
|
|
1265
|
+
const prompts = config?.suggestedPrompts?.slice(0, 3) ?? [];
|
|
1266
|
+
return /* @__PURE__ */ jsxs6("section", { className: "frankie-page-empty", "aria-label": "Start a conversation", children: [
|
|
1267
|
+
/* @__PURE__ */ jsx16("span", { className: "frankie-page-avatar", "aria-hidden": true, children: name.trim().slice(0, 1).toUpperCase() }),
|
|
1268
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
1269
|
+
/* @__PURE__ */ jsxs6("p", { className: "frankie-page-kicker", children: [
|
|
1270
|
+
name,
|
|
1271
|
+
" assistant"
|
|
1272
|
+
] }),
|
|
1273
|
+
/* @__PURE__ */ jsx16("h1", { children: "What would you like to do?" }),
|
|
1274
|
+
/* @__PURE__ */ jsx16("p", { children: config?.greeting ?? "Ask a question or choose a task to get started." })
|
|
1275
|
+
] }),
|
|
1276
|
+
prompts.length ? /* @__PURE__ */ jsx16("div", { className: "frankie-page-prompts", children: prompts.map((prompt, index) => /* @__PURE__ */ jsxs6("button", { type: "button", disabled: busy, onClick: () => send(prompt), children: [
|
|
1277
|
+
/* @__PURE__ */ jsx16("span", { children: String(index + 1).padStart(2, "0") }),
|
|
1278
|
+
/* @__PURE__ */ jsx16("strong", { children: prompt }),
|
|
1279
|
+
/* @__PURE__ */ jsx16("b", { "aria-hidden": true, children: "\u2197" })
|
|
1280
|
+
] }, prompt)) }) : null
|
|
1281
|
+
] });
|
|
1282
|
+
}
|
|
1283
|
+
function PageChrome({
|
|
1284
|
+
header,
|
|
1285
|
+
footer,
|
|
1286
|
+
emptyState,
|
|
1287
|
+
renderMessage,
|
|
1288
|
+
renderTool,
|
|
1289
|
+
placeholder,
|
|
1290
|
+
autoFocus
|
|
1291
|
+
}) {
|
|
1292
|
+
const { config } = useFrankie();
|
|
1293
|
+
const { reset } = useFrankieChat();
|
|
1294
|
+
const name = config?.branding.name ?? "Frankie";
|
|
1295
|
+
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
1296
|
+
/* @__PURE__ */ jsxs6("header", { className: "frankie-page-header", children: [
|
|
1297
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
1298
|
+
/* @__PURE__ */ jsx16("span", { className: "frankie-page-status", "aria-hidden": true }),
|
|
1299
|
+
/* @__PURE__ */ jsx16("strong", { children: name })
|
|
1300
|
+
] }),
|
|
1301
|
+
/* @__PURE__ */ jsx16("button", { type: "button", onClick: reset, "aria-label": "Start a new conversation", children: "New chat" })
|
|
1302
|
+
] }),
|
|
1303
|
+
/* @__PURE__ */ jsx16("div", { className: "frankie-page-canvas", children: /* @__PURE__ */ jsx16(
|
|
1304
|
+
FrankieInline,
|
|
1305
|
+
{
|
|
1306
|
+
header: header ?? false,
|
|
1307
|
+
footer,
|
|
1308
|
+
emptyState: emptyState ?? /* @__PURE__ */ jsx16(PageEmptyState, {}),
|
|
1309
|
+
renderMessage,
|
|
1310
|
+
renderTool,
|
|
1311
|
+
placeholder,
|
|
1312
|
+
autoFocus
|
|
1313
|
+
}
|
|
1314
|
+
) })
|
|
1315
|
+
] });
|
|
1316
|
+
}
|
|
1248
1317
|
function FrankieChatPage({
|
|
1249
1318
|
className,
|
|
1250
1319
|
style,
|
|
@@ -1260,10 +1329,10 @@ function FrankieChatPage({
|
|
|
1260
1329
|
return /* @__PURE__ */ jsx16(
|
|
1261
1330
|
"main",
|
|
1262
1331
|
{
|
|
1263
|
-
className,
|
|
1332
|
+
className: ["frankie-root", "frankie-chat-page", className].filter(Boolean).join(" "),
|
|
1264
1333
|
style: { height: "100dvh", minHeight: "100dvh", width: "100%", ...style },
|
|
1265
1334
|
children: /* @__PURE__ */ jsx16(FrankieProvider, { ...providerProps, children: /* @__PURE__ */ jsx16(
|
|
1266
|
-
|
|
1335
|
+
PageChrome,
|
|
1267
1336
|
{
|
|
1268
1337
|
header,
|
|
1269
1338
|
footer,
|