@frankieai/react 0.2.9 → 0.2.10
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 +231 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -3
- package/dist/index.d.ts +55 -3
- package/dist/index.js +231 -25
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/chat/Composer.tsx +21 -16
- package/src/components/chat/FrankieChatPage.tsx +1 -1
- package/src/components/chat/FrankieInline.tsx +3 -2
- package/src/components/chat/FrankieWidget.tsx +2 -2
- package/src/components/chat/MessageBubble.tsx +24 -5
- package/src/components/chat/ToolActivityList.tsx +2 -1
- package/src/generated/css-content.ts +2 -0
- package/src/hooks/FrankieProvider.tsx +30 -3
- package/src/index.ts +1 -1
- package/src/lib/client.ts +136 -5
- package/src/lib/ensure-frankie-styles.ts +32 -0
- package/src/lib/identity.ts +39 -0
- package/src/lib/styles-ready.ts +19 -7
- package/src/lib/theme-inherit.test.ts +68 -0
- package/src/lib/theme-inherit.ts +89 -0
- package/src/styles/frankie.css +30 -0
- package/src/styles-ready.test.tsx +30 -3
- package/src/widget.test.tsx +218 -0
package/dist/index.cjs
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
Separator: () => Separator,
|
|
47
47
|
SuggestedPrompts: () => SuggestedPrompts,
|
|
48
48
|
Textarea: () => Textarea,
|
|
49
|
+
Thinking: () => Thinking,
|
|
49
50
|
ToolActivityList: () => ToolActivityList,
|
|
50
51
|
ToolActivityRow: () => ToolActivityRow,
|
|
51
52
|
TypingDots: () => TypingDots,
|
|
@@ -67,6 +68,31 @@ module.exports = __toCommonJS(index_exports);
|
|
|
67
68
|
// src/hooks/FrankieProvider.tsx
|
|
68
69
|
var import_react2 = require("react");
|
|
69
70
|
|
|
71
|
+
// src/lib/identity.ts
|
|
72
|
+
function sessionIdentity(token) {
|
|
73
|
+
if (!token) return void 0;
|
|
74
|
+
return jwtSubject(token) ?? token;
|
|
75
|
+
}
|
|
76
|
+
function jwtSubject(token) {
|
|
77
|
+
const parts = token.split(".");
|
|
78
|
+
if (parts.length !== 3 || !parts[1]) return void 0;
|
|
79
|
+
try {
|
|
80
|
+
const payload = JSON.parse(base64UrlDecode(parts[1]));
|
|
81
|
+
return typeof payload.sub === "string" && payload.sub ? payload.sub : void 0;
|
|
82
|
+
} catch {
|
|
83
|
+
return void 0;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function base64UrlDecode(segment) {
|
|
87
|
+
const base64 = segment.replace(/-/g, "+").replace(/_/g, "/");
|
|
88
|
+
const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
|
|
89
|
+
if (typeof atob === "function") {
|
|
90
|
+
const bytes = atob(padded);
|
|
91
|
+
return decodeURIComponent(Array.from(bytes, (c) => "%" + c.charCodeAt(0).toString(16).padStart(2, "0")).join(""));
|
|
92
|
+
}
|
|
93
|
+
return Buffer.from(padded, "base64").toString("utf8");
|
|
94
|
+
}
|
|
95
|
+
|
|
70
96
|
// src/lib/client.ts
|
|
71
97
|
var FRANKIE_CLOUD_URL = "https://frankie-control-665333762719.us-central1.run.app";
|
|
72
98
|
var FrankieApiError = class extends Error {
|
|
@@ -95,7 +121,8 @@ var FrankieClient = class {
|
|
|
95
121
|
baseUrl;
|
|
96
122
|
doFetch;
|
|
97
123
|
session;
|
|
98
|
-
|
|
124
|
+
/** Identity (JWT `sub`, else the raw token) the cached session was issued for. */
|
|
125
|
+
sessionUserKey;
|
|
99
126
|
get sessionId() {
|
|
100
127
|
return this.session?.sessionId;
|
|
101
128
|
}
|
|
@@ -137,7 +164,18 @@ var FrankieClient = class {
|
|
|
137
164
|
return await this.unwrap(response);
|
|
138
165
|
}
|
|
139
166
|
async ensureSession(context) {
|
|
140
|
-
|
|
167
|
+
let userToken;
|
|
168
|
+
try {
|
|
169
|
+
userToken = await this.options.getUserToken?.();
|
|
170
|
+
} catch (error) {
|
|
171
|
+
this.resetSession();
|
|
172
|
+
const reason = error instanceof Error && error.message.trim() ? error.message.trim() : void 0;
|
|
173
|
+
throw new FrankieApiError(
|
|
174
|
+
reason ?? "Your signed-in Frankie session could not be verified. Refresh the page and sign in again.",
|
|
175
|
+
401,
|
|
176
|
+
"user_token_unavailable"
|
|
177
|
+
);
|
|
178
|
+
}
|
|
141
179
|
if (this.options.getUserToken && !userToken) {
|
|
142
180
|
this.resetSession();
|
|
143
181
|
throw new FrankieApiError(
|
|
@@ -146,7 +184,8 @@ var FrankieClient = class {
|
|
|
146
184
|
"user_token_unavailable"
|
|
147
185
|
);
|
|
148
186
|
}
|
|
149
|
-
|
|
187
|
+
const userKey = sessionIdentity(userToken);
|
|
188
|
+
if (userKey !== this.sessionUserKey) this.resetSession();
|
|
150
189
|
if (this.session && new Date(this.session.expiresAt).getTime() > Date.now() + 3e4) return this.session;
|
|
151
190
|
const response = await this.doFetch(`${this.baseUrl}/v1/session`, {
|
|
152
191
|
method: "POST",
|
|
@@ -158,7 +197,7 @@ var FrankieClient = class {
|
|
|
158
197
|
})
|
|
159
198
|
});
|
|
160
199
|
this.session = await this.unwrap(response);
|
|
161
|
-
this.
|
|
200
|
+
this.sessionUserKey = userKey;
|
|
162
201
|
this.writeStored();
|
|
163
202
|
return this.session;
|
|
164
203
|
}
|
|
@@ -180,7 +219,7 @@ var FrankieClient = class {
|
|
|
180
219
|
if (response.status === 404) return void 0;
|
|
181
220
|
const body = await this.unwrap(response);
|
|
182
221
|
this.session = body.session;
|
|
183
|
-
this.
|
|
222
|
+
this.sessionUserKey = sessionIdentity(userToken);
|
|
184
223
|
this.writeStored();
|
|
185
224
|
return { messages: Array.isArray(body.messages) ? body.messages : [], title: body.title ?? "New chat" };
|
|
186
225
|
}
|
|
@@ -239,9 +278,59 @@ var FrankieClient = class {
|
|
|
239
278
|
return;
|
|
240
279
|
}
|
|
241
280
|
for await (const event of readEventStream(response.body)) {
|
|
281
|
+
if (event.type === "tool_call_request") {
|
|
282
|
+
void this.runClientTool(session, event.callId, event.request);
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
242
285
|
onEvent(event);
|
|
243
286
|
}
|
|
244
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* Execute one host API call in the browser and report the outcome back to the
|
|
290
|
+
* server. Never throws: a transport failure or a missing `api` client becomes
|
|
291
|
+
* a result the model can see and explain, exactly like a non-2xx status.
|
|
292
|
+
*/
|
|
293
|
+
async runClientTool(session, callId, request) {
|
|
294
|
+
const result = await this.callHostApi(request);
|
|
295
|
+
await this.postToolResult(session, callId, result).catch(() => void 0);
|
|
296
|
+
}
|
|
297
|
+
async callHostApi(request) {
|
|
298
|
+
const api = this.options.api;
|
|
299
|
+
if (!api) {
|
|
300
|
+
return {
|
|
301
|
+
status: 0,
|
|
302
|
+
error: "This assistant tried to call your API from the browser, but no host API client is configured in the Frankie SDK (the `api` option)."
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
const extra = api.headers ? await api.headers() : {};
|
|
307
|
+
const response = await this.doFetch(joinHostUrl(api.baseUrl, request.path), {
|
|
308
|
+
method: request.method,
|
|
309
|
+
credentials: api.credentials ?? "same-origin",
|
|
310
|
+
headers: {
|
|
311
|
+
accept: "application/json, text/plain;q=0.9, */*;q=0.8",
|
|
312
|
+
...request.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
313
|
+
...extra
|
|
314
|
+
},
|
|
315
|
+
...request.body !== void 0 ? { body: JSON.stringify(request.body) } : {}
|
|
316
|
+
});
|
|
317
|
+
const body = await response.text().catch(() => "");
|
|
318
|
+
return { status: response.status, body };
|
|
319
|
+
} catch (error) {
|
|
320
|
+
return { status: 0, error: error instanceof Error ? error.message : String(error) };
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
async postToolResult(session, callId, result) {
|
|
324
|
+
await this.doFetch(`${this.baseUrl}/v1/chat/tool-result`, {
|
|
325
|
+
method: "POST",
|
|
326
|
+
headers: {
|
|
327
|
+
"content-type": "application/json",
|
|
328
|
+
"x-frankie-key": this.options.publishableKey,
|
|
329
|
+
authorization: `Bearer ${session.sessionToken}`
|
|
330
|
+
},
|
|
331
|
+
body: JSON.stringify({ callId, result })
|
|
332
|
+
});
|
|
333
|
+
}
|
|
245
334
|
async unwrap(response) {
|
|
246
335
|
if (response.ok) return response.json();
|
|
247
336
|
let code = "internal";
|
|
@@ -255,6 +344,12 @@ var FrankieClient = class {
|
|
|
255
344
|
throw new FrankieApiError(message, response.status, code);
|
|
256
345
|
}
|
|
257
346
|
};
|
|
347
|
+
function joinHostUrl(baseUrl, path) {
|
|
348
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(path) || path.startsWith("//")) {
|
|
349
|
+
throw new Error("A client tool path must be relative to the configured host API base URL.");
|
|
350
|
+
}
|
|
351
|
+
return `${baseUrl.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
|
|
352
|
+
}
|
|
258
353
|
async function* readEventStream(body) {
|
|
259
354
|
const reader = body.getReader();
|
|
260
355
|
const decoder = new TextDecoder();
|
|
@@ -287,6 +382,68 @@ function parseFrame(frame) {
|
|
|
287
382
|
}
|
|
288
383
|
}
|
|
289
384
|
|
|
385
|
+
// src/lib/theme-inherit.ts
|
|
386
|
+
function parseRgb(value) {
|
|
387
|
+
const match = value.match(/rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)(?:\s*[,/]\s*([\d.]+%?))?\s*\)/i);
|
|
388
|
+
if (!match) return null;
|
|
389
|
+
const alpha = match[4] === void 0 ? 1 : match[4].endsWith("%") ? Number(match[4].slice(0, -1)) / 100 : Number(match[4]);
|
|
390
|
+
return [Number(match[1]), Number(match[2]), Number(match[3]), alpha];
|
|
391
|
+
}
|
|
392
|
+
function toCss([r, g, b, a]) {
|
|
393
|
+
return a >= 1 ? `rgb(${r}, ${g}, ${b})` : `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
394
|
+
}
|
|
395
|
+
function sameColor(a, b) {
|
|
396
|
+
return Math.abs(a[0] - b[0]) < 12 && Math.abs(a[1] - b[1]) < 12 && Math.abs(a[2] - b[2]) < 12;
|
|
397
|
+
}
|
|
398
|
+
function luminance([r, g, b]) {
|
|
399
|
+
const channel = (c) => {
|
|
400
|
+
const v = c / 255;
|
|
401
|
+
return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
|
|
402
|
+
};
|
|
403
|
+
return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);
|
|
404
|
+
}
|
|
405
|
+
function contrastRatio(a, b) {
|
|
406
|
+
const la = luminance(a), lb = luminance(b);
|
|
407
|
+
return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
|
|
408
|
+
}
|
|
409
|
+
var ACCENT_SELECTORS = ["[data-frankie-accent]", "button[type=submit]", "a[href]", "button", "[class*=primary]", "[class*=btn]"];
|
|
410
|
+
function inferHostTheme() {
|
|
411
|
+
if (typeof document === "undefined" || typeof getComputedStyle !== "function") return null;
|
|
412
|
+
try {
|
|
413
|
+
const bodyStyle = getComputedStyle(document.body);
|
|
414
|
+
const background = parseRgb(bodyStyle.backgroundColor);
|
|
415
|
+
const foreground = parseRgb(bodyStyle.color);
|
|
416
|
+
if (!background || !foreground) return null;
|
|
417
|
+
if (background[3] < 0.5) return null;
|
|
418
|
+
if (contrastRatio(background, foreground) < 2) return null;
|
|
419
|
+
let accent = null;
|
|
420
|
+
for (const selector of ACCENT_SELECTORS) {
|
|
421
|
+
const element = document.querySelector(selector);
|
|
422
|
+
if (!element) continue;
|
|
423
|
+
const style = getComputedStyle(element);
|
|
424
|
+
const surface = parseRgb(style.backgroundColor);
|
|
425
|
+
if (surface && surface[3] > 0.5 && !sameColor(surface, background)) {
|
|
426
|
+
accent = surface;
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
const text = parseRgb(style.color);
|
|
430
|
+
if (text && text[3] > 0.5 && !sameColor(text, foreground)) {
|
|
431
|
+
accent = text;
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
if (!accent) return null;
|
|
436
|
+
return {
|
|
437
|
+
background: toCss(background),
|
|
438
|
+
foreground: toCss(foreground),
|
|
439
|
+
primary: toCss(accent),
|
|
440
|
+
primaryForeground: luminance(accent) > 0.5 ? "#0a0a0a" : "#fafafa"
|
|
441
|
+
};
|
|
442
|
+
} catch {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
290
447
|
// src/hooks/useFrankieChat.ts
|
|
291
448
|
var import_react = require("react");
|
|
292
449
|
|
|
@@ -607,6 +764,7 @@ function FrankieProvider({
|
|
|
607
764
|
context,
|
|
608
765
|
theme,
|
|
609
766
|
config: providedConfig,
|
|
767
|
+
injectStyles = true,
|
|
610
768
|
...clientOptions
|
|
611
769
|
}) {
|
|
612
770
|
const tokenCallback = (0, import_react2.useRef)(clientOptions.getUserToken);
|
|
@@ -614,7 +772,7 @@ function FrankieProvider({
|
|
|
614
772
|
const client = (0, import_react2.useMemo)(
|
|
615
773
|
() => new FrankieClient({ ...clientOptions, ...clientOptions.getUserToken ? { getUserToken: () => tokenCallback.current?.() } : {} }),
|
|
616
774
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
617
|
-
[clientOptions.baseUrl, clientOptions.publishableKey, clientOptions.storageNamespace, clientOptions.conversationId, clientOptions.persist, clientOptions.fetchImpl, Boolean(clientOptions.getUserToken)]
|
|
775
|
+
[clientOptions.baseUrl, clientOptions.publishableKey, clientOptions.storageNamespace, clientOptions.conversationId, clientOptions.persist, clientOptions.fetchImpl, clientOptions.api?.baseUrl, clientOptions.api?.credentials, Boolean(clientOptions.getUserToken)]
|
|
618
776
|
);
|
|
619
777
|
const [config, setConfig] = (0, import_react2.useState)(providedConfig);
|
|
620
778
|
const [configError, setConfigError] = (0, import_react2.useState)(void 0);
|
|
@@ -641,9 +799,10 @@ function FrankieProvider({
|
|
|
641
799
|
...configError ? { configError } : {},
|
|
642
800
|
loading,
|
|
643
801
|
...context ? { context } : {},
|
|
644
|
-
...theme ? { theme } : {}
|
|
802
|
+
...theme ? { theme } : {},
|
|
803
|
+
injectStyles
|
|
645
804
|
}),
|
|
646
|
-
[client, config, configError, loading, context, theme]
|
|
805
|
+
[client, config, configError, loading, context, theme, injectStyles]
|
|
647
806
|
);
|
|
648
807
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FrankieContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConversationState, { children }, client.namespace + ":" + (client.conversationId ?? "")) });
|
|
649
808
|
}
|
|
@@ -658,7 +817,16 @@ function useFrankie() {
|
|
|
658
817
|
}
|
|
659
818
|
function useFrankieTheme() {
|
|
660
819
|
const { config, theme } = useFrankie();
|
|
661
|
-
|
|
820
|
+
const merged = (0, import_react2.useMemo)(() => ({ ...config?.theme, ...theme }), [config?.theme, theme]);
|
|
821
|
+
const inheriting = merged?.source === "inherit";
|
|
822
|
+
const [inferred, setInferred] = (0, import_react2.useState)(null);
|
|
823
|
+
(0, import_react2.useEffect)(() => {
|
|
824
|
+
setInferred(inheriting ? inferHostTheme() : null);
|
|
825
|
+
}, [inheriting]);
|
|
826
|
+
return (0, import_react2.useMemo)(() => {
|
|
827
|
+
if (!inheriting || !inferred) return merged;
|
|
828
|
+
return { ...merged, ...inferred };
|
|
829
|
+
}, [merged, inheriting, inferred]);
|
|
662
830
|
}
|
|
663
831
|
|
|
664
832
|
// src/components/chat/FrankieWidget.tsx
|
|
@@ -667,9 +835,28 @@ var import_react10 = require("react");
|
|
|
667
835
|
|
|
668
836
|
// src/lib/styles-ready.ts
|
|
669
837
|
var import_react3 = require("react");
|
|
838
|
+
|
|
839
|
+
// src/generated/css-content.ts
|
|
840
|
+
var FRANKIE_CSS_CONTENT = `/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
841
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-ease:initial}}}@layer theme{:root,:host{--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-600:oklch(59.6% .145 163.225);--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-medium:500;--font-weight-semibold:600;--leading-tight:1.25;--radius-md:.375rem;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}}@layer components{.frankie-page-shell{background:var(--frankie-background);height:100%;min-height:0;color:var(--frankie-foreground);flex:1;display:flex}.frankie-page-main{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.frankie-history-desktop{border-right:1px solid var(--frankie-border);background:var(--frankie-secondary);flex-direction:column;flex-shrink:0;gap:16px;width:260px;padding:20px 14px;transition:width .16s,padding .16s;display:flex;overflow:auto}.frankie-history-toggle{border:1px solid var(--frankie-border);background:var(--frankie-background);width:32px;height:32px;color:var(--frankie-muted-foreground);cursor:pointer;border-radius:8px;flex-shrink:0;justify-content:center;align-self:flex-end;align-items:center;display:flex}.frankie-history-toggle:hover{color:var(--frankie-foreground)}.frankie-history-collapsed{width:56px;padding:20px 8px;overflow:visible}.frankie-history-collapsed .frankie-history-toggle{align-self:center}.frankie-history-heading{justify-content:space-between;align-items:center;font-size:14px;display:flex}.frankie-new-chat{border:1px solid var(--frankie-border);background:var(--frankie-background);cursor:pointer;border-radius:10px;justify-content:center;align-items:center;gap:8px;min-height:44px;font-weight:600;display:flex}.frankie-history-search>span{color:var(--frankie-muted-foreground);margin-bottom:6px;font-size:12px;display:block}.frankie-history-search input{border:1px solid var(--frankie-border);background:var(--frankie-background);border-radius:8px;width:100%;min-height:40px;padding:8px 10px}.frankie-history-list{flex-direction:column;flex:1;gap:4px;display:flex}.frankie-history-list button{text-align:left;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:8px;flex-direction:column;align-items:flex-start;gap:5px;min-height:54px;padding:10px;display:flex}.frankie-history-list button span{text-overflow:ellipsis;white-space:nowrap;width:100%;font-size:13px;overflow:hidden}.frankie-history-list small{color:var(--frankie-muted-foreground);font-size:11px}.frankie-history-list button:hover,.frankie-history-list button[aria-current]{background:var(--frankie-background);border-color:var(--frankie-border)}.frankie-history-desktop>p,.frankie-history-dialog p{color:var(--frankie-muted-foreground);font-size:13px}.frankie-header-caption{color:var(--frankie-muted-foreground);font-size:12px}.frankie-page-header button{cursor:pointer;justify-content:center;align-items:center;gap:6px;min-width:40px;min-height:40px;display:inline-flex}.frankie-chat-settings{position:relative}.frankie-chat-settings summary{cursor:pointer;border-radius:8px;place-items:center;width:40px;height:40px;list-style:none;display:grid}.frankie-chat-settings summary::-webkit-details-marker{display:none}.frankie-chat-settings>div{z-index:5;border:1px solid var(--frankie-border);background:var(--frankie-background);border-radius:12px;gap:12px;width:min(280px,80vw);padding:16px;font-size:13px;display:grid;position:absolute;top:46px;right:0;box-shadow:0 10px 30px #0002}.frankie-chat-settings p{color:var(--frankie-muted-foreground);margin:0}.frankie-loaded-skills{width:100%;max-width:760px;color:var(--frankie-muted-foreground);font-size:12px}.frankie-loaded-skills summary{cursor:pointer;padding:6px 0}.frankie-loaded-skills ul{margin:0;padding:4px 0;list-style:none}.frankie-loaded-skills li{gap:8px;padding:4px 0;display:flex}.frankie-loaded-skills small{opacity:.7}.frankie-history-dialog{background:var(--frankie-secondary);width:min(320px,86vw);max-width:none;height:100dvh;max-height:none;color:var(--frankie-foreground);border:0;margin:0;padding:0}.frankie-history-dialog::backdrop{background:#0008}.frankie-history-dialog>aside{height:100%;padding:calc(20px + env(safe-area-inset-top)) 16px calc(20px + env(safe-area-inset-bottom));flex-direction:column;gap:16px;display:flex;overflow:auto}.frankie-mobile-only{display:none!important}.frankie-widget-panel{max-height:calc(100dvh - 100px)}.frankie-root button:focus-visible,.frankie-root summary:focus-visible,.frankie-root input:focus-visible{outline:2px solid var(--frankie-primary);outline-offset:3px}.frankie-root button:disabled{opacity:.5;cursor:not-allowed}@media (max-width:760px){.frankie-history-desktop{display:none}.frankie-mobile-only{display:inline-flex!important}.frankie-header-caption{display:none}.frankie-page-header{padding:6px 10px}.frankie-history-heading button{background:0 0;border:0;justify-content:center;align-items:center;min-width:44px;min-height:44px}.frankie-page-prompts{gap:8px}.frankie-widget-panel{width:calc(100vw - 32px)}}.frankie-root{--frankie-styles-ready:1;--frankie-background:#fff;--frankie-foreground:#0a0a0a;--frankie-primary:#171717;--frankie-primary-foreground:#fafafa;--frankie-secondary:#f5f5f5;--frankie-secondary-foreground:#171717;--frankie-muted:#f5f5f5;--frankie-muted-foreground:#737373;--frankie-border:#e5e5e5;--frankie-radius:.625rem;--frankie-font:ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;font-family:var(--frankie-font);color:var(--frankie-foreground);-webkit-font-smoothing:antialiased;line-height:1.5}.frankie-root.dark{--frankie-background:#0a0a0a;--frankie-foreground:#fafafa;--frankie-primary:#fafafa;--frankie-primary-foreground:#171717;--frankie-secondary:#262626;--frankie-secondary-foreground:#fafafa;--frankie-muted:#262626;--frankie-muted-foreground:#a3a3a3;--frankie-border:#262626}.frankie-root,.frankie-root *,.frankie-root :before,.frankie-root :after{box-sizing:border-box}.frankie-root button,.frankie-root textarea,.frankie-root input{font:inherit;color:inherit;margin:0}.frankie-root textarea{background-color:var(--frankie-background)}.frankie-focus:focus-visible{outline:2px solid var(--frankie-primary);outline-offset:2px}.frankie-scroll{scrollbar-width:thin;scrollbar-color:var(--frankie-border) transparent}.frankie-prose>*+*{margin-top:.6rem}.frankie-prose p{white-space:pre-wrap;overflow-wrap:anywhere;margin:0;line-height:1.6}.frankie-prose>.frankie-h{letter-spacing:-.01em;margin-top:1.15rem;line-height:1.3}.frankie-prose>.frankie-h:first-child{margin-top:0}.frankie-prose h3.frankie-h{font-size:1.06em;font-weight:700}.frankie-prose h4.frankie-h{font-size:1em;font-weight:600}.frankie-prose h5.frankie-h{color:var(--frankie-muted-foreground);font-size:.92em;font-weight:600}.frankie-prose strong{font-weight:600}.frankie-prose ul,.frankie-prose ol{flex-direction:column;gap:.35rem;margin:0;padding-left:1.4rem;display:flex}.frankie-prose li{padding-left:.15rem;line-height:1.55}.frankie-prose li::marker{color:var(--frankie-muted-foreground)}.frankie-prose ul{list-style:outside}.frankie-prose ol{list-style:decimal}.frankie-prose a{color:var(--frankie-primary);text-underline-offset:2px;text-decoration:underline}.frankie-prose code{background-color:var(--frankie-muted);border-radius:.25rem;padding:.1em .3em;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:.85em}.frankie-prose pre{border-radius:var(--frankie-radius);background-color:var(--frankie-muted);margin:0;padding:.625rem .75rem;overflow-x:auto}.frankie-prose pre code{background:0 0;padding:0}.frankie-chat-page{background:radial-gradient(60rem 24rem at 50% -12rem, var(--frankie-primary), transparent 65%), var(--frankie-background);flex-direction:column;min-width:0;display:flex;overflow:hidden}@supports (color:color-mix(in lab, red, red)){.frankie-chat-page{background:radial-gradient(60rem 24rem at 50% -12rem, color-mix(in srgb, var(--frankie-primary) 8%, transparent), transparent 65%), var(--frankie-background)}}.frankie-chat-page{color:var(--frankie-foreground)}.frankie-page-header{border-bottom:1px solid var(--frankie-border);background:var(--frankie-background);flex:0 0 56px;justify-content:space-between;align-items:center;gap:16px;min-height:56px;padding:0 24px;display:flex}@supports (color:color-mix(in lab, red, red)){.frankie-page-header{background:color-mix(in srgb, var(--frankie-background) 92%, transparent)}}.frankie-page-header{-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.frankie-page-header>div{align-items:center;gap:10px;display:flex}.frankie-page-header strong{font-size:.925rem;font-weight:650}.frankie-page-status{background:var(--frankie-primary);width:10px;height:10px;box-shadow:0 0 0 4px var(--frankie-primary);border-radius:999px}@supports (color:color-mix(in lab, red, red)){.frankie-page-status{box-shadow:0 0 0 4px color-mix(in srgb, var(--frankie-primary) 16%, transparent)}}.frankie-page-header button{border:1px solid var(--frankie-border);border-radius:calc(var(--frankie-radius) * .9);background:var(--frankie-secondary);cursor:pointer;min-height:36px;padding:0 13px}.frankie-page-header button:hover{border-color:var(--frankie-primary)}.frankie-page-canvas{flex:1;min-width:0;min-height:0;display:flex}.frankie-page-canvas>.frankie-inline{width:100%;max-width:56rem;margin:0 auto}.frankie-page-canvas .frankie-scroll{padding:2rem clamp(1rem,4vw,4rem) 1.25rem}.frankie-page-canvas .frankie-root>.border-t{background:linear-gradient(180deg, transparent, var(--frankie-background) 30%);border-top:0;padding:.75rem clamp(1rem,4vw,4rem) 1.5rem}.frankie-page-empty{text-align:center;flex-direction:column;justify-content:center;align-items:center;gap:1rem;width:min(100%,38rem);min-height:100%;margin:auto;padding:clamp(2rem,7vh,4.5rem) 1rem 2rem;display:flex}.frankie-page-avatar{border-radius:calc(var(--frankie-radius) * 1.4);background:var(--frankie-primary);width:48px;height:48px;color:var(--frankie-primary-foreground);place-items:center;font-weight:750;display:grid}.frankie-page-kicker{color:var(--frankie-primary);letter-spacing:.1em;text-transform:uppercase;margin:0 0 .4rem;font-size:.7rem;font-weight:750}.frankie-page-empty h1{letter-spacing:-.045em;margin:0;font-size:clamp(1.65rem,4vw,2.15rem);line-height:1.08}.frankie-page-empty h1+p{max-width:30rem;color:var(--frankie-muted-foreground);margin:.6rem auto 0}.frankie-page-prompts{gap:.55rem;width:100%;margin-top:.4rem;display:grid}.frankie-page-prompts button{border:1px solid var(--frankie-border);border-radius:calc(var(--frankie-radius) * 1.25);background:var(--frankie-secondary);text-align:left;cursor:pointer;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:.65rem;min-height:60px;padding:.75rem .9rem;display:grid}.frankie-page-prompts button:hover{border-color:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-page-prompts button:hover{border-color:color-mix(in srgb, var(--frankie-primary) 58%, var(--frankie-border))}}.frankie-page-prompts button:hover{transform:translateY(-1px)}.frankie-page-prompts button>span{color:var(--frankie-muted-foreground);font-size:.68rem;font-weight:700}.frankie-page-prompts button>strong{font-size:.875rem}.frankie-page-prompts button>b{color:var(--frankie-primary);font-size:1rem}@media (max-width:640px){.frankie-page-header{flex-basis:52px;min-height:52px;padding:0 12px}.frankie-page-canvas .frankie-scroll{padding:1.25rem .75rem .5rem}.frankie-page-canvas .frankie-root>.border-t{padding:.65rem .75rem calc(.65rem + env(safe-area-inset-bottom))}}}@layer utilities;@scope(.frankie-root){.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.isolate{isolation:isolate}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mt-0{margin-top:0}.mt-0\\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.block{display:block}.contents{display:contents}.flex{display:flex}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.size-1{width:var(--spacing);height:var(--spacing)}.size-1\\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-3\\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.size-12{width:calc(var(--spacing) * 12);height:calc(var(--spacing) * 12)}.size-full{width:100%;height:100%}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-\\[32rem\\]{height:32rem}.h-full{height:100%}.h-px{height:1px}.min-h-7{min-height:calc(var(--spacing) * 7)}.min-h-\\[2\\.25rem\\]{min-height:2.25rem}.w-\\[22rem\\]{width:22rem}.w-full{width:100%}.max-w-\\[12rem\\]{max-width:12rem}.max-w-\\[14rem\\]{max-width:14rem}.max-w-\\[85\\%\\]{max-width:85%}.max-w-\\[calc\\(100vw-2rem\\)\\]{max-width:calc(100vw - 2rem)}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.list-none{list-style-type:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:var(--spacing)}.gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded{border-radius:.25rem}.rounded-\\[calc\\(var\\(--frankie-radius\\)\\+4px\\)\\]{border-radius:calc(var(--frankie-radius) + 4px)}.rounded-\\[calc\\(var\\(--frankie-radius\\)-2px\\)\\]{border-radius:calc(var(--frankie-radius) - 2px)}.rounded-\\[var\\(--frankie-radius\\)\\]{border-radius:var(--frankie-radius)}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.rounded-none{border-radius:0}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-border{border-color:var(--frankie-border)}.border-transparent{border-color:#0000}.bg-background{background-color:var(--frankie-background)}.bg-border{background-color:var(--frankie-border)}.bg-emerald-500{background-color:var(--color-emerald-500)}.bg-emerald-500\\/10{background-color:#00bb7f1a}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\\/10{background-color:color-mix(in oklab, var(--color-emerald-500) 10%, transparent)}}.bg-muted{background-color:var(--frankie-muted)}.bg-muted-foreground{background-color:var(--frankie-muted-foreground)}.bg-primary{background-color:var(--frankie-primary)}.bg-red-500{background-color:var(--color-red-500)}.bg-red-500\\/10{background-color:#fb2c361a}@supports (color:color-mix(in lab, red, red)){.bg-red-500\\/10{background-color:color-mix(in oklab, var(--color-red-500) 10%, transparent)}}.bg-secondary{background-color:var(--frankie-secondary)}.object-cover{object-fit:cover}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.px-1{padding-inline:var(--spacing)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0{padding-block:0}.py-0\\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.pl-2{padding-left:calc(var(--spacing) * 2)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\\[0\\.625rem\\]{font-size:.625rem}.text-\\[0\\.6875rem\\]{font-size:.6875rem}.text-\\[11px\\]{font-size:11px}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-nowrap{white-space:nowrap}.text-emerald-600{color:var(--color-emerald-600)}.text-foreground{color:var(--frankie-foreground)}.text-muted-foreground{color:var(--frankie-muted-foreground)}.text-primary{color:var(--frankie-primary)}.text-primary-foreground{color:var(--frankie-primary-foreground)}.text-red-600{color:var(--color-red-600)}.text-secondary-foreground{color:var(--frankie-secondary-foreground)}.underline-offset-4{text-underline-offset:4px}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.placeholder\\:text-muted-foreground::placeholder{color:var(--frankie-muted-foreground)}@media (hover:hover){.hover\\:border-border:hover{border-color:var(--frankie-border)}.hover\\:bg-muted:hover{background-color:var(--frankie-muted)}.hover\\:text-foreground:hover{color:var(--frankie-foreground)}.hover\\:underline:hover{text-decoration-line:underline}.hover\\:opacity-90:hover{opacity:.9}.hover\\:opacity-100:hover{opacity:1}}.focus-visible\\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\\:ring-primary:focus-visible{--tw-ring-color:var(--frankie-primary)}.focus-visible\\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\\:pointer-events-none:disabled{pointer-events:none}.disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\\:opacity-50:disabled{opacity:.5}.dark\\:text-emerald-400:where(.dark,.dark *){color:var(--color-emerald-400)}.dark\\:text-red-400:where(.dark,.dark *){color:var(--color-red-400)}.\\[\\&_svg\\]\\:pointer-events-none svg{pointer-events:none}.\\[\\&_svg\\]\\:size-4 svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\\[\\&_svg\\]\\:shrink-0 svg{flex-shrink:0}.\\[\\&\\:\\:-webkit-details-marker\\]\\:hidden::-webkit-details-marker{display:none}}.frankie-root.frankie-chat-panel{min-height:0;position:relative}.frankie-root.frankie-widget-panel{box-shadow:0 32px 72px -18px var(--frankie-primary), 0 12px 28px -12px #0f172a47, 0 0 0 1px var(--frankie-foreground)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-widget-panel{box-shadow:0 32px 72px -18px color-mix(in srgb, var(--frankie-primary) 22%, #0f172a6b), 0 12px 28px -12px #0f172a47, 0 0 0 1px color-mix(in srgb, var(--frankie-foreground) 8%, transparent)}}.frankie-root.frankie-widget-panel.dark{box-shadow:0 34px 80px -16px #000000b8, 0 14px 32px -12px #0009, 0 0 0 1px var(--frankie-foreground)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-widget-panel.dark{box-shadow:0 34px 80px -16px #000000b8, 0 14px 32px -12px #0009, 0 0 0 1px color-mix(in srgb, var(--frankie-foreground) 12%, transparent)}}.frankie-root .frankie-agent-context-wrap{flex:none;justify-content:center;padding:12px 10px;display:flex}.frankie-root .frankie-agent-context{max-width:100%;color:var(--frankie-foreground);font-size:13px;position:relative}.frankie-root .frankie-agent-context>summary{border:1px solid var(--frankie-border);background:var(--frankie-background);cursor:pointer;white-space:nowrap;border-radius:999px;justify-content:center;align-items:center;gap:10px;min-height:44px;padding:7px 13px;list-style:none;display:flex;box-shadow:0 1px 3px #0000000d}.frankie-root .frankie-agent-context>summary::-webkit-details-marker{display:none}.frankie-root .frankie-agent-context>summary>svg{color:var(--frankie-muted-foreground);flex:none}.frankie-root .frankie-context-count{background:var(--frankie-muted);color:var(--frankie-muted-foreground);border-radius:999px;padding:2px 10px;font-size:12px}.frankie-root .frankie-context-status{color:var(--frankie-muted-foreground);align-items:center;gap:6px;font-size:12px;display:flex}.frankie-root .frankie-context-status i{background:currentColor;border-radius:50%;width:7px;height:7px}.frankie-root .frankie-context-status[data-active=true]{color:#00976b}.frankie-root .frankie-context-detail{z-index:10;border:1px solid var(--frankie-border);background:var(--frankie-background);border-radius:16px;width:340px;max-width:calc(100vw - 32px);padding:18px;position:absolute;top:calc(100% + 10px);left:50%;transform:translate(-50%);box-shadow:0 12px 32px #00000016}.frankie-root .frankie-context-detail p{color:var(--frankie-muted-foreground);margin:10px 0 0;font-size:12px;line-height:1.6}.frankie-root .frankie-context-detail ul{max-height:220px;margin:12px 0;padding:0;list-style:none;overflow:auto}.frankie-root .frankie-context-detail li{border-bottom:1px solid var(--frankie-border);overflow-wrap:anywhere;justify-content:space-between;gap:12px;padding:8px 0;display:flex}.frankie-root .frankie-context-detail small{color:var(--frankie-muted-foreground);flex:none}.frankie-root .frankie-sr-only{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.frankie-root.frankie-chat-panel-fill{--frankie-canvas:var(--frankie-background)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-chat-panel-fill{--frankie-canvas:color-mix(in srgb,var(--frankie-background) 60%,var(--frankie-muted))}}.frankie-root.frankie-chat-panel-fill{background:var(--frankie-canvas)}.frankie-root.frankie-chat-panel-fill .frankie-agent-context-wrap{padding:44px 16px 26px}.frankie-root.frankie-chat-panel-fill .frankie-transcript{padding:14px max(24px,50% - 480px) 24px}.frankie-root.frankie-chat-panel-fill .frankie-message-list{gap:38px}.frankie-root.frankie-chat-panel-fill .frankie-user-bubble{background:var(--frankie-muted);color:var(--frankie-foreground);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:24px;padding:12px 20px;font-size:15px}.frankie-root.frankie-chat-panel-fill .frankie-assistant-content{flex:1;max-width:100%;font-size:15px;line-height:1.7}.frankie-root.frankie-chat-panel-fill .frankie-assistant-message{gap:14px}.frankie-root .frankie-thinking{color:var(--frankie-muted-foreground);gap:5px}.frankie-root .frankie-thinking-label{margin-right:6px;font-size:14px}.frankie-root.frankie-chat-panel-fill .frankie-composer-footer{background:0 0;border:0;flex:none;padding:16px max(24px,50% - 500px) 24px}.frankie-root.frankie-chat-panel-fill .frankie-composer{border:1px solid var(--frankie-border);background:var(--frankie-background);border-radius:28px;padding:14px;box-shadow:0 2px 4px #0000000a}.frankie-root.frankie-chat-panel-fill .frankie-composer:focus-within{border-color:var(--frankie-foreground)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-chat-panel-fill .frankie-composer:focus-within{border-color:color-mix(in srgb,var(--frankie-foreground) 32%,var(--frankie-border))}}.frankie-root.frankie-chat-panel-fill .frankie-composer:focus-within{box-shadow:0 0 0 2px var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-chat-panel-fill .frankie-composer:focus-within{box-shadow:0 0 0 2px color-mix(in srgb,var(--frankie-primary) 8%,transparent)}}.frankie-root.frankie-chat-panel-fill .frankie-composer-controls{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.frankie-root.frankie-chat-panel-fill .frankie-composer textarea{resize:none;width:100%;min-height:32px;max-height:140px;color:var(--frankie-foreground);box-shadow:none;background:0 0;border:0;border-radius:0;outline:none;flex:0 0 100%;order:-1;margin-bottom:4px;padding:2px 6px;font-size:16px}.frankie-root.frankie-chat-panel-fill .frankie-composer button[aria-label=Send],.frankie-root.frankie-chat-panel-fill .frankie-composer button[aria-label=Stop]{background:var(--frankie-primary);width:42px;height:42px;color:var(--frankie-primary-foreground);border:0;border-radius:50%;margin-left:auto}.frankie-root.frankie-chat-panel-fill .frankie-composer button[aria-label=Attach\\ files]{border-radius:50%;width:42px;height:42px}.frankie-root .frankie-composer-meta{align-items:center;gap:8px;margin-top:6px;padding:0 2px;display:flex}.frankie-root .frankie-model-picker{align-items:center;min-width:0;display:inline-flex}.frankie-root .frankie-model-select{appearance:none;max-width:12rem;color:var(--frankie-muted-foreground);font:inherit;cursor:pointer;text-overflow:ellipsis;background-color:#0000;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238b8b8b' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");background-position:right 6px center;background-repeat:no-repeat;background-size:11px;border:0;border-radius:8px;padding:5px 22px 5px 8px;font-size:12px;font-weight:500;line-height:1;transition:background-color .12s,color .12s}.frankie-root .frankie-model-select:hover{background-color:var(--frankie-muted);color:var(--frankie-foreground)}.frankie-root .frankie-model-select:disabled{opacity:.5;cursor:not-allowed}.frankie-root .frankie-model-select option{color:var(--frankie-foreground);background:var(--frankie-background);font-weight:400}.frankie-root .frankie-history-desktop{background:var(--frankie-background);width:290px;padding:20px 12px}.frankie-root .frankie-history-collapsed{width:56px;padding:20px 8px}.frankie-root .frankie-new-chat{background:0 0;border:0;justify-content:flex-start;padding:8px 12px;font-size:15px}.frankie-root .frankie-history-heading{color:var(--frankie-muted-foreground);padding:0 12px;font-size:12px;font-weight:400}.frankie-root .frankie-history-list button{min-height:44px;padding:10px 12px}.frankie-root .frankie-history-list button span{font-size:14px}.frankie-root .frankie-history-list button[aria-current],.frankie-root .frankie-history-list button:hover{background:var(--frankie-muted);border-color:#0000}.frankie-root .frankie-history-list small{display:none}.frankie-root .frankie-page-header{background:var(--frankie-background);height:56px;min-height:56px}.frankie-root .frankie-page-header>div{min-width:0}.frankie-root .frankie-thread-title{text-overflow:ellipsis;white-space:nowrap;max-width:55vw;font-weight:500;overflow:hidden}.frankie-root .frankie-page-header button{background:0 0;border-color:#0000}.frankie-root .frankie-page-canvas>.frankie-inline{max-width:none}@media (max-width:760px){.frankie-root.frankie-chat-panel-fill .frankie-agent-context-wrap{padding:20px 8px 14px}.frankie-root.frankie-chat-panel-fill .frankie-transcript{padding:12px 16px 16px}.frankie-root.frankie-chat-panel-fill .frankie-composer-footer{padding:10px 12px calc(12px + env(safe-area-inset-bottom))}.frankie-root .frankie-agent-context>summary{gap:6px;padding:7px 9px;font-size:12px}.frankie-root .frankie-context-count{padding:2px 7px;font-size:11px}.frankie-root .frankie-context-status{gap:4px;font-size:11px}.frankie-root .frankie-agent-context>summary>svg{width:14px}.frankie-root .frankie-thread-title{max-width:42vw}}.frankie-root .frankie-agent-context>summary>svg:first-child{box-sizing:content-box;background:var(--frankie-muted);border-radius:50%;padding:4px}.frankie-root.frankie-chat-panel-fill .frankie-agent-context>summary{font-size:14px}.frankie-root .frankie-agent-context>summary>span:first-of-type{border-right:1px solid var(--frankie-border);padding-right:10px}@media (max-width:760px){.frankie-root .frankie-page-header button>span{display:none}}.frankie-root .frankie-choices{flex-direction:column;gap:8px;margin-top:12px;display:flex}.frankie-root .frankie-choice{text-align:left;cursor:pointer;border:1px solid var(--frankie-border);border-radius:var(--frankie-radius);background:var(--frankie-background);width:100%;color:var(--frankie-foreground);font:inherit;align-items:center;gap:12px;padding:11px 14px;font-size:14px;line-height:1.4;transition:border-color .15s,background-color .15s,transform .12s;display:flex}.frankie-root .frankie-choice:hover:not(:disabled){border-color:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-choice:hover:not(:disabled){border-color:color-mix(in srgb, var(--frankie-primary) 55%, var(--frankie-border))}}.frankie-root .frankie-choice:hover:not(:disabled){background:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-choice:hover:not(:disabled){background:color-mix(in srgb, var(--frankie-primary) 6%, var(--frankie-background))}}.frankie-root .frankie-choice:active:not(:disabled){transform:scale(.99)}.frankie-root .frankie-choice:focus-visible{box-shadow:0 0 0 2px var(--frankie-primary);outline:none}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-choice:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, var(--frankie-primary) 40%, transparent)}}.frankie-root .frankie-choice:disabled{opacity:.6;cursor:default}.frankie-root .frankie-choice-index{border:1px solid var(--frankie-border);background:var(--frankie-muted);width:24px;height:24px;color:var(--frankie-muted-foreground);border-radius:50%;flex:none;place-items:center;font-size:12px;font-weight:600;transition:background-color .15s,color .15s,border-color .15s;display:grid}.frankie-root .frankie-choice:hover:not(:disabled) .frankie-choice-index{background:var(--frankie-primary);border-color:var(--frankie-primary);color:var(--frankie-primary-foreground)}.frankie-root .frankie-choice-label{flex:1;min-width:0}.frankie-root .frankie-choice-go{color:var(--frankie-muted-foreground);opacity:0;flex:none;transition:opacity .15s,transform .15s;transform:translate(-4px)}.frankie-root .frankie-choice:hover:not(:disabled) .frankie-choice-go{opacity:1;color:var(--frankie-primary);transform:none}@media (prefers-reduced-motion:reduce){.frankie-root .frankie-choice,.frankie-root .frankie-choice-go,.frankie-root .frankie-choice-index{transition:none}}.frankie-root .frankie-choice-other{color:var(--frankie-muted-foreground);border-style:dashed}.frankie-root .frankie-choice-other .frankie-choice-index{background:0 0}.frankie-root .frankie-choice-other:hover:not(:disabled){color:var(--frankie-foreground)}.frankie-root .frankie-choice-other:hover:not(:disabled) .frankie-choice-index{background:var(--frankie-muted);border-color:var(--frankie-border);color:var(--frankie-foreground)}.frankie-root .frankie-choice-hint{color:var(--frankie-muted-foreground);flex:none;font-size:12px}.frankie-root .frankie-skeleton{flex-direction:column;gap:8px;max-width:min(420px,100%);padding:4px 0 6px;display:flex}.frankie-root .frankie-skeleton-line{background:linear-gradient(90deg, var(--frankie-muted-foreground) 25%, var(--frankie-muted-foreground) 37%, var(--frankie-muted-foreground) 63%);border-radius:6px;height:12px}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-skeleton-line{background:linear-gradient(90deg, color-mix(in srgb, var(--frankie-muted-foreground) 11%, transparent) 25%, color-mix(in srgb, var(--frankie-muted-foreground) 26%, transparent) 37%, color-mix(in srgb, var(--frankie-muted-foreground) 11%, transparent) 63%)}}.frankie-root .frankie-skeleton-line{background-size:400% 100%;animation:1.4s infinite frankie-shimmer}@keyframes frankie-shimmer{0%{background-position:100%}to{background-position:0}}@keyframes frankie-skeleton-pulse{0%,to{opacity:.45}50%{opacity:.85}}@media (prefers-reduced-motion:reduce){.frankie-root .frankie-skeleton-line{background:var(--frankie-muted-foreground)}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-skeleton-line{background:color-mix(in srgb, var(--frankie-muted-foreground) 16%, transparent)}}.frankie-root .frankie-skeleton-line{animation:1.6s ease-in-out infinite frankie-skeleton-pulse}}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}`;
|
|
842
|
+
|
|
843
|
+
// src/lib/ensure-frankie-styles.ts
|
|
844
|
+
var STYLE_ELEMENT_ID = "frankie-fallback-styles";
|
|
845
|
+
var attempted = false;
|
|
846
|
+
function ensureFrankieStyles() {
|
|
847
|
+
if (attempted || typeof document === "undefined") return;
|
|
848
|
+
attempted = true;
|
|
849
|
+
if (document.getElementById(STYLE_ELEMENT_ID)) return;
|
|
850
|
+
const style = document.createElement("style");
|
|
851
|
+
style.id = STYLE_ELEMENT_ID;
|
|
852
|
+
style.textContent = FRANKIE_CSS_CONTENT;
|
|
853
|
+
document.head.appendChild(style);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// src/lib/styles-ready.ts
|
|
670
857
|
var useIsomorphicLayoutEffect = typeof window === "undefined" ? import_react3.useEffect : import_react3.useLayoutEffect;
|
|
671
858
|
var SENTINEL = "--frankie-styles-ready";
|
|
672
|
-
function useStylesReady(ref, timeoutMs = 600) {
|
|
859
|
+
function useStylesReady(ref, timeoutMs = 600, injectFallback = true) {
|
|
673
860
|
const [ready, setReady] = (0, import_react3.useState)(false);
|
|
674
861
|
useIsomorphicLayoutEffect(() => {
|
|
675
862
|
if (ready) return;
|
|
@@ -686,7 +873,12 @@ function useStylesReady(ref, timeoutMs = 600) {
|
|
|
686
873
|
const deadline = Date.now() + timeoutMs;
|
|
687
874
|
let frame = 0;
|
|
688
875
|
const poll = () => {
|
|
689
|
-
if (applied()
|
|
876
|
+
if (applied()) {
|
|
877
|
+
setReady(true);
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
if (Date.now() >= deadline) {
|
|
881
|
+
if (injectFallback) ensureFrankieStyles();
|
|
690
882
|
setReady(true);
|
|
691
883
|
return;
|
|
692
884
|
}
|
|
@@ -698,7 +890,7 @@ function useStylesReady(ref, timeoutMs = 600) {
|
|
|
698
890
|
}
|
|
699
891
|
frame = window.requestAnimationFrame(poll);
|
|
700
892
|
return () => window.cancelAnimationFrame(frame);
|
|
701
|
-
}, [ref, ready, timeoutMs]);
|
|
893
|
+
}, [ref, ready, timeoutMs, injectFallback]);
|
|
702
894
|
return ready;
|
|
703
895
|
}
|
|
704
896
|
|
|
@@ -1039,19 +1231,22 @@ function Composer({ onSend, onStop, busy, placeholder, disabled, autoFocus, atta
|
|
|
1039
1231
|
"aria-label": "Message"
|
|
1040
1232
|
}
|
|
1041
1233
|
),
|
|
1042
|
-
|
|
1234
|
+
busy ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", size: "icon", variant: "outline", onClick: onStop, "aria-label": "Stop", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Square, {}) }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "submit", size: "icon", disabled: disabled || nothingToSend, "aria-label": "Send", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.ArrowUp, {}) })
|
|
1235
|
+
] }),
|
|
1236
|
+
models.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "frankie-composer-meta", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "frankie-model-picker", title: "Model", children: [
|
|
1237
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "frankie-sr-only", children: "Model" }),
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1043
1239
|
"select",
|
|
1044
1240
|
{
|
|
1045
1241
|
value: modelPicker?.value ?? models[0]?.id,
|
|
1046
1242
|
onChange: (event) => modelPicker?.onChange(event.target.value),
|
|
1047
1243
|
disabled,
|
|
1048
1244
|
"aria-label": "Model",
|
|
1049
|
-
className: "frankie-
|
|
1245
|
+
className: "frankie-model-select",
|
|
1050
1246
|
children: models.map((model) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: model.id, children: model.label }, model.id))
|
|
1051
1247
|
}
|
|
1052
|
-
)
|
|
1053
|
-
|
|
1054
|
-
] })
|
|
1248
|
+
)
|
|
1249
|
+
] }) }) : null
|
|
1055
1250
|
]
|
|
1056
1251
|
}
|
|
1057
1252
|
);
|
|
@@ -1280,6 +1475,7 @@ function ToolActivityList({ tools, renderTool }) {
|
|
|
1280
1475
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("details", { className: "frankie-tool-activity mt-2", open: running, children: [
|
|
1281
1476
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("summary", { className: "inline-flex min-h-7 cursor-pointer list-none items-center gap-1.5 rounded-md px-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground [&::-webkit-details-marker]:hidden", children: [
|
|
1282
1477
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.ChevronDown, { className: "frankie-tool-chevron size-3.5 transition-transform", "aria-hidden": "true" }),
|
|
1478
|
+
running ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.Loader2, { className: "size-3.5 animate-spin", "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.Wrench, { className: "size-3.5", "aria-hidden": "true" }),
|
|
1283
1479
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: running ? "Working" : "Activity" }),
|
|
1284
1480
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "text-[11px]", children: [
|
|
1285
1481
|
"\xB7 ",
|
|
@@ -1348,18 +1544,20 @@ var MessageBubble = (0, import_react8.memo)(function MessageBubble2({
|
|
|
1348
1544
|
] }) : null
|
|
1349
1545
|
] });
|
|
1350
1546
|
}
|
|
1351
|
-
const empty = message.text.length === 0 && message.tools.length === 0;
|
|
1352
1547
|
const { body, options } = extractChoices(message.text);
|
|
1353
1548
|
const showChoices = Boolean(active && onChoose && options && message.status === "done");
|
|
1549
|
+
const toolsRunning = message.tools.some((tool) => tool.status === "running");
|
|
1550
|
+
const waiting = message.status === "streaming" && body.length === 0 && !toolsRunning;
|
|
1354
1551
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "frankie-assistant-message flex gap-2", children: [
|
|
1355
1552
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "frankie-assistant-actions mt-0.5 flex shrink-0 flex-col items-center gap-1", children: [
|
|
1356
1553
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Avatar, { ...avatarUrl ? { src: avatarUrl } : {}, name: assistantName }),
|
|
1357
1554
|
body ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageCopyButton, { text: body }) : null
|
|
1358
1555
|
] }),
|
|
1359
1556
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "frankie-assistant-content min-w-0 max-w-[85%]", children: [
|
|
1360
|
-
message.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "rounded-[var(--frankie-radius)] bg-red-500/10 px-3 py-2 text-sm text-red-600 dark:text-red-400", children: message.error }) :
|
|
1557
|
+
message.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "rounded-[var(--frankie-radius)] bg-red-500/10 px-3 py-2 text-sm text-red-600 dark:text-red-400", children: message.error }) : body ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Markdown, { text: body, className: "text-sm" }) : null,
|
|
1361
1558
|
showChoices ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Choices, { options: options ?? [], onPick: onChoose, ...onRequestInput ? { onSomethingElse: onRequestInput } : {}, disabled: busy }) : null,
|
|
1362
|
-
showToolActivity ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToolActivityList, { tools: message.tools, ...renderTool ? { renderTool } : {} }) : null
|
|
1559
|
+
showToolActivity ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToolActivityList, { tools: message.tools, ...renderTool ? { renderTool } : {} }) : null,
|
|
1560
|
+
waiting ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Thinking, {}) : null
|
|
1363
1561
|
] })
|
|
1364
1562
|
] });
|
|
1365
1563
|
});
|
|
@@ -1388,6 +1586,13 @@ function TypingDots() {
|
|
|
1388
1586
|
))
|
|
1389
1587
|
] });
|
|
1390
1588
|
}
|
|
1589
|
+
function Thinking() {
|
|
1590
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "frankie-skeleton", role: "status", "aria-label": "Thinking", children: [
|
|
1591
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "frankie-skeleton-line", style: { width: "62%" } }),
|
|
1592
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "frankie-skeleton-line", style: { width: "92%" } }),
|
|
1593
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "frankie-skeleton-line", style: { width: "48%" } })
|
|
1594
|
+
] });
|
|
1595
|
+
}
|
|
1391
1596
|
|
|
1392
1597
|
// src/components/chat/SuggestedPrompts.tsx
|
|
1393
1598
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
@@ -1533,10 +1738,10 @@ function FrankieWidget({
|
|
|
1533
1738
|
renderLauncher,
|
|
1534
1739
|
...panelProps
|
|
1535
1740
|
}) {
|
|
1536
|
-
const { config } = useFrankie();
|
|
1741
|
+
const { config, injectStyles } = useFrankie();
|
|
1537
1742
|
const theme = useFrankieTheme();
|
|
1538
1743
|
const rootRef = (0, import_react10.useRef)(null);
|
|
1539
|
-
const stylesReady = useStylesReady(rootRef);
|
|
1744
|
+
const stylesReady = useStylesReady(rootRef, void 0, injectStyles);
|
|
1540
1745
|
const [uncontrolledOpen, setUncontrolledOpen] = (0, import_react10.useState)(defaultOpen);
|
|
1541
1746
|
const open = controlledOpen ?? uncontrolledOpen;
|
|
1542
1747
|
const setOpen = (next) => {
|
|
@@ -1585,10 +1790,11 @@ function FrankieWidget({
|
|
|
1585
1790
|
var import_react11 = require("react");
|
|
1586
1791
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1587
1792
|
function FrankieInline({ className, style, ...panelProps }) {
|
|
1793
|
+
const { injectStyles } = useFrankie();
|
|
1588
1794
|
const theme = useFrankieTheme();
|
|
1589
1795
|
const mode = resolveMode(theme?.mode);
|
|
1590
1796
|
const rootRef = (0, import_react11.useRef)(null);
|
|
1591
|
-
const stylesReady = useStylesReady(rootRef);
|
|
1797
|
+
const stylesReady = useStylesReady(rootRef, void 0, injectStyles);
|
|
1592
1798
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1593
1799
|
"div",
|
|
1594
1800
|
{
|
|
@@ -1760,7 +1966,7 @@ function FrankieChatPage({ className, style, header, footer, emptyState, renderM
|
|
|
1760
1966
|
const [id, setId] = (0, import_react12.useState)(() => provider.conversationId ?? crypto.randomUUID());
|
|
1761
1967
|
const onNew = () => setId(crypto.randomUUID());
|
|
1762
1968
|
const pageRef = (0, import_react12.useRef)(null);
|
|
1763
|
-
const stylesReady = useStylesReady(pageRef);
|
|
1969
|
+
const stylesReady = useStylesReady(pageRef, void 0, provider.injectStyles);
|
|
1764
1970
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { ref: pageRef, className: ["frankie-root", "frankie-chat-page", className].filter(Boolean).join(" "), style: { height: "100%", minHeight: "min(36rem, 100dvh)", width: "100%", ...style, ...stylesReady ? null : { opacity: 0 } }, "data-frankie-styles": stylesReady ? "ready" : "pending", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(FrankieProvider, { ...provider, conversationId: id, storageNamespace: (provider.storageNamespace ?? "frankie." + provider.publishableKey) + "." + id, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PageChrome, { showHistory, navigation, currentId: id, onSelect: setId, onNew, header, footer, emptyState, renderMessage, renderTool, placeholder, autoFocus }) }) });
|
|
1765
1971
|
}
|
|
1766
1972
|
|
|
@@ -1796,6 +2002,7 @@ function Separator({ className }) {
|
|
|
1796
2002
|
Separator,
|
|
1797
2003
|
SuggestedPrompts,
|
|
1798
2004
|
Textarea,
|
|
2005
|
+
Thinking,
|
|
1799
2006
|
ToolActivityList,
|
|
1800
2007
|
ToolActivityRow,
|
|
1801
2008
|
TypingDots,
|