@frankieai/react 0.2.2 → 0.2.3

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/FrankieProvider.tsx","../src/lib/client.ts","../src/hooks/useFrankieChat.ts","../src/lib/messages.ts","../src/components/chat/FrankieWidget.tsx","../src/lib/theme.ts","../src/lib/utils.ts","../src/components/ui/button.tsx","../src/components/chat/ChatPanel.tsx","../src/components/ui/avatar.tsx","../src/components/ui/card.tsx","../src/components/ui/scroll-area.tsx","../src/components/chat/AgentContext.tsx","../src/components/chat/Composer.tsx","../src/components/ui/textarea.tsx","../src/components/chat/MessageBubble.tsx","../src/components/chat/Markdown.tsx","../src/components/chat/ToolActivityList.tsx","../src/components/ui/badge.tsx","../src/components/chat/SuggestedPrompts.tsx","../src/components/chat/FrankieInline.tsx","../src/components/chat/FrankieChatPage.tsx","../src/components/ui/separator.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport type { PublicWidgetConfig, WidgetTheme } from \"@frankieai/core\";\nimport { FrankieClient, type FrankieClientOptions, type PageContext } from \"../lib/client.js\";\nimport { FrankieChatContext, useFrankieChatState } from \"./useFrankieChat.js\";\n\nexport interface FrankieProviderProps extends FrankieClientOptions {\n children: ReactNode;\n context?: PageContext;\n theme?: WidgetTheme;\n config?: PublicWidgetConfig;\n}\n\ninterface FrankieContextValue {\n client: FrankieClient;\n config?: PublicWidgetConfig;\n configError?: string;\n loading: boolean;\n context?: PageContext;\n theme?: WidgetTheme;\n}\n\nconst FrankieContext = createContext<FrankieContextValue | null>(null);\n\nexport function FrankieProvider({\n children,\n context,\n theme,\n config: providedConfig,\n ...clientOptions\n}: FrankieProviderProps) {\n const tokenCallback = useRef(clientOptions.getUserToken);\n tokenCallback.current = clientOptions.getUserToken;\n const client = useMemo(\n () => new FrankieClient({ ...clientOptions, ...(clientOptions.getUserToken ? { getUserToken: () => tokenCallback.current?.() } : {}) }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [clientOptions.baseUrl, clientOptions.publishableKey, clientOptions.storageNamespace, clientOptions.conversationId, clientOptions.persist, clientOptions.fetchImpl, Boolean(clientOptions.getUserToken)],\n );\n\n const [config, setConfig] = useState<PublicWidgetConfig | undefined>(providedConfig);\n const [configError, setConfigError] = useState<string | undefined>(undefined);\n const [loading, setLoading] = useState(!providedConfig);\n\n useEffect(() => {\n if (providedConfig) return;\n const abort = new AbortController();\n setLoading(true);\n client\n .getConfig(abort.signal)\n .then((next) => {\n setConfig(next);\n setConfigError(undefined);\n })\n .catch((error: unknown) => {\n if (abort.signal.aborted) return;\n setConfigError(error instanceof Error ? error.message : \"Could not load the assistant.\");\n })\n .finally(() => {\n if (!abort.signal.aborted) setLoading(false);\n });\n return () => abort.abort();\n }, [client, providedConfig]);\n\n const value = useMemo<FrankieContextValue>(\n () => ({\n client,\n ...(config ? { config } : {}),\n ...(configError ? { configError } : {}),\n loading,\n ...(context ? { context } : {}),\n ...(theme ? { theme } : {}),\n }),\n [client, config, configError, loading, context, theme],\n );\n\n return <FrankieContext.Provider value={value}><ConversationState key={client.namespace + \":\" + (client.conversationId ?? \"\")}>{children}</ConversationState></FrankieContext.Provider>;\n}\n\nfunction ConversationState({ children }: { children: ReactNode }) {\n const chat = useFrankieChatState();\n return <FrankieChatContext.Provider value={chat}>{children}</FrankieChatContext.Provider>;\n}\n\nexport function useFrankie(): FrankieContextValue {\n const value = useContext(FrankieContext);\n if (!value) throw new Error(\"Frankie components must be rendered inside <FrankieProvider>.\");\n return value;\n}\n\nexport function useFrankieTheme(): WidgetTheme | undefined {\n const { config, theme } = useFrankie();\n return useMemo(() => ({ ...config?.theme, ...theme }), [config?.theme, theme]);\n}\n","import type {\n ChatAttachment,\n ChatRequestBody,\n CreateSessionResponse,\n FrankieServerEvent,\n PublicWidgetConfig,\n} from \"@frankieai/core\";\n\nexport type PageContext = Record<string, string | number | boolean | null>;\n\n/**\n * The hosted Frankie data plane. Embedding needs only a publishable key, so\n * `baseUrl` defaults here — override it only when self-hosting the server.\n */\nexport const FRANKIE_CLOUD_URL = \"https://frankie-data-665333762719.us-central1.run.app\";\n\nexport interface FrankieClientOptions {\n /** Where the Frankie server is mounted. Defaults to the hosted cloud. */\n baseUrl?: string;\n /** Safe to ship to the browser; the origin allowlist is what authorises it. */\n publishableKey: string;\n /**\n * Fetches a short-lived JWT for the signed-in user from the host's own\n * backend. Called before each turn; return undefined after sign-out.\n * Omit only for tenants that allow anonymous chat.\n */\n getUserToken?: () => Promise<string | undefined> | string | undefined;\n fetchImpl?: typeof fetch;\n /**\n * Remember the session (and, in the hook, the transcript) in localStorage so a\n * page reload resumes the same anonymous conversation. Authenticated chat\n * never writes tokens or transcripts to localStorage; it uses server history.\n */\n persist?: boolean;\n /** Override localStorage namespace for session and transcript. */\n storageNamespace?: string;\n /** Stable id for a server-backed conversation. */\n conversationId?: string;\n}\n\nexport interface ChatConversation {\n id: string;\n title: string;\n createdAt: number;\n updatedAt: number;\n}\n\nexport class FrankieApiError extends Error {\n constructor(\n message: string,\n readonly status: number,\n readonly code: string,\n ) {\n super(message);\n }\n}\n\nexport class FrankieClient {\n private readonly baseUrl: string;\n private readonly doFetch: typeof fetch;\n private session?: CreateSessionResponse;\n private sessionUserToken?: string;\n\n constructor(private readonly options: FrankieClientOptions) {\n this.baseUrl = (options.baseUrl ?? FRANKIE_CLOUD_URL).replace(/\\/+$/, \"\");\n this.doFetch = options.fetchImpl ?? globalThis.fetch.bind(globalThis);\n this.session = this.readStored();\n if (options.getUserToken && typeof window !== \"undefined\") {\n try { for (const suffix of [\"session\", \"messages\"]) window.localStorage.removeItem(`${this.namespace}.${suffix}`); } catch { /* storage may be unavailable */ }\n }\n }\n\n get sessionId(): string | undefined {\n return this.session?.sessionId;\n }\n\n get conversationId(): string | undefined {\n return this.options.conversationId;\n }\n\n /** Whether this client persists across reloads (browser only, opt-out via `persist:false`). */\n get persist(): boolean {\n // Authenticated history comes from the identity-checked server. Do not leave\n // a previous user's bearer token or transcript in shared browser storage.\n return !this.options.getUserToken && this.options.persist !== false && typeof window !== \"undefined\";\n }\n\n /** localStorage namespace for this tenant/conversation, shared with the chat hook. */\n get namespace(): string {\n return this.options.storageNamespace ?? `frankie.${this.options.publishableKey}`;\n }\n\n private readStored(): CreateSessionResponse | undefined {\n if (!this.persist) return undefined;\n try {\n const raw = window.localStorage.getItem(`${this.namespace}.session`);\n if (!raw) return undefined;\n const session = JSON.parse(raw) as CreateSessionResponse;\n return new Date(session.expiresAt).getTime() > Date.now() + 30_000 ? session : undefined;\n } catch {\n return undefined;\n }\n }\n\n private writeStored(): void {\n if (!this.persist) return;\n try {\n if (this.session) window.localStorage.setItem(`${this.namespace}.session`, JSON.stringify(this.session));\n else window.localStorage.removeItem(`${this.namespace}.session`);\n } catch {\n /* storage may be unavailable (private mode); the chat still works in memory */\n }\n }\n\n async getConfig(signal?: AbortSignal): Promise<PublicWidgetConfig> {\n const response = await this.doFetch(`${this.baseUrl}/v1/config`, {\n headers: { \"x-frankie-key\": this.options.publishableKey },\n ...(signal ? { signal } : {}),\n });\n return (await this.unwrap(response)) as PublicWidgetConfig;\n }\n\n async ensureSession(context?: PageContext): Promise<CreateSessionResponse> {\n const userToken = await this.options.getUserToken?.();\n if (this.options.getUserToken && !userToken) {\n this.resetSession();\n throw new FrankieApiError(\n \"Your signed-in Frankie session could not be verified. Refresh the page and sign in again.\",\n 401,\n \"user_token_unavailable\",\n );\n }\n if (userToken !== this.sessionUserToken) this.resetSession();\n if (this.session && new Date(this.session.expiresAt).getTime() > Date.now() + 30_000) return this.session;\n const response = await this.doFetch(`${this.baseUrl}/v1/session`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-frankie-key\": this.options.publishableKey },\n body: JSON.stringify({\n ...(userToken ? { userToken } : {}),\n ...(context ? { context } : {}),\n ...(this.options.conversationId ? { conversationId: this.options.conversationId } : {}),\n }),\n });\n this.session = (await this.unwrap(response)) as CreateSessionResponse;\n this.sessionUserToken = userToken;\n this.writeStored();\n return this.session;\n }\n\n async listConversations(): Promise<ChatConversation[]> {\n const userToken = await this.requireUserToken();\n const response = await this.doFetch(`${this.baseUrl}/v1/conversations`, {\n headers: { \"x-frankie-key\": this.options.publishableKey, authorization: `Bearer ${userToken}` },\n });\n const body = (await this.unwrap(response)) as { conversations?: ChatConversation[] };\n return Array.isArray(body.conversations) ? body.conversations : [];\n }\n\n async resumeConversation(id = this.options.conversationId): Promise<{ messages: unknown[]; title: string } | undefined> {\n if (!id || !this.options.getUserToken) return undefined;\n const userToken = await this.requireUserToken();\n const response = await this.doFetch(`${this.baseUrl}/v1/conversations/${encodeURIComponent(id)}/resume`, {\n method: \"POST\",\n headers: { \"x-frankie-key\": this.options.publishableKey, authorization: `Bearer ${userToken}` },\n });\n if (response.status === 404) return undefined;\n const body = (await this.unwrap(response)) as { session: CreateSessionResponse; messages?: unknown[]; title?: string };\n this.session = body.session;\n this.sessionUserToken = userToken;\n this.writeStored();\n return { messages: Array.isArray(body.messages) ? body.messages : [], title: body.title ?? \"New chat\" };\n }\n\n async syncConversation(messages: unknown[], title?: string): Promise<void> {\n if (!this.session || !this.options.conversationId) return;\n const response = await this.doFetch(`${this.baseUrl}/v1/conversations/${encodeURIComponent(this.options.conversationId)}`, {\n method: \"PUT\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-frankie-key\": this.options.publishableKey,\n authorization: `Bearer ${this.session.sessionToken}`,\n },\n body: JSON.stringify({ messages, ...(title ? { title } : {}) }),\n });\n await this.unwrap(response);\n }\n\n async deleteConversation(id: string): Promise<void> {\n const userToken = await this.requireUserToken();\n const response = await this.doFetch(`${this.baseUrl}/v1/conversations/${encodeURIComponent(id)}`, {\n method: \"DELETE\",\n headers: { \"x-frankie-key\": this.options.publishableKey, authorization: `Bearer ${userToken}` },\n });\n if (response.status !== 404) await this.unwrap(response);\n }\n\n private async requireUserToken(): Promise<string> {\n const token = await this.options.getUserToken?.();\n if (!token) throw new FrankieApiError(\"Sign in to access your chat history.\", 401, \"unauthorized\");\n return token;\n }\n\n resetSession(): void {\n this.session = undefined;\n this.writeStored();\n }\n\n async send(\n input: {\n message: string;\n context?: PageContext;\n model?: string;\n attachments?: ChatAttachment[];\n signal?: AbortSignal;\n },\n onEvent: (event: FrankieServerEvent) => void,\n ): Promise<void> {\n const session = await this.ensureSession(input.context);\n const body: ChatRequestBody = {\n sessionId: session.sessionId,\n message: input.message,\n ...(input.context ? { context: input.context } : {}),\n ...(input.model ? { model: input.model } : {}),\n ...(input.attachments?.length ? { attachments: input.attachments } : {}),\n };\n\n const response = await this.doFetch(`${this.baseUrl}/v1/chat`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-frankie-key\": this.options.publishableKey,\n authorization: `Bearer ${session.sessionToken}`,\n },\n body: JSON.stringify(body),\n ...(input.signal ? { signal: input.signal } : {}),\n });\n\n if (!response.ok || !response.body) {\n if (response.status === 401 || response.status === 404) this.resetSession();\n await this.unwrap(response);\n return;\n }\n\n for await (const event of readEventStream(response.body)) {\n onEvent(event);\n }\n }\n\n private async unwrap(response: Response): Promise<unknown> {\n if (response.ok) return response.json();\n let code = \"internal\";\n let message = `Request failed with status ${response.status}.`;\n try {\n const body = (await response.json()) as { error?: { code?: string; message?: string } };\n code = body.error?.code ?? code;\n message = body.error?.message ?? message;\n } catch {\n /* keep the default message */\n }\n throw new FrankieApiError(message, response.status, code);\n }\n}\n\nexport async function* readEventStream(\n body: ReadableStream<Uint8Array>,\n): AsyncGenerator<FrankieServerEvent> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n let split = buffer.indexOf(\"\\n\\n\");\n while (split !== -1) {\n const frame = buffer.slice(0, split);\n buffer = buffer.slice(split + 2);\n const event = parseFrame(frame);\n if (event) yield event;\n split = buffer.indexOf(\"\\n\\n\");\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction parseFrame(frame: string): FrankieServerEvent | null {\n const data = frame\n .split(\"\\n\")\n .filter((line) => line.startsWith(\"data:\"))\n .map((line) => line.slice(5).replace(/^ /, \"\"))\n .join(\"\\n\");\n if (!data) return null;\n try {\n return JSON.parse(data) as FrankieServerEvent;\n } catch {\n return null;\n }\n}\n","\"use client\";\n\nimport { createContext, useContext, useCallback, useEffect, useRef, useState } from \"react\";\nimport type { ChatAttachment, LoadedSkill } from \"@frankieai/core\";\nimport { FrankieApiError } from \"../lib/client.js\";\nimport {\n applyEvent,\n newAssistantMessage,\n newUserMessage,\n type AssistantChatMessage,\n type ChatMessage,\n} from \"../lib/messages.js\";\nimport { useFrankie } from \"./FrankieProvider.jsx\";\n\n/** Extra inputs a turn can carry: attached files and a chosen model. */\nexport interface SendOptions {\n attachments?: ChatAttachment[];\n model?: string;\n}\n\nexport interface UseFrankieChatResult {\n loadedSkills: LoadedSkill[] | null;\n restoring: boolean;\n messages: ChatMessage[];\n /** True from the moment a message is sent until the turn ends. */\n busy: boolean;\n /** Set when the turn failed outright (network, auth, rate limit). */\n error?: string;\n send: (text: string, opts?: SendOptions) => Promise<void>;\n /** Abort the in-flight turn. The partial answer stays in the transcript. */\n stop: () => void;\n /** Clear the transcript and start a brand-new server session. */\n reset: () => void;\n}\n\nlet counter = 0;\nconst nextId = (prefix: string) => `${prefix}_${Date.now().toString(36)}_${(counter += 1)}`;\n\nexport const FrankieChatContext = createContext<UseFrankieChatResult | null>(null);\nexport function useFrankieChat(): UseFrankieChatResult {\n const value = useContext(FrankieChatContext);\n if (!value) throw new Error(\"useFrankieChat requires FrankieProvider.\");\n return value;\n}\n\nexport function useFrankieChatState(): UseFrankieChatResult {\n const { client, context } = useFrankie();\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | undefined>(undefined);\n const [restored, setRestored] = useState(false);\n const [loadedSkills, setLoadedSkills] = useState<LoadedSkill[] | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n const mounted = useRef(true);\n // State updates can be batched while a stream is arriving. Keep the latest\n // transcript synchronously so the final server sync cannot save a stale copy.\n const messagesRef = useRef<ChatMessage[]>([]);\n\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n abortRef.current?.abort();\n };\n }, []);\n\n const storageKey = `${client.namespace}.messages`;\n\n // Restore local storage immediately, then hydrate the authoritative server\n // transcript. The server path makes the same signed-in user's chats available\n // on another browser or device.\n useEffect(() => {\n let active = true;\n const restore = async () => {\n if (client.persist) {\n try {\n const raw = window.localStorage.getItem(storageKey);\n const stored = raw ? (JSON.parse(raw) as ChatMessage[]) : [];\n if (Array.isArray(stored) && stored.length && active) {\n messagesRef.current = stored;\n setMessages(stored);\n }\n } catch {\n /* storage unavailable; server history can still restore */\n }\n }\n try {\n const remote = await client.resumeConversation();\n if (active && remote?.messages.length) {\n const restoredMessages = remote.messages as ChatMessage[];\n messagesRef.current = restoredMessages;\n setMessages(restoredMessages);\n }\n } catch {\n if (active) setError(\"Could not restore this conversation. Check your sign-in and connection, then try opening it again.\");\n } finally {\n if (active) setRestored(true);\n }\n };\n void restore();\n return () => { active = false; };\n }, [client, storageKey]);\n\n // Persist once a turn settles — never mid-stream — so the saved copy is clean.\n // Wait until the initial restore has completed so an empty initial state never\n // deletes an existing transcript.\n useEffect(() => {\n if (!client.persist || !restored || busy) return;\n try {\n if (messages.length) window.localStorage.setItem(storageKey, JSON.stringify(messages));\n else window.localStorage.removeItem(storageKey);\n } catch {\n /* ignore */\n }\n if (messages.length) void client.syncConversation(messages, conversationTitle(messages)).catch(() => undefined);\n }, [messages, busy, client, storageKey, restored]);\n\n const patchAssistant = useCallback((id: string, update: (m: AssistantChatMessage) => AssistantChatMessage) => {\n const next = messagesRef.current.map((message) =>\n message.id === id && message.role === \"assistant\" ? update(message) : message,\n );\n messagesRef.current = next;\n setMessages(next);\n }, []);\n\n const send = useCallback(\n async (text: string, opts?: SendOptions) => {\n const trimmed = text.trim();\n const attachments = opts?.attachments ?? [];\n if ((!trimmed && attachments.length === 0) || abortRef.current || !restored) return;\n // The server needs a message; an attachment-only turn gets a stand-in.\n const outgoing = trimmed || \"Please take a look at the attached file(s).\";\n\n const assistantId = nextId(\"a\");\n setError(undefined);\n setLoadedSkills(null);\n setBusy(true);\n const next = [\n ...messagesRef.current,\n newUserMessage(\n nextId(\"u\"),\n trimmed,\n attachments.map((file) => ({ name: file.name, mimeType: file.mimeType })),\n ),\n newAssistantMessage(assistantId),\n ];\n messagesRef.current = next;\n setMessages(next);\n\n const abort = new AbortController();\n abortRef.current = abort;\n\n try {\n let receivedText = false;\n let receivedToolActivity = false;\n await client.send(\n {\n message: outgoing,\n ...(context ? { context } : {}),\n ...(opts?.model ? { model: opts.model } : {}),\n ...(attachments.length ? { attachments } : {}),\n signal: abort.signal,\n },\n (event) => {\n if (event.type === \"skills_loaded\") { setLoadedSkills(event.skills); return; }\n if (event.type === \"ping\" || event.type === \"session\") return;\n if (event.type === \"text_delta\") receivedText = true;\n if (event.type === \"tool_start\" || event.type === \"tool_end\") receivedToolActivity = true;\n patchAssistant(assistantId, (message) => applyEvent(message, event));\n },\n );\n // A terminated stream with no text previously looked like Frankie did\n // nothing. Preserve visible tool activity, but never leave an empty\n // assistant bubble for the user to interpret.\n if (!receivedText) {\n patchAssistant(assistantId, (message) => ({\n ...message,\n status: \"done\",\n text: receivedToolActivity\n ? \"Completed. Open Agent activity for the details.\"\n : \"Frankie didn’t return an answer. Please try again.\",\n }));\n }\n } catch (caught) {\n if (abort.signal.aborted) {\n patchAssistant(assistantId, (message) => ({\n ...message,\n status: \"done\",\n text: message.text || \"Stopped.\",\n }));\n } else {\n const message =\n caught instanceof FrankieApiError\n ? caught.message\n : caught instanceof Error && caught.message.startsWith(\"Frankie\")\n ? caught.message\n : \"Could not reach the assistant. Check your connection and try again.\";\n if (mounted.current) setError(message);\n patchAssistant(assistantId, (current) => ({ ...current, status: \"error\", error: message }));\n }\n } finally {\n // A turn that ended without a `turn_end` event still has to settle.\n patchAssistant(assistantId, (message) =>\n message.status === \"streaming\" ? { ...message, status: \"done\" } : message,\n );\n // Persist before send() resolves. This closes the previous gap where a\n // route change or tab close could leave a server conversation with no\n // rendered messages even though the agent transcript existed.\n const transcript = messagesRef.current;\n if (transcript.length) {\n await client.syncConversation(transcript, conversationTitle(transcript)).catch(() => undefined);\n }\n if (mounted.current) setBusy(false);\n abortRef.current = null;\n }\n },\n [busy, client, context, patchAssistant, restored],\n );\n\n const stop = useCallback(() => abortRef.current?.abort(), []);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n client.resetSession();\n messagesRef.current = [];\n setMessages([]);\n setError(undefined);\n setBusy(false);\n setRestored(true);\n setLoadedSkills(null);\n try {\n if (client.persist) window.localStorage.removeItem(`${client.namespace}.messages`);\n } catch {\n /* ignore */\n }\n }, [client]);\n\n return { messages, busy, loadedSkills, restoring: !restored, ...(error ? { error } : {}), send, stop, reset };\n}\n\n\nfunction conversationTitle(messages: ChatMessage[]): string | undefined {\n const first = messages.find((message) => message.role === \"user\" && message.text.trim());\n if (!first) return undefined;\n const title = first.text.trim().replace(/\\s+/g, \" \");\n return title.length > 42 ? `${title.slice(0, 42)}…` : title;\n}\n","import type { FrankieServerEvent } from \"@frankieai/core\";\n\nexport interface ToolActivity {\n id: string;\n name: string;\n label: string;\n status: \"running\" | \"done\" | \"failed\" | \"denied\";\n detail?: string;\n}\n\n/** A file shown on a user message (name/type only — the bytes aren't kept in the transcript). */\nexport interface MessageAttachment {\n name: string;\n mimeType: string;\n}\n\nexport interface UserChatMessage {\n id: string;\n role: \"user\";\n text: string;\n attachments?: MessageAttachment[];\n createdAt: number;\n}\n\nexport interface AssistantChatMessage {\n id: string;\n role: \"assistant\";\n text: string;\n thinking: string;\n tools: ToolActivity[];\n status: \"streaming\" | \"done\" | \"error\";\n error?: string;\n createdAt: number;\n}\n\nexport type ChatMessage = UserChatMessage | AssistantChatMessage;\n\n/**\n * Fold one server event into the assistant message being built.\n *\n * Kept pure and separate from React so the streaming logic is testable without\n * a DOM, and so a host writing its own UI can reuse it.\n */\nexport function applyEvent(message: AssistantChatMessage, event: FrankieServerEvent): AssistantChatMessage {\n switch (event.type) {\n case \"text_delta\":\n return { ...message, text: message.text + event.text };\n\n case \"thinking_delta\":\n return { ...message, thinking: message.thinking + event.text };\n\n case \"tool_start\":\n return {\n ...message,\n tools: [\n ...message.tools,\n { id: event.toolUseId, name: event.name, label: event.label, status: \"running\" },\n ],\n };\n\n case \"tool_end\":\n return {\n ...message,\n tools: message.tools.map((tool) =>\n tool.id === event.toolUseId\n ? {\n ...tool,\n status: event.ok ? \"done\" : \"failed\",\n ...(event.preview ? { detail: event.preview } : {}),\n }\n : tool,\n ),\n };\n\n case \"tool_denied\":\n return {\n ...message,\n tools: upsertTool(message.tools, {\n id: event.toolUseId,\n name: event.name,\n label: event.name,\n status: \"denied\",\n detail: event.reason,\n }),\n };\n\n case \"turn_end\":\n return {\n ...message,\n status: message.status === \"error\" ? \"error\" : \"done\",\n // A turn that produced nothing still needs to say something.\n text: message.text || fallbackText(event.stopReason),\n };\n\n case \"error\":\n return { ...message, status: \"error\", error: event.message };\n\n default:\n return message;\n }\n}\n\nfunction upsertTool(tools: ToolActivity[], next: ToolActivity): ToolActivity[] {\n return tools.some((tool) => tool.id === next.id)\n ? tools.map((tool) => (tool.id === next.id ? { ...tool, ...next } : tool))\n : [...tools, next];\n}\n\nfunction fallbackText(stopReason: string): string {\n switch (stopReason) {\n case \"max_turns\":\n return \"I got stuck working on that. Could you narrow it down a little?\";\n case \"aborted\":\n return \"Stopped.\";\n case \"error\":\n return \"Something went wrong before I could answer. Try again?\";\n default:\n return \"\";\n }\n}\n\nexport function newAssistantMessage(id: string): AssistantChatMessage {\n return { id, role: \"assistant\", text: \"\", thinking: \"\", tools: [], status: \"streaming\", createdAt: Date.now() };\n}\n\nexport function newUserMessage(id: string, text: string, attachments?: MessageAttachment[]): UserChatMessage {\n return { id, role: \"user\", text, ...(attachments?.length ? { attachments } : {}), createdAt: Date.now() };\n}\n","\"use client\";\n\nimport { MessageCircle, X } from \"lucide-react\";\nimport { useEffect, useState } from \"react\";\nimport { useFrankie, useFrankieTheme } from \"../../hooks/FrankieProvider.jsx\";\nimport { resolveMode, themeToCssVars } from \"../../lib/theme.js\";\nimport { cn } from \"../../lib/utils.js\";\nimport { Button } from \"../ui/button.js\";\nimport { ChatPanel, type ChatPanelProps } from \"./ChatPanel.js\";\n\nexport interface FrankieWidgetProps extends ChatPanelProps {\n position?: \"bottom-right\" | \"bottom-left\";\n /** Distance from the viewport edges, in pixels. */\n offset?: number;\n defaultOpen?: boolean;\n /** Host overlays should sit above the assistant. Override for your layer system. */\n zIndex?: number;\n /** Controlled mode: pass both to drive open state from the host app. */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Replace the floating launcher button. */\n renderLauncher?: (props: { open: boolean; toggle: () => void; label: string }) => React.ReactNode;\n}\n\n/**\n * The drop-in embed: a floating launcher plus the chat panel.\n *\n * Renders `position: fixed` at the document level, so it does not care what\n * layout the host page uses.\n */\nexport function FrankieWidget({\n position = \"bottom-right\",\n offset = 24,\n defaultOpen = false,\n zIndex = 20,\n open: controlledOpen,\n onOpenChange,\n renderLauncher,\n ...panelProps\n}: FrankieWidgetProps) {\n const { config } = useFrankie();\n const theme = useFrankieTheme();\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n const open = controlledOpen ?? uncontrolledOpen;\n\n const setOpen = (next: boolean) => {\n if (controlledOpen === undefined) setUncontrolledOpen(next);\n onOpenChange?.(next);\n };\n\n // Escape closes the panel, matching every other overlay on the host's page.\n useEffect(() => {\n if (!open) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") setOpen(false);\n };\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n\n const label = config?.branding.launcherLabel ?? \"Need a hand?\";\n const mode = resolveMode(theme?.mode);\n const side = position === \"bottom-right\" ? { right: offset } : { left: offset };\n\n return (\n <div\n className={cn(\"frankie-root frankie-widget\", mode === \"dark\" && \"dark\")}\n style={{ ...themeToCssVars(theme), position: \"fixed\", bottom: offset, ...side, zIndex, pointerEvents: \"none\" }}\n data-frankie-mode={mode}\n >\n <div className={cn(\"flex flex-col gap-3\", position === \"bottom-left\" ? \"items-start\" : \"items-end\")}>\n {open ? <div style={{ pointerEvents: \"auto\", maxHeight: \"calc(100dvh - 100px)\", overflow: \"hidden\" }}><ChatPanel {...panelProps} className={cn(\"frankie-widget-panel\", panelProps.className)} onClose={() => setOpen(false)} autoFocus /></div> : null}\n <div style={{ pointerEvents: \"auto\" }}>\n {renderLauncher ? (\n renderLauncher({ open, toggle: () => setOpen(!open), label })\n ) : (\n <Button\n size=\"icon\"\n className=\"size-12 rounded-full shadow-lg\"\n onClick={() => setOpen(!open)}\n aria-expanded={open}\n aria-label={open ? \"Close the assistant\" : label}\n title={label}\n >\n {open ? <X className=\"size-5\" /> : <MessageCircle className=\"size-5\" />}\n </Button>\n )}</div>\n </div>\n </div>\n );\n}\n","import type { WidgetTheme } from \"@frankieai/core\";\nimport type { CSSProperties } from \"react\";\n\n/**\n * Map a theme to the CSS custom properties the widget's styles read.\n *\n * Anything not set falls through to the defaults in `frankie.css`, which are\n * themselves shadcn/ui token names — so a host that already runs shadcn can\n * drop the stylesheet and the widget inherits their design system instead.\n */\nexport function themeToCssVars(theme: WidgetTheme | undefined): CSSProperties {\n if (!theme) return {};\n const vars: Record<string, string> = {};\n if (theme.primary) vars[\"--frankie-primary\"] = theme.primary;\n if (theme.primaryForeground) vars[\"--frankie-primary-foreground\"] = theme.primaryForeground;\n if (theme.background) vars[\"--frankie-background\"] = theme.background;\n if (theme.foreground) vars[\"--frankie-foreground\"] = theme.foreground;\n if (theme.muted) vars[\"--frankie-muted\"] = theme.muted;\n if (theme.border) vars[\"--frankie-border\"] = theme.border;\n if (theme.radius) vars[\"--frankie-radius\"] = `${theme.radius}rem`;\n if (theme.fontFamily) vars[\"--frankie-font\"] = theme.fontFamily;\n return vars as CSSProperties;\n}\n\n/** Resolve `mode: \"system\"` against the browser, so the widget can hard-set a class. */\nexport function resolveMode(mode: WidgetTheme[\"mode\"]): \"light\" | \"dark\" {\n if (mode === \"light\" || mode === \"dark\") return mode;\n if (typeof window === \"undefined\" || !window.matchMedia) return \"light\";\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\";\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/** shadcn/ui's class helper: conditional classes with Tailwind conflict resolution. */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\nexport const buttonVariants = cva(\n \"frankie-focus inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[var(--frankie-radius)] text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:opacity-90\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-muted\",\n outline: \"border border-border bg-background hover:bg-muted\",\n ghost: \"hover:bg-muted\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-[calc(var(--frankie-radius)-2px)] px-3 text-xs\",\n lg: \"h-10 px-6\",\n icon: \"size-9\",\n },\n },\n defaultVariants: { variant: \"default\", size: \"default\" },\n },\n);\n\nexport interface ButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nexport function Button({ className, variant, size, asChild = false, ...props }: ButtonProps) {\n const Comp = asChild ? Slot : \"button\";\n return <Comp className={cn(buttonVariants({ variant, size }), className)} {...props} />;\n}\n","\"use client\";\n\nimport { RotateCcw, X } from \"lucide-react\";\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { useFrankie, useFrankieTheme } from \"../../hooks/FrankieProvider.jsx\";\nimport { useFrankieChat } from \"../../hooks/useFrankieChat.js\";\nimport type { ChatMessage, ToolActivity } from \"../../lib/messages.js\";\nimport { resolveMode, themeToCssVars } from \"../../lib/theme.js\";\nimport { cn } from \"../../lib/utils.js\";\nimport { Avatar } from \"../ui/avatar.js\";\nimport { Button } from \"../ui/button.js\";\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from \"../ui/card.js\";\nimport { ScrollArea } from \"../ui/scroll-area.js\";\nimport { AgentContext } from \"./AgentContext.js\";\nimport { Composer } from \"./Composer.js\";\nimport { MessageBubble } from \"./MessageBubble.js\";\nimport { SuggestedPrompts } from \"./SuggestedPrompts.js\";\n\nexport interface ChatPanelProps {\n className?: string;\n /** Replace the header entirely, or pass `false` to drop it. */\n header?: ReactNode | false;\n /** Rendered under the composer — good for a \"powered by\" or a privacy note. */\n footer?: ReactNode;\n /** Shown before the first message, in place of the default greeting block. */\n emptyState?: ReactNode;\n /** Take over message rendering completely. */\n renderMessage?: (message: ChatMessage) => ReactNode;\n /** Take over the tool-activity rows. */\n renderTool?: (tool: ToolActivity) => ReactNode;\n placeholder?: string;\n /** Shows a close button in the header when provided. */\n onClose?: () => void;\n autoFocus?: boolean;\n /** Fill the parent instead of the fixed floating size — for full-page use. */\n fill?: boolean;\n}\n\nexport function ChatPanel({\n className,\n header,\n footer,\n emptyState,\n renderMessage,\n renderTool,\n placeholder,\n onClose,\n autoFocus,\n fill,\n}: ChatPanelProps) {\n const { config, configError, loading } = useFrankie();\n const theme = useFrankieTheme();\n const { messages, busy, restoring, error, send, stop, reset } = useFrankieChat();\n const scrollRef = useRef<HTMLDivElement>(null);\n\n const features = config?.features;\n const pickerModels = features?.modelPicker.enabled ? features.modelPicker.models : [];\n const [model, setModel] = useState<string | undefined>(undefined);\n\n // Follow the stream, but only while the reader is already near the bottom.\n useEffect(() => {\n const node = scrollRef.current;\n if (!node) return;\n const distanceFromBottom = node.scrollHeight - node.scrollTop - node.clientHeight;\n if (distanceFromBottom < 160) node.scrollTop = node.scrollHeight;\n }, [messages]);\n\n const name = config?.branding.name ?? \"Assistant\";\n const mode = resolveMode(theme?.mode);\n\n return (\n <Card\n className={cn(\n \"frankie-root frankie-chat-panel\",\n fill && \"frankie-chat-panel-fill\",\n fill ? \"h-full w-full rounded-none border-0 shadow-none\" : \"h-[32rem] w-[22rem] max-w-[calc(100vw-2rem)]\",\n mode === \"dark\" && \"dark\",\n className,\n )}\n style={themeToCssVars(theme)}\n data-frankie-mode={mode}\n >\n {header === false ? null : header !== undefined ? (\n header\n ) : (\n <CardHeader>\n <Avatar {...(config?.branding.avatarUrl ? { src: config.branding.avatarUrl } : {})} name={name} />\n <div className=\"min-w-0 flex-1\">\n <CardTitle>{name}</CardTitle>\n {config?.branding.tagline ? <CardDescription>{config.branding.tagline}</CardDescription> : null}\n </div>\n <Button size=\"icon\" variant=\"ghost\" onClick={reset} aria-label=\"Start a new conversation\" title=\"New conversation\">\n <RotateCcw />\n </Button>\n {onClose ? (\n <Button size=\"icon\" variant=\"ghost\" onClick={onClose} aria-label=\"Close\">\n <X />\n </Button>\n ) : null}\n </CardHeader>\n )}\n\n <AgentContext />\n <CardContent className=\"frankie-conversation-content\">\n <ScrollArea ref={scrollRef} className=\"frankie-transcript flex h-full flex-col gap-4 p-4\" aria-live=\"polite\">\n {configError ? (\n <div className=\"frankie-config-error\" role=\"alert\">\n <strong>Frankie couldn’t start</strong>\n <p>{configError}</p>\n <p>Refresh this page after checking the workspace’s allowed origin and sign-in settings.</p>\n </div>\n ) : loading ? (\n <p className=\"text-sm text-muted-foreground\">Starting Frankie…</p>\n ) : messages.length === 0 ? (\n (emptyState ?? (\n <div className=\"flex flex-col gap-4\">\n <p className=\"text-sm text-muted-foreground\">{config?.greeting}</p>\n <SuggestedPrompts prompts={config?.suggestedPrompts ?? []} onPick={send} disabled={busy} />\n </div>\n ))\n ) : (\n <div className=\"frankie-message-list flex flex-col gap-4\">\n {messages.map((message) =>\n renderMessage ? (\n <div key={message.id}>{renderMessage(message)}</div>\n ) : (\n <MessageBubble\n key={message.id}\n message={message}\n assistantName={name}\n {...(config?.branding.avatarUrl ? { avatarUrl: config.branding.avatarUrl } : {})}\n showToolActivity={config?.showToolActivity ?? true}\n {...(renderTool ? { renderTool } : {})}\n />\n ),\n )}\n </div>\n )}\n </ScrollArea>\n </CardContent>\n\n <CardFooter className=\"frankie-composer-footer flex flex-col gap-2\">\n {error ? <p className=\"w-full text-xs text-red-600 dark:text-red-400\">{error}</p> : null}\n <div className=\"w-full\">\n <Composer\n onSend={send}\n onStop={stop}\n busy={busy}\n disabled={loading || restoring || Boolean(configError)}\n {...(placeholder ? { placeholder } : {})}\n {...(autoFocus ? { autoFocus } : {})}\n {...(features?.attachments.enabled ? { attachments: features.attachments } : {})}\n {...(pickerModels.length\n ? { modelPicker: { models: pickerModels, value: model ?? pickerModels[0]?.id, onChange: setModel } }\n : {})}\n />\n </div>\n {footer}\n </CardFooter>\n </Card>\n );\n}\n","\"use client\";\n\nimport { cn } from \"../../lib/utils.js\";\n\nexport interface AvatarProps {\n src?: string;\n name: string;\n className?: string;\n}\n\n/** Image avatar with an initials fallback — no image request when `src` is absent. */\nexport function Avatar({ src, name, className }: AvatarProps) {\n const initials = name\n .split(/\\s+/)\n .slice(0, 2)\n .map((part) => part[0]?.toUpperCase() ?? \"\")\n .join(\"\");\n\n return (\n <span\n className={cn(\n \"inline-flex size-7 shrink-0 items-center justify-center overflow-hidden rounded-full bg-primary text-[0.625rem] font-semibold text-primary-foreground\",\n className,\n )}\n aria-hidden=\"true\"\n >\n {src ? <img src={src} alt=\"\" className=\"size-full object-cover\" /> : initials}\n </span>\n );\n}\n","\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\nexport function Card({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn(\n \"flex flex-col rounded-[calc(var(--frankie-radius)+4px)] border border-border bg-background text-foreground shadow-lg\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport function CardHeader({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"flex items-center gap-3 border-b border-border px-4 py-3\", className)} {...props} />;\n}\n\nexport function CardTitle({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"text-sm font-semibold leading-tight\", className)} {...props} />;\n}\n\nexport function CardDescription({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"text-xs text-muted-foreground\", className)} {...props} />;\n}\n\nexport function CardContent({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"flex-1 overflow-hidden\", className)} {...props} />;\n}\n\nexport function CardFooter({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"border-t border-border p-3\", className)} {...props} />;\n}\n","\"use client\";\n\nimport { forwardRef, type HTMLAttributes } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * A plain overflow container rather than Radix's ScrollArea: the widget lives\n * inside someone else's page, and a native scroller inherits their scrollbar\n * behaviour instead of fighting it.\n */\nexport const ScrollArea = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(\n function ScrollArea({ className, ...props }, ref) {\n return <div ref={ref} className={cn(\"frankie-scroll overflow-y-auto overscroll-contain\", className)} {...props} />;\n },\n);\n","\"use client\";\nimport { ArrowUpRight, Sparkles } from \"lucide-react\";\nimport { useFrankie } from \"../../hooks/FrankieProvider.jsx\";\nimport { useFrankieChat } from \"../../hooks/useFrankieChat.js\";\n\n/** Reports server-confirmed skills for the current turn; never implies drafts are active. */\nexport function AgentContext() {\n const { loading, configError } = useFrankie();\n const { loadedSkills, busy, restoring, error } = useFrankieChat();\n const status = configError || error ? \"Unavailable\" : loading || restoring ? \"Connecting\" : busy && loadedSkills === null ? \"Checking\" : loadedSkills?.length ? \"Active\" : loadedSkills ? \"Tools only\" : \"Ready\";\n return <div className=\"frankie-agent-context-wrap\">\n <details className=\"frankie-agent-context\">\n <summary aria-label=\"Agent context\"><Sparkles size={17} aria-hidden=\"true\" /><span>Agent context</span><span className=\"frankie-context-count\">{loadedSkills === null ? \"Not checked\" : `${loadedSkills.length} ${loadedSkills.length === 1 ? \"skill\" : \"skills\"}`}</span><span className=\"frankie-context-status\" data-active={status === \"Active\"}><i aria-hidden=\"true\" />{status}</span><ArrowUpRight size={15} aria-hidden=\"true\" /></summary>\n <div className=\"frankie-context-detail\">\n <strong>{loadedSkills === null ? \"Skills are checked when you send a message\" : loadedSkills.length ? `${loadedSkills.length} ${loadedSkills.length === 1 ? \"skill\" : \"skills\"} loaded` : \"No skills loaded for this turn\"}</strong>\n {loadedSkills?.length ? <ul>{loadedSkills.map(skill => <li key={skill.id}><span>{skill.name}</span><small>v{skill.revision}</small></li>)}</ul> : <p>Frankie can use the tools approved for this workspace. Drafts and skills without available tools are not loaded.</p>}\n <p>Published skills and updates are checked on every message. Only approved, available tools can run.</p>\n </div>\n </details>\n <span className=\"frankie-sr-only\" role=\"status\">{loadedSkills === null ? status : `${loadedSkills.length} ${loadedSkills.length === 1 ? \"skill\" : \"skills\"} loaded. ${status}.`}</span>\n </div>;\n}\n","\"use client\";\n\nimport { ArrowUp, Paperclip, Plus, Square, X } from \"lucide-react\";\nimport { useCallback, useEffect, useRef, useState, type KeyboardEvent } from \"react\";\nimport type { ChatAttachment } from \"@frankieai/core\";\nimport { Button } from \"../ui/button.js\";\nimport { Textarea } from \"../ui/textarea.js\";\n\nexport interface ComposerAttachmentsConfig {\n enabled: boolean;\n /** Accepted MIME patterns, e.g. \"image/*\". */\n accept: string[];\n maxCount: number;\n maxMb: number;\n}\n\nexport interface ComposerModelPicker {\n models: { id: string; label: string }[];\n value?: string;\n onChange: (id: string) => void;\n}\n\nexport interface ComposerProps {\n onSend: (text: string, opts?: { attachments?: ChatAttachment[]; model?: string }) => void;\n onStop: () => void;\n busy: boolean;\n placeholder?: string;\n disabled?: boolean;\n autoFocus?: boolean;\n /** Enables the attach button when provided and `enabled`. */\n attachments?: ComposerAttachmentsConfig;\n /** Enables a model dropdown when provided with at least one model. */\n modelPicker?: ComposerModelPicker;\n}\n\ninterface PickedFile extends ChatAttachment {\n id: string;\n}\n\nconst MAX_ROWS_PX = 140;\n\nexport function Composer({ onSend, onStop, busy, placeholder, disabled, autoFocus, attachments, modelPicker }: ComposerProps) {\n const [value, setValue] = useState(\"\");\n const [files, setFiles] = useState<PickedFile[]>([]);\n const [fileError, setFileError] = useState<string | undefined>(undefined);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const canAttach = Boolean(attachments?.enabled);\n const models = modelPicker?.models ?? [];\n\n // Grow with the content up to a cap, then scroll.\n useEffect(() => {\n const node = textareaRef.current;\n if (!node) return;\n node.style.height = \"auto\";\n node.style.height = `${Math.min(node.scrollHeight, MAX_ROWS_PX)}px`;\n }, [value]);\n\n const addFiles = useCallback(\n async (list: FileList | null) => {\n if (!list || !attachments) return;\n setFileError(undefined);\n const room = attachments.maxCount - files.length;\n const chosen = Array.from(list).slice(0, Math.max(0, room));\n if (Array.from(list).length > room) setFileError(`You can attach up to ${attachments.maxCount} file(s).`);\n\n const next: PickedFile[] = [];\n for (const file of chosen) {\n if (!mimeAccepted(file.type || \"application/octet-stream\", attachments.accept)) {\n setFileError(`Files of type ${file.type || \"unknown\"} aren't allowed.`);\n continue;\n }\n if (file.size > attachments.maxMb * 1024 * 1024) {\n setFileError(`Each file must be under ${attachments.maxMb} MB.`);\n continue;\n }\n try {\n next.push({\n id: `${file.name}-${file.size}-${Math.random().toString(36).slice(2, 7)}`,\n name: file.name,\n mimeType: file.type || \"application/octet-stream\",\n data: await readAsBase64(file),\n });\n } catch {\n setFileError(\"Couldn't read that file.\");\n }\n }\n if (next.length) setFiles((current) => [...current, ...next]);\n },\n [attachments, files.length],\n );\n\n const removeFile = (id: string) => setFiles((current) => current.filter((file) => file.id !== id));\n\n const submit = useCallback(() => {\n const text = value.trim();\n if ((!text && files.length === 0) || busy || disabled) return;\n setValue(\"\");\n const attached = files.map(({ name, mimeType, data }) => ({ name, mimeType, data }));\n setFiles([]);\n setFileError(undefined);\n onSend(text, {\n ...(attached.length ? { attachments: attached } : {}),\n ...(modelPicker?.value ? { model: modelPicker.value } : {}),\n });\n }, [busy, disabled, files, modelPicker?.value, onSend, value]);\n\n const onKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n if (event.key === \"Enter\" && !event.shiftKey && !event.nativeEvent.isComposing) {\n event.preventDefault();\n submit();\n }\n };\n\n const nothingToSend = value.trim().length === 0 && files.length === 0;\n\n return (\n <form\n className=\"frankie-composer flex flex-col gap-2\"\n onSubmit={(event) => {\n event.preventDefault();\n submit();\n }}\n >\n {files.length > 0 ? (\n <div className=\"flex flex-wrap gap-2\">\n {files.map((file) => (\n <span\n key={file.id}\n className=\"inline-flex max-w-[14rem] items-center gap-1.5 rounded-[var(--frankie-radius)] border border-border bg-muted px-2 py-1 text-xs\"\n >\n <Paperclip className=\"size-3 shrink-0 opacity-70\" />\n <span className=\"truncate\">{file.name}</span>\n <button\n type=\"button\"\n onClick={() => removeFile(file.id)}\n aria-label={`Remove ${file.name}`}\n className=\"frankie-focus shrink-0 opacity-60 hover:opacity-100\"\n >\n <X className=\"size-3\" />\n </button>\n </span>\n ))}\n </div>\n ) : null}\n\n {fileError ? <p className=\"text-xs text-red-600 dark:text-red-400\">{fileError}</p> : null}\n\n <div className=\"frankie-composer-controls flex items-end gap-2\">\n {canAttach ? (\n <>\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n hidden\n accept={attachments?.accept.join(\",\")}\n onChange={(event) => {\n void addFiles(event.target.files);\n event.target.value = \"\";\n }}\n />\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"outline\"\n disabled={disabled || files.length >= (attachments?.maxCount ?? 0)}\n onClick={() => fileInputRef.current?.click()}\n aria-label=\"Attach files\"\n title=\"Attach files\"\n >\n <Plus />\n </Button>\n </>\n ) : null}\n\n <Textarea\n ref={textareaRef}\n rows={1}\n value={value}\n disabled={disabled}\n autoFocus={autoFocus}\n onChange={(event) => setValue(event.target.value)}\n onKeyDown={onKeyDown}\n placeholder={placeholder ?? \"Ask anything…\"}\n aria-label=\"Message\"\n />\n\n {models.length > 0 ? (\n <select\n value={modelPicker?.value ?? models[0]?.id}\n onChange={(event) => modelPicker?.onChange(event.target.value)}\n disabled={disabled}\n aria-label=\"Model\"\n className=\"frankie-focus h-9 max-w-[8rem] rounded-[var(--frankie-radius)] border border-border bg-background px-2 text-sm\"\n >\n {models.map((model) => (\n <option key={model.id} value={model.id}>\n {model.label}\n </option>\n ))}\n </select>\n ) : null}\n\n {busy ? (\n <Button type=\"button\" size=\"icon\" variant=\"outline\" onClick={onStop} aria-label=\"Stop\">\n <Square />\n </Button>\n ) : (\n <Button type=\"submit\" size=\"icon\" disabled={disabled || nothingToSend} aria-label=\"Send\">\n <ArrowUp />\n </Button>\n )}\n </div>\n </form>\n );\n}\n\nfunction mimeAccepted(mimeType: string, accept: string[]): boolean {\n return accept.some((pattern) =>\n pattern.endsWith(\"/*\") ? mimeType.startsWith(pattern.slice(0, -1)) : pattern === mimeType,\n );\n}\n\n/** Read a File to a base64 string (no data-URL prefix), for the wire protocol. */\nfunction readAsBase64(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const result = String(reader.result);\n const comma = result.indexOf(\",\");\n resolve(comma >= 0 ? result.slice(comma + 1) : result);\n };\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n}\n\n","\"use client\";\n\nimport { forwardRef, type TextareaHTMLAttributes } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** `forwardRef` rather than React 19's ref-as-prop, so React 18 hosts work too. */\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaHTMLAttributes<HTMLTextAreaElement>>(\n function Textarea({ className, ...props }, ref) {\n return (\n <textarea\n ref={ref}\n className={cn(\n \"frankie-focus flex min-h-[2.25rem] w-full resize-none rounded-[var(--frankie-radius)] border border-border bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n {...props}\n />\n );\n },\n);\n","\"use client\";\n\nimport { Check, Copy, Paperclip } from \"lucide-react\";\nimport \"./message-actions.css\";\nimport { useState, type ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\nimport type { ChatMessage, ToolActivity } from \"../../lib/messages.js\";\nimport { Avatar } from \"../ui/avatar.js\";\nimport { Markdown } from \"./Markdown.js\";\nimport { ToolActivityList } from \"./ToolActivityList.js\";\n\nexport interface MessageBubbleProps {\n message: ChatMessage;\n assistantName: string;\n avatarUrl?: string;\n showToolActivity: boolean;\n renderTool?: (tool: ToolActivity) => ReactNode;\n}\n\nexport function MessageBubble({\n message,\n assistantName,\n avatarUrl,\n showToolActivity,\n renderTool,\n}: MessageBubbleProps) {\n if (message.role === \"user\") {\n return (\n <div className=\"frankie-user-message flex flex-col items-end gap-1\">\n {message.attachments?.length ? (\n <div className=\"flex max-w-[85%] flex-wrap justify-end gap-1\">\n {message.attachments.map((file, index) => (\n <span\n key={`${file.name}-${index}`}\n className=\"inline-flex max-w-[12rem] items-center gap-1 rounded-[var(--frankie-radius)] border border-border bg-muted px-2 py-1 text-xs\"\n >\n <Paperclip className=\"size-3 shrink-0 opacity-70\" />\n <span className=\"truncate\">{file.name}</span>\n </span>\n ))}\n </div>\n ) : null}\n {message.text ? (\n <div className=\"flex max-w-[85%] items-end gap-1\">\n <div className=\"frankie-user-bubble rounded-[var(--frankie-radius)] bg-primary px-3 py-2 text-sm text-primary-foreground\">{message.text}</div>\n <MessageCopyButton text={message.text} />\n </div>\n ) : null}\n </div>\n );\n }\n\n const empty = message.text.length === 0 && message.tools.length === 0;\n\n return (\n <div className=\"frankie-assistant-message flex gap-2\">\n <div className=\"frankie-assistant-actions mt-0.5 flex shrink-0 flex-col items-center gap-1\">\n <Avatar {...(avatarUrl ? { src: avatarUrl } : {})} name={assistantName} />\n {message.text ? <MessageCopyButton text={message.text} /> : null}\n </div>\n <div className=\"frankie-assistant-content min-w-0 max-w-[85%]\">\n {message.status === \"error\" ? (\n <p className=\"rounded-[var(--frankie-radius)] bg-red-500/10 px-3 py-2 text-sm text-red-600 dark:text-red-400\">\n {message.error}\n </p>\n ) : empty && message.status === \"streaming\" ? (\n <TypingDots />\n ) : (\n <Markdown text={message.text} className=\"text-sm\" />\n )}\n {showToolActivity ? (\n <ToolActivityList tools={message.tools} {...(renderTool ? { renderTool } : {})} />\n ) : null}\n </div>\n </div>\n );\n}\n\nfunction MessageCopyButton({ text }: { text: string }) {\n const [copied, setCopied] = useState(false);\n const copy = async () => {\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n window.setTimeout(() => setCopied(false), 1500);\n } catch { /* Clipboard access can be disabled by an embedding host. */ }\n };\n return <button type=\"button\" onClick={() => void copy()} className=\"frankie-message-copy inline-flex size-8 shrink-0 items-center justify-center rounded-md border border-transparent text-muted-foreground transition hover:border-border hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary\" aria-label={copied ? \"Copied\" : \"Copy message\"} title={copied ? \"Copied\" : \"Copy message\"}>{copied ? <Check className=\"size-3.5\" aria-hidden=\"true\" /> : <Copy className=\"size-3.5\" aria-hidden=\"true\" />}</button>;\n}\n\nexport function TypingDots() {\n return (\n <span className=\"frankie-thinking inline-flex items-center gap-1 py-2\" role=\"status\" aria-label=\"Thinking\">\n <span className=\"frankie-thinking-label\">Thinking</span>\n {[0, 1, 2].map((index) => (\n <span\n key={index}\n className={cn(\"size-1.5 animate-pulse rounded-full bg-muted-foreground\")}\n style={{ animationDelay: `${index * 150}ms` }}\n />\n ))}\n </span>\n );\n}\n\n","\"use client\";\n\nimport { Fragment, type ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * A deliberately small Markdown subset — paragraphs, lists, fenced code, bold,\n * italic, inline code and links.\n *\n * Everything is rendered as React elements; nothing goes through\n * `dangerouslySetInnerHTML`. Model output lands in someone else's production\n * page, so it is never trusted as markup.\n */\nexport function Markdown({ text, className }: { text: string; className?: string }) {\n return <div className={cn(\"frankie-prose\", className)}>{renderBlocks(text)}</div>;\n}\n\nfunction renderBlocks(text: string): ReactNode[] {\n const lines = text.split(\"\\n\");\n const blocks: ReactNode[] = [];\n let paragraph: string[] = [];\n let list: { ordered: boolean; items: string[] } | null = null;\n let code: { lang: string; lines: string[] } | null = null;\n\n const flushParagraph = () => {\n if (paragraph.length === 0) return;\n blocks.push(<p key={`p${blocks.length}`}>{renderInline(paragraph.join(\" \"))}</p>);\n paragraph = [];\n };\n const flushList = () => {\n if (!list) return;\n const items = list.items.map((item, index) => <li key={index}>{renderInline(item)}</li>);\n blocks.push(list.ordered ? <ol key={`l${blocks.length}`}>{items}</ol> : <ul key={`l${blocks.length}`}>{items}</ul>);\n list = null;\n };\n\n for (const line of lines) {\n const fence = /^```(\\w*)\\s*$/.exec(line);\n if (fence) {\n if (code) {\n blocks.push(\n <pre key={`c${blocks.length}`}>\n <code>{code.lines.join(\"\\n\")}</code>\n </pre>,\n );\n code = null;\n } else {\n flushParagraph();\n flushList();\n code = { lang: fence[1] ?? \"\", lines: [] };\n }\n continue;\n }\n if (code) {\n code.lines.push(line);\n continue;\n }\n\n const bullet = /^\\s*[-*+]\\s+(.*)$/.exec(line);\n const ordered = /^\\s*\\d+[.)]\\s+(.*)$/.exec(line);\n if (bullet ?? ordered) {\n flushParagraph();\n const isOrdered = Boolean(ordered);\n if (!list || list.ordered !== isOrdered) {\n flushList();\n list = { ordered: isOrdered, items: [] };\n }\n list.items.push((ordered?.[1] ?? bullet?.[1]) ?? \"\");\n continue;\n }\n\n if (line.trim() === \"\") {\n flushParagraph();\n flushList();\n continue;\n }\n\n const heading = /^#{1,6}\\s+(.*)$/.exec(line);\n if (heading) {\n flushParagraph();\n flushList();\n blocks.push(<p key={`h${blocks.length}`} className=\"font-semibold\">{renderInline(heading[1] ?? \"\")}</p>);\n continue;\n }\n\n flushList();\n paragraph.push(line.trim());\n }\n\n if (code) {\n blocks.push(\n <pre key={`c${blocks.length}`}>\n <code>{code.lines.join(\"\\n\")}</code>\n </pre>,\n );\n }\n flushParagraph();\n flushList();\n return blocks;\n}\n\nconst INLINE = /(\\*\\*[^*]+\\*\\*|`[^`]+`|\\[[^\\]]+\\]\\((?:https?:\\/\\/|\\/)[^)\\s]+\\)|\\bhttps?:\\/\\/[^\\s<>()]+)/g;\n\nfunction renderInline(text: string): ReactNode[] {\n const nodes: ReactNode[] = [];\n let lastIndex = 0;\n\n for (const match of text.matchAll(INLINE)) {\n const token = match[0];\n const start = match.index;\n if (start > lastIndex) nodes.push(text.slice(lastIndex, start));\n nodes.push(<Fragment key={start}>{renderToken(token)}</Fragment>);\n lastIndex = start + token.length;\n }\n\n if (lastIndex < text.length) nodes.push(text.slice(lastIndex));\n return nodes;\n}\n\nfunction renderToken(token: string): ReactNode {\n if (token.startsWith(\"**\")) return <strong>{token.slice(2, -2)}</strong>;\n if (token.startsWith(\"`\")) return <code>{token.slice(1, -1)}</code>;\n\n const link = /^\\[([^\\]]+)\\]\\(([^)]+)\\)$/.exec(token);\n const href = link ? (link[2] ?? \"\") : token;\n const label = link ? (link[1] ?? \"\") : token;\n\n // Only http(s) and same-site paths become links; anything else stays text,\n // so a model can never emit a `javascript:` href into the host page.\n if (!/^(https?:\\/\\/|\\/)/.test(href)) return token;\n return (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer nofollow\">\n {label}\n </a>\n );\n}\n","\"use client\";\n\nimport { Check, ChevronDown, Loader2, ShieldAlert, X } from \"lucide-react\";\nimport { Badge } from \"../ui/badge.js\";\nimport type { ToolActivity } from \"../../lib/messages.js\";\n\nexport interface ToolActivityListProps {\n tools: ToolActivity[];\n /** Replace the default row rendering entirely. */\n renderTool?: (tool: ToolActivity) => React.ReactNode;\n}\n\n/** The \"what the assistant is doing\" strip under a streaming answer. */\nexport function ToolActivityList({ tools, renderTool }: ToolActivityListProps) {\n if (tools.length === 0) return null;\n const running = tools.some((tool) => tool.status === \"running\");\n return (\n <details className=\"frankie-tool-activity mt-2\" open={running}>\n <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\">\n <ChevronDown className=\"frankie-tool-chevron size-3.5 transition-transform\" aria-hidden=\"true\" />\n <span>{running ? \"Working\" : \"Activity\"}</span>\n <span className=\"text-[11px]\">· {tools.length} tool call{tools.length === 1 ? \"\" : \"s\"}</span>\n </summary>\n <ul className=\"mt-1 flex flex-col gap-1 border-l border-border pl-2\">{tools.map((tool) => <li key={tool.id}>{renderTool ? renderTool(tool) : <ToolActivityRow tool={tool} />}</li>)}</ul>\n </details>\n );\n}\n\nexport function ToolActivityRow({ tool }: { tool: ToolActivity }) {\n return (\n <Badge variant={badgeVariant(tool.status)} title={tool.detail ?? tool.name}>\n <ToolIcon status={tool.status} />\n <span className=\"truncate\">{tool.label}</span>\n </Badge>\n );\n}\n\nfunction ToolIcon({ status }: { status: ToolActivity[\"status\"] }) {\n switch (status) {\n case \"running\":\n return <Loader2 className=\"size-3 animate-spin\" aria-hidden=\"true\" />;\n case \"done\":\n return <Check className=\"size-3\" aria-hidden=\"true\" />;\n case \"denied\":\n return <ShieldAlert className=\"size-3\" aria-hidden=\"true\" />;\n default:\n return <X className=\"size-3\" aria-hidden=\"true\" />;\n }\n}\n\nfunction badgeVariant(status: ToolActivity[\"status\"]): \"default\" | \"success\" | \"danger\" | \"outline\" {\n if (status === \"done\") return \"success\";\n if (status === \"failed\") return \"danger\";\n if (status === \"denied\") return \"outline\";\n return \"default\";\n}\n","\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\nconst badgeVariants = cva(\n \"inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[0.6875rem] font-medium\",\n {\n variants: {\n variant: {\n default: \"border-transparent bg-muted text-muted-foreground\",\n success: \"border-transparent bg-emerald-500/10 text-emerald-600 dark:text-emerald-400\",\n danger: \"border-transparent bg-red-500/10 text-red-600 dark:text-red-400\",\n outline: \"border-border text-muted-foreground\",\n },\n },\n defaultVariants: { variant: \"default\" },\n },\n);\n\nexport function Badge({\n className,\n variant,\n ...props\n}: HTMLAttributes<HTMLSpanElement> & VariantProps<typeof badgeVariants>) {\n return <span className={cn(badgeVariants({ variant }), className)} {...props} />;\n}\n","\"use client\";\n\nimport { Button } from \"../ui/button.js\";\n\nexport function SuggestedPrompts({\n prompts,\n onPick,\n disabled,\n}: {\n prompts: string[];\n onPick: (prompt: string) => void;\n disabled?: boolean;\n}) {\n if (prompts.length === 0) return null;\n return (\n <div className=\"flex flex-wrap gap-2\">\n {prompts.map((prompt) => (\n <Button\n key={prompt}\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={disabled}\n onClick={() => onPick(prompt)}\n >\n {prompt}\n </Button>\n ))}\n </div>\n );\n}\n","\"use client\";\n\nimport type { CSSProperties } from \"react\";\nimport { useFrankieTheme } from \"../../hooks/FrankieProvider.jsx\";\nimport { resolveMode, themeToCssVars } from \"../../lib/theme.js\";\nimport { cn } from \"../../lib/utils.js\";\nimport { ChatPanel, type ChatPanelProps } from \"./ChatPanel.js\";\n\nexport interface FrankieInlineProps extends ChatPanelProps {\n /** Extra styles on the filling wrapper — e.g. a `maxWidth` to centre the column. */\n style?: CSSProperties;\n}\n\n/**\n * Full-page (or any-container) chat: the panel fills its parent instead of\n * floating in a corner. Drop it into a route or a sized element — it brings its\n * own theme root, so it styles correctly wherever it lands.\n *\n * <div style={{ height: \"100dvh\" }}>\n * <FrankieProvider …><FrankieInline /></FrankieProvider>\n * </div>\n */\nexport function FrankieInline({ className, style, ...panelProps }: FrankieInlineProps) {\n const theme = useFrankieTheme();\n const mode = resolveMode(theme?.mode);\n return (\n <div\n className={cn(\"frankie-root frankie-inline\", mode === \"dark\" && \"dark\", className)}\n style={{ ...themeToCssVars(theme), display: \"flex\", height: \"100%\", width: \"100%\", ...style }}\n data-frankie-mode={mode}\n >\n <ChatPanel {...panelProps} fill />\n </div>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef, useState, type CSSProperties } from \"react\";\nimport { History, Menu, Plus, Settings, X } from \"lucide-react\";\nimport type { FrankieProviderProps } from \"../../hooks/FrankieProvider.jsx\";\nimport { FrankieProvider, useFrankie, useFrankieTheme } from \"../../hooks/FrankieProvider.jsx\";\nimport { useFrankieChat } from \"../../hooks/useFrankieChat.js\";\nimport { themeToCssVars, resolveMode } from \"../../lib/theme.js\";\nimport type { ChatConversation } from \"../../lib/client.js\";\nimport { FrankieInline } from \"./FrankieInline.js\";\nimport type { ChatPanelProps } from \"./ChatPanel.js\";\n\nexport interface FrankieChatPageProps extends Omit<FrankieProviderProps, \"children\">,\n Pick<ChatPanelProps, \"header\" | \"footer\" | \"emptyState\" | \"renderMessage\" | \"renderTool\" | \"placeholder\" | \"autoFocus\"> {\n className?: string;\n style?: CSSProperties;\n /** Include the built-in conversation sidebar. Defaults to true. */\n showHistory?: boolean;\n /** Optional host navigation, e.g. a Back to dashboard link. */\n navigation?: React.ReactNode;\n}\n\nfunction PageEmptyState() {\n const { config } = useFrankie();\n const { send, busy, restoring } = useFrankieChat();\n const name = config?.branding.name ?? \"Frankie\";\n return <section className=\"frankie-page-empty\" aria-label=\"Start a conversation\">\n <span className=\"frankie-page-avatar\" aria-hidden>{name.trim().slice(0, 1).toUpperCase()}</span>\n <div><p className=\"frankie-page-kicker\">Your product assistant</p><h1>How can I help?</h1><p>{config?.greeting ?? \"Ask a question or choose a task to get started.\"}</p></div>\n <div className=\"frankie-page-prompts\">{config?.suggestedPrompts?.slice(0, 3).map(prompt => <button key={prompt} type=\"button\" disabled={busy || restoring} onClick={() => void send(prompt)}><strong>{prompt}</strong><b aria-hidden>↗</b></button>)}</div>\n </section>;\n}\n\nfunction PageChrome({ showHistory, navigation, currentId, onSelect, onNew, ...panel }: Pick<FrankieChatPageProps, \"header\" | \"footer\" | \"emptyState\" | \"renderMessage\" | \"renderTool\" | \"placeholder\" | \"autoFocus\" | \"navigation\"> & { showHistory: boolean; currentId: string; onSelect: (id: string) => void; onNew: () => void }) {\n const { client, config } = useFrankie();\n const { busy, messages } = useFrankieChat();\n const theme = useFrankieTheme();\n const [conversations, setConversations] = useState<ChatConversation[]>([]);\n const [historyError, setHistoryError] = useState(\"\");\n const [historyLoading, setHistoryLoading] = useState(false);\n const [drawerOpen, setDrawerOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const dialog = useRef<HTMLDialogElement>(null);\n const menu = useRef<HTMLButtonElement>(null);\n const requestVersion = useRef(0);\n const refresh = useCallback(async () => {\n if (!showHistory || !config || config.allowAnonymous) { setHistoryError(\"\"); return; }\n const version = ++requestVersion.current;\n setHistoryLoading(true); setHistoryError(\"\");\n try { const items = await client.listConversations(); if (version === requestVersion.current) setConversations(items); }\n catch { if (version === requestVersion.current) setHistoryError(\"History couldn’t load. Check your sign-in and try again.\"); }\n finally { if (version === requestVersion.current) setHistoryLoading(false); }\n }, [client, showHistory, config?.allowAnonymous]);\n useEffect(() => { if (!busy) void refresh(); return () => { requestVersion.current++; }; }, [refresh, busy]);\n useEffect(() => {\n const node = dialog.current;\n if (drawerOpen) { node?.showModal?.(); }\n else { node?.close?.(); }\n }, [drawerOpen]);\n const close = () => { setDrawerOpen(false); menu.current?.focus(); };\n const select = (id: string) => { if (!busy) { onSelect(id); close(); } };\n const history = <>\n <div className=\"frankie-history-heading\"><strong>Conversations</strong><button type=\"button\" className=\"frankie-mobile-only\" aria-label=\"Close conversations\" onClick={close}><X size={18} /></button></div>\n <button type=\"button\" className=\"frankie-new-chat\" disabled={busy} onClick={() => { onNew(); close(); }}><Plus size={17} />New chat</button>\n <label className=\"frankie-history-search\"><span>Search conversations</span><input type=\"search\" placeholder=\"Search chats…\" value={query} onChange={event => setQuery(event.target.value)} /></label>\n <nav className=\"frankie-history-list\" aria-label=\"Conversations\">{conversations.filter(item => item.title.toLowerCase().includes(query.toLowerCase())).map(item => <button type=\"button\" key={item.id} aria-current={item.id === currentId ? \"page\" : undefined} disabled={busy} onClick={() => select(item.id)}><span>{item.title}</span><small>{new Date(item.updatedAt).toLocaleDateString()}</small></button>)}</nav>\n {historyLoading ? <p role=\"status\">Loading history…</p> : historyError ? <p role=\"status\">{historyError}<button type=\"button\" onClick={() => void refresh()}>Try again</button></p> : !conversations.length ? <p>{config?.allowAnonymous ? \"Sign in to sync conversations across devices.\" : \"Your conversations will appear here.\"}</p> : null}\n {navigation ? <div className=\"frankie-host-navigation\">{navigation}</div> : null}\n </>;\n return <div className={\"frankie-page-shell\" + (resolveMode(theme?.mode) === \"dark\" ? \" dark\" : \"\")} style={themeToCssVars(theme)}>\n {showHistory ? <aside className=\"frankie-history-desktop\">{history}</aside> : null}\n <div className=\"frankie-page-main\">\n <header className=\"frankie-page-header\"><div>{showHistory ? <button type=\"button\" className=\"frankie-mobile-only\" ref={menu} aria-label=\"Open conversations\" aria-haspopup=\"dialog\" aria-expanded={drawerOpen} onClick={() => setDrawerOpen(true)}><Menu size={20} /></button> : null}<strong className=\"frankie-thread-title\">{conversations.find(item => item.id === currentId)?.title ?? messages.find(message => message.role === \"user\")?.text ?? \"New chat\"}</strong></div><div>\n <button type=\"button\" disabled={busy} onClick={onNew} aria-label=\"Start a new conversation\"><Plus size={16} /><span>New chat</span></button>\n <details className=\"frankie-chat-settings\"><summary aria-label=\"Chat settings\"><Settings size={19} /></summary><div><strong>Chat settings</strong><p>History syncs automatically for signed-in users.</p><button type=\"button\" onClick={() => void refresh()} disabled={historyLoading || !showHistory}><History size={16} />Refresh history</button><small>Skills are checked at the start of each message.</small></div></details>\n </div></header>\n <div className=\"frankie-page-canvas\"><FrankieInline {...panel} header={panel.header ?? false} emptyState={panel.emptyState ?? <PageEmptyState />} /></div>\n </div>\n {showHistory ? <dialog ref={dialog} className=\"frankie-history-dialog frankie-root\" aria-label=\"Chat conversations\" style={themeToCssVars(theme)} onCancel={close} onClick={event => { if (event.target === event.currentTarget) close(); }}><aside>{history}</aside></dialog> : null}\n </div>;\n}\n\n/** Reusable product chat with one shared conversation state and scoped styling. */\nexport function FrankieChatPage({ className, style, header, footer, emptyState, renderMessage, renderTool, placeholder, autoFocus, showHistory = true, navigation, ...provider }: FrankieChatPageProps) {\n const [id, setId] = useState(() => provider.conversationId ?? crypto.randomUUID());\n const onNew = () => setId(crypto.randomUUID());\n return <div className={[\"frankie-root\", \"frankie-chat-page\", className].filter(Boolean).join(\" \")} style={{ height: \"100%\", minHeight: \"min(36rem, 100dvh)\", width: \"100%\", ...style }}>\n <FrankieProvider {...provider} conversationId={id} storageNamespace={(provider.storageNamespace ?? \"frankie.\" + provider.publishableKey) + \".\" + id}>\n <PageChrome showHistory={showHistory} navigation={navigation} currentId={id} onSelect={setId} onNew={onNew} header={header} footer={footer} emptyState={emptyState} renderMessage={renderMessage} renderTool={renderTool} placeholder={placeholder} autoFocus={autoFocus} />\n </FrankieProvider>\n </div>;\n}\n","\"use client\";\n\nimport { cn } from \"../../lib/utils.js\";\n\nexport function Separator({ className }: { className?: string }) {\n return <div role=\"separator\" className={cn(\"h-px w-full bg-border\", className)} />;\n}\n"],"mappings":"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","names":["createContext","useContext","useEffect","useRef","useState","createContext","useRef","useState","useEffect","useContext","X","useEffect","useState","jsx","X","useEffect","useRef","useState","jsx","jsx","jsx","ScrollArea","jsx","useCallback","useEffect","useRef","useState","forwardRef","jsx","forwardRef","Textarea","jsx","jsxs","useState","useRef","useEffect","useCallback","Check","Paperclip","useState","Fragment","jsx","Fragment","X","cva","jsx","cva","jsx","jsxs","X","jsx","jsxs","Paperclip","useState","Check","jsx","jsx","jsxs","useRef","useState","useEffect","X","jsx","jsxs","useState","useEffect","X","jsx","useCallback","useEffect","useRef","useState","Plus","X","Fragment","jsx","jsxs","useState","useRef","useCallback","useEffect","X","Plus","jsx"]}
1
+ {"version":3,"sources":["../src/hooks/FrankieProvider.tsx","../src/lib/client.ts","../src/hooks/useFrankieChat.ts","../src/lib/messages.ts","../src/components/chat/FrankieWidget.tsx","../src/lib/theme.ts","../src/lib/utils.ts","../src/components/ui/button.tsx","../src/components/chat/ChatPanel.tsx","../src/components/ui/avatar.tsx","../src/components/ui/card.tsx","../src/components/ui/scroll-area.tsx","../src/components/chat/AgentContext.tsx","../src/components/chat/Composer.tsx","../src/components/ui/textarea.tsx","../src/components/chat/MessageBubble.tsx","../src/components/chat/Markdown.tsx","../src/components/chat/ToolActivityList.tsx","../src/components/ui/badge.tsx","../src/components/chat/SuggestedPrompts.tsx","../src/components/chat/FrankieInline.tsx","../src/components/chat/FrankieChatPage.tsx","../src/components/ui/separator.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport type { PublicWidgetConfig, WidgetTheme } from \"@frankieai/core\";\nimport { FrankieClient, type FrankieClientOptions, type PageContext } from \"../lib/client.js\";\nimport { FrankieChatContext, useFrankieChatState } from \"./useFrankieChat.js\";\n\nexport interface FrankieProviderProps extends FrankieClientOptions {\n children: ReactNode;\n context?: PageContext;\n theme?: WidgetTheme;\n config?: PublicWidgetConfig;\n}\n\ninterface FrankieContextValue {\n client: FrankieClient;\n config?: PublicWidgetConfig;\n configError?: string;\n loading: boolean;\n context?: PageContext;\n theme?: WidgetTheme;\n}\n\nconst FrankieContext = createContext<FrankieContextValue | null>(null);\n\nexport function FrankieProvider({\n children,\n context,\n theme,\n config: providedConfig,\n ...clientOptions\n}: FrankieProviderProps) {\n const tokenCallback = useRef(clientOptions.getUserToken);\n tokenCallback.current = clientOptions.getUserToken;\n const client = useMemo(\n () => new FrankieClient({ ...clientOptions, ...(clientOptions.getUserToken ? { getUserToken: () => tokenCallback.current?.() } : {}) }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [clientOptions.baseUrl, clientOptions.publishableKey, clientOptions.storageNamespace, clientOptions.conversationId, clientOptions.persist, clientOptions.fetchImpl, Boolean(clientOptions.getUserToken)],\n );\n\n const [config, setConfig] = useState<PublicWidgetConfig | undefined>(providedConfig);\n const [configError, setConfigError] = useState<string | undefined>(undefined);\n const [loading, setLoading] = useState(!providedConfig);\n\n useEffect(() => {\n if (providedConfig) return;\n const abort = new AbortController();\n setLoading(true);\n client\n .getConfig(abort.signal)\n .then((next) => {\n setConfig(next);\n setConfigError(undefined);\n })\n .catch((error: unknown) => {\n if (abort.signal.aborted) return;\n setConfigError(error instanceof Error ? error.message : \"Could not load the assistant.\");\n })\n .finally(() => {\n if (!abort.signal.aborted) setLoading(false);\n });\n return () => abort.abort();\n }, [client, providedConfig]);\n\n const value = useMemo<FrankieContextValue>(\n () => ({\n client,\n ...(config ? { config } : {}),\n ...(configError ? { configError } : {}),\n loading,\n ...(context ? { context } : {}),\n ...(theme ? { theme } : {}),\n }),\n [client, config, configError, loading, context, theme],\n );\n\n return <FrankieContext.Provider value={value}><ConversationState key={client.namespace + \":\" + (client.conversationId ?? \"\")}>{children}</ConversationState></FrankieContext.Provider>;\n}\n\nfunction ConversationState({ children }: { children: ReactNode }) {\n const chat = useFrankieChatState();\n return <FrankieChatContext.Provider value={chat}>{children}</FrankieChatContext.Provider>;\n}\n\nexport function useFrankie(): FrankieContextValue {\n const value = useContext(FrankieContext);\n if (!value) throw new Error(\"Frankie components must be rendered inside <FrankieProvider>.\");\n return value;\n}\n\nexport function useFrankieTheme(): WidgetTheme | undefined {\n const { config, theme } = useFrankie();\n return useMemo(() => ({ ...config?.theme, ...theme }), [config?.theme, theme]);\n}\n","import type {\n ChatAttachment,\n ChatRequestBody,\n CreateSessionResponse,\n FrankieServerEvent,\n PublicWidgetConfig,\n} from \"@frankieai/core\";\n\nexport type PageContext = Record<string, string | number | boolean | null>;\n\n/**\n * The hosted Frankie data plane. Embedding needs only a publishable key, so\n * `baseUrl` defaults here — override it only when self-hosting the server.\n */\nexport const FRANKIE_CLOUD_URL = \"https://frankie-data-v2-665333762719.us-central1.run.app\";\n\nexport interface FrankieClientOptions {\n /** Where the Frankie server is mounted. Defaults to the hosted cloud. */\n baseUrl?: string;\n /** Safe to ship to the browser; the origin allowlist is what authorises it. */\n publishableKey: string;\n /**\n * Fetches a short-lived JWT for the signed-in user from the host's own\n * backend. Called before each turn; return undefined after sign-out.\n * Omit only for tenants that allow anonymous chat.\n */\n getUserToken?: () => Promise<string | undefined> | string | undefined;\n fetchImpl?: typeof fetch;\n /**\n * Remember the session (and, in the hook, the transcript) in localStorage so a\n * page reload resumes the same anonymous conversation. Authenticated chat\n * never writes tokens or transcripts to localStorage; it uses server history.\n */\n persist?: boolean;\n /** Override localStorage namespace for session and transcript. */\n storageNamespace?: string;\n /** Stable id for a server-backed conversation. */\n conversationId?: string;\n}\n\nexport interface ChatConversation {\n id: string;\n title: string;\n createdAt: number;\n updatedAt: number;\n}\n\nexport class FrankieApiError extends Error {\n constructor(\n message: string,\n readonly status: number,\n readonly code: string,\n ) {\n super(message);\n }\n}\n\nexport class FrankieClient {\n private readonly baseUrl: string;\n private readonly doFetch: typeof fetch;\n private session?: CreateSessionResponse;\n private sessionUserToken?: string;\n\n constructor(private readonly options: FrankieClientOptions) {\n this.baseUrl = (options.baseUrl ?? FRANKIE_CLOUD_URL).replace(/\\/+$/, \"\");\n this.doFetch = options.fetchImpl ?? globalThis.fetch.bind(globalThis);\n this.session = this.readStored();\n if (options.getUserToken && typeof window !== \"undefined\") {\n try { for (const suffix of [\"session\", \"messages\"]) window.localStorage.removeItem(`${this.namespace}.${suffix}`); } catch { /* storage may be unavailable */ }\n }\n }\n\n get sessionId(): string | undefined {\n return this.session?.sessionId;\n }\n\n get conversationId(): string | undefined {\n return this.options.conversationId;\n }\n\n /** Whether this client persists across reloads (browser only, opt-out via `persist:false`). */\n get persist(): boolean {\n // Authenticated history comes from the identity-checked server. Do not leave\n // a previous user's bearer token or transcript in shared browser storage.\n return !this.options.getUserToken && this.options.persist !== false && typeof window !== \"undefined\";\n }\n\n /** localStorage namespace for this tenant/conversation, shared with the chat hook. */\n get namespace(): string {\n return this.options.storageNamespace ?? `frankie.${this.options.publishableKey}`;\n }\n\n private readStored(): CreateSessionResponse | undefined {\n if (!this.persist) return undefined;\n try {\n const raw = window.localStorage.getItem(`${this.namespace}.session`);\n if (!raw) return undefined;\n const session = JSON.parse(raw) as CreateSessionResponse;\n return new Date(session.expiresAt).getTime() > Date.now() + 30_000 ? session : undefined;\n } catch {\n return undefined;\n }\n }\n\n private writeStored(): void {\n if (!this.persist) return;\n try {\n if (this.session) window.localStorage.setItem(`${this.namespace}.session`, JSON.stringify(this.session));\n else window.localStorage.removeItem(`${this.namespace}.session`);\n } catch {\n /* storage may be unavailable (private mode); the chat still works in memory */\n }\n }\n\n async getConfig(signal?: AbortSignal): Promise<PublicWidgetConfig> {\n const response = await this.doFetch(`${this.baseUrl}/v1/config`, {\n headers: { \"x-frankie-key\": this.options.publishableKey },\n ...(signal ? { signal } : {}),\n });\n return (await this.unwrap(response)) as PublicWidgetConfig;\n }\n\n async ensureSession(context?: PageContext): Promise<CreateSessionResponse> {\n const userToken = await this.options.getUserToken?.();\n if (this.options.getUserToken && !userToken) {\n this.resetSession();\n throw new FrankieApiError(\n \"Your signed-in Frankie session could not be verified. Refresh the page and sign in again.\",\n 401,\n \"user_token_unavailable\",\n );\n }\n if (userToken !== this.sessionUserToken) this.resetSession();\n if (this.session && new Date(this.session.expiresAt).getTime() > Date.now() + 30_000) return this.session;\n const response = await this.doFetch(`${this.baseUrl}/v1/session`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-frankie-key\": this.options.publishableKey },\n body: JSON.stringify({\n ...(userToken ? { userToken } : {}),\n ...(context ? { context } : {}),\n ...(this.options.conversationId ? { conversationId: this.options.conversationId } : {}),\n }),\n });\n this.session = (await this.unwrap(response)) as CreateSessionResponse;\n this.sessionUserToken = userToken;\n this.writeStored();\n return this.session;\n }\n\n async listConversations(): Promise<ChatConversation[]> {\n const userToken = await this.requireUserToken();\n const response = await this.doFetch(`${this.baseUrl}/v1/conversations`, {\n headers: { \"x-frankie-key\": this.options.publishableKey, authorization: `Bearer ${userToken}` },\n });\n const body = (await this.unwrap(response)) as { conversations?: ChatConversation[] };\n return Array.isArray(body.conversations) ? body.conversations : [];\n }\n\n async resumeConversation(id = this.options.conversationId): Promise<{ messages: unknown[]; title: string } | undefined> {\n if (!id || !this.options.getUserToken) return undefined;\n const userToken = await this.requireUserToken();\n const response = await this.doFetch(`${this.baseUrl}/v1/conversations/${encodeURIComponent(id)}/resume`, {\n method: \"POST\",\n headers: { \"x-frankie-key\": this.options.publishableKey, authorization: `Bearer ${userToken}` },\n });\n if (response.status === 404) return undefined;\n const body = (await this.unwrap(response)) as { session: CreateSessionResponse; messages?: unknown[]; title?: string };\n this.session = body.session;\n this.sessionUserToken = userToken;\n this.writeStored();\n return { messages: Array.isArray(body.messages) ? body.messages : [], title: body.title ?? \"New chat\" };\n }\n\n async syncConversation(messages: unknown[], title?: string): Promise<void> {\n if (!this.session || !this.options.conversationId) return;\n const response = await this.doFetch(`${this.baseUrl}/v1/conversations/${encodeURIComponent(this.options.conversationId)}`, {\n method: \"PUT\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-frankie-key\": this.options.publishableKey,\n authorization: `Bearer ${this.session.sessionToken}`,\n },\n body: JSON.stringify({ messages, ...(title ? { title } : {}) }),\n });\n await this.unwrap(response);\n }\n\n async deleteConversation(id: string): Promise<void> {\n const userToken = await this.requireUserToken();\n const response = await this.doFetch(`${this.baseUrl}/v1/conversations/${encodeURIComponent(id)}`, {\n method: \"DELETE\",\n headers: { \"x-frankie-key\": this.options.publishableKey, authorization: `Bearer ${userToken}` },\n });\n if (response.status !== 404) await this.unwrap(response);\n }\n\n private async requireUserToken(): Promise<string> {\n const token = await this.options.getUserToken?.();\n if (!token) throw new FrankieApiError(\"Sign in to access your chat history.\", 401, \"unauthorized\");\n return token;\n }\n\n resetSession(): void {\n this.session = undefined;\n this.writeStored();\n }\n\n async send(\n input: {\n message: string;\n context?: PageContext;\n model?: string;\n attachments?: ChatAttachment[];\n signal?: AbortSignal;\n },\n onEvent: (event: FrankieServerEvent) => void,\n ): Promise<void> {\n const session = await this.ensureSession(input.context);\n const body: ChatRequestBody = {\n sessionId: session.sessionId,\n message: input.message,\n ...(input.context ? { context: input.context } : {}),\n ...(input.model ? { model: input.model } : {}),\n ...(input.attachments?.length ? { attachments: input.attachments } : {}),\n };\n\n const response = await this.doFetch(`${this.baseUrl}/v1/chat`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-frankie-key\": this.options.publishableKey,\n authorization: `Bearer ${session.sessionToken}`,\n },\n body: JSON.stringify(body),\n ...(input.signal ? { signal: input.signal } : {}),\n });\n\n if (!response.ok || !response.body) {\n if (response.status === 401 || response.status === 404) this.resetSession();\n await this.unwrap(response);\n return;\n }\n\n for await (const event of readEventStream(response.body)) {\n onEvent(event);\n }\n }\n\n private async unwrap(response: Response): Promise<unknown> {\n if (response.ok) return response.json();\n let code = \"internal\";\n let message = `Request failed with status ${response.status}.`;\n try {\n const body = (await response.json()) as { error?: { code?: string; message?: string } };\n code = body.error?.code ?? code;\n message = body.error?.message ?? message;\n } catch {\n /* keep the default message */\n }\n throw new FrankieApiError(message, response.status, code);\n }\n}\n\nexport async function* readEventStream(\n body: ReadableStream<Uint8Array>,\n): AsyncGenerator<FrankieServerEvent> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n let split = buffer.indexOf(\"\\n\\n\");\n while (split !== -1) {\n const frame = buffer.slice(0, split);\n buffer = buffer.slice(split + 2);\n const event = parseFrame(frame);\n if (event) yield event;\n split = buffer.indexOf(\"\\n\\n\");\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction parseFrame(frame: string): FrankieServerEvent | null {\n const data = frame\n .split(\"\\n\")\n .filter((line) => line.startsWith(\"data:\"))\n .map((line) => line.slice(5).replace(/^ /, \"\"))\n .join(\"\\n\");\n if (!data) return null;\n try {\n return JSON.parse(data) as FrankieServerEvent;\n } catch {\n return null;\n }\n}\n","\"use client\";\n\nimport { createContext, useContext, useCallback, useEffect, useRef, useState } from \"react\";\nimport type { ChatAttachment, LoadedSkill } from \"@frankieai/core\";\nimport { FrankieApiError } from \"../lib/client.js\";\nimport {\n applyEvent,\n newAssistantMessage,\n newUserMessage,\n type AssistantChatMessage,\n type ChatMessage,\n} from \"../lib/messages.js\";\nimport { useFrankie } from \"./FrankieProvider.jsx\";\n\n/** Extra inputs a turn can carry: attached files and a chosen model. */\nexport interface SendOptions {\n attachments?: ChatAttachment[];\n model?: string;\n}\n\nexport interface UseFrankieChatResult {\n loadedSkills: LoadedSkill[] | null;\n restoring: boolean;\n messages: ChatMessage[];\n /** True from the moment a message is sent until the turn ends. */\n busy: boolean;\n /** Set when the turn failed outright (network, auth, rate limit). */\n error?: string;\n send: (text: string, opts?: SendOptions) => Promise<void>;\n /** Abort the in-flight turn. The partial answer stays in the transcript. */\n stop: () => void;\n /** Clear the transcript and start a brand-new server session. */\n reset: () => void;\n}\n\nlet counter = 0;\nconst nextId = (prefix: string) => `${prefix}_${Date.now().toString(36)}_${(counter += 1)}`;\n\nexport const FrankieChatContext = createContext<UseFrankieChatResult | null>(null);\nexport function useFrankieChat(): UseFrankieChatResult {\n const value = useContext(FrankieChatContext);\n if (!value) throw new Error(\"useFrankieChat requires FrankieProvider.\");\n return value;\n}\n\nexport function useFrankieChatState(): UseFrankieChatResult {\n const { client, context } = useFrankie();\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | undefined>(undefined);\n const [restored, setRestored] = useState(false);\n const [loadedSkills, setLoadedSkills] = useState<LoadedSkill[] | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n const mounted = useRef(true);\n // State updates can be batched while a stream is arriving. Keep the latest\n // transcript synchronously so the final server sync cannot save a stale copy.\n const messagesRef = useRef<ChatMessage[]>([]);\n\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n abortRef.current?.abort();\n };\n }, []);\n\n const storageKey = `${client.namespace}.messages`;\n\n // Restore local storage immediately, then hydrate the authoritative server\n // transcript. The server path makes the same signed-in user's chats available\n // on another browser or device.\n useEffect(() => {\n let active = true;\n const restore = async () => {\n if (client.persist) {\n try {\n const raw = window.localStorage.getItem(storageKey);\n const stored = raw ? (JSON.parse(raw) as ChatMessage[]) : [];\n if (Array.isArray(stored) && stored.length && active) {\n messagesRef.current = stored;\n setMessages(stored);\n }\n } catch {\n /* storage unavailable; server history can still restore */\n }\n }\n try {\n const remote = await client.resumeConversation();\n if (active && remote?.messages.length) {\n const restoredMessages = remote.messages as ChatMessage[];\n messagesRef.current = restoredMessages;\n setMessages(restoredMessages);\n }\n } catch {\n if (active) setError(\"Could not restore this conversation. Check your sign-in and connection, then try opening it again.\");\n } finally {\n if (active) setRestored(true);\n }\n };\n void restore();\n return () => { active = false; };\n }, [client, storageKey]);\n\n // Persist once a turn settles — never mid-stream — so the saved copy is clean.\n // Wait until the initial restore has completed so an empty initial state never\n // deletes an existing transcript.\n useEffect(() => {\n if (!client.persist || !restored || busy) return;\n try {\n if (messages.length) window.localStorage.setItem(storageKey, JSON.stringify(messages));\n else window.localStorage.removeItem(storageKey);\n } catch {\n /* ignore */\n }\n if (messages.length) void client.syncConversation(messages, conversationTitle(messages)).catch(() => undefined);\n }, [messages, busy, client, storageKey, restored]);\n\n const patchAssistant = useCallback((id: string, update: (m: AssistantChatMessage) => AssistantChatMessage) => {\n const next = messagesRef.current.map((message) =>\n message.id === id && message.role === \"assistant\" ? update(message) : message,\n );\n messagesRef.current = next;\n setMessages(next);\n }, []);\n\n const send = useCallback(\n async (text: string, opts?: SendOptions) => {\n const trimmed = text.trim();\n const attachments = opts?.attachments ?? [];\n if ((!trimmed && attachments.length === 0) || abortRef.current || !restored) return;\n // The server needs a message; an attachment-only turn gets a stand-in.\n const outgoing = trimmed || \"Please take a look at the attached file(s).\";\n\n const assistantId = nextId(\"a\");\n setError(undefined);\n setLoadedSkills(null);\n setBusy(true);\n const next = [\n ...messagesRef.current,\n newUserMessage(\n nextId(\"u\"),\n trimmed,\n attachments.map((file) => ({ name: file.name, mimeType: file.mimeType })),\n ),\n newAssistantMessage(assistantId),\n ];\n messagesRef.current = next;\n setMessages(next);\n\n const abort = new AbortController();\n abortRef.current = abort;\n\n try {\n let receivedText = false;\n let receivedToolActivity = false;\n await client.send(\n {\n message: outgoing,\n ...(context ? { context } : {}),\n ...(opts?.model ? { model: opts.model } : {}),\n ...(attachments.length ? { attachments } : {}),\n signal: abort.signal,\n },\n (event) => {\n if (event.type === \"skills_loaded\") { setLoadedSkills(event.skills); return; }\n if (event.type === \"ping\" || event.type === \"session\") return;\n if (event.type === \"text_delta\") receivedText = true;\n if (event.type === \"tool_start\" || event.type === \"tool_end\") receivedToolActivity = true;\n patchAssistant(assistantId, (message) => applyEvent(message, event));\n },\n );\n // A terminated stream with no text previously looked like Frankie did\n // nothing. Preserve visible tool activity, but never leave an empty\n // assistant bubble for the user to interpret.\n if (!receivedText) {\n patchAssistant(assistantId, (message) => ({\n ...message,\n status: \"done\",\n text: receivedToolActivity\n ? \"Completed. Open Agent activity for the details.\"\n : \"Frankie didn’t return an answer. Please try again.\",\n }));\n }\n } catch (caught) {\n if (abort.signal.aborted) {\n patchAssistant(assistantId, (message) => ({\n ...message,\n status: \"done\",\n text: message.text || \"Stopped.\",\n }));\n } else {\n const message =\n caught instanceof FrankieApiError\n ? caught.message\n : caught instanceof Error && caught.message.startsWith(\"Frankie\")\n ? caught.message\n : \"Could not reach the assistant. Check your connection and try again.\";\n if (mounted.current) setError(message);\n patchAssistant(assistantId, (current) => ({ ...current, status: \"error\", error: message }));\n }\n } finally {\n // A turn that ended without a `turn_end` event still has to settle.\n patchAssistant(assistantId, (message) =>\n message.status === \"streaming\" ? { ...message, status: \"done\" } : message,\n );\n // Persist before send() resolves. This closes the previous gap where a\n // route change or tab close could leave a server conversation with no\n // rendered messages even though the agent transcript existed.\n const transcript = messagesRef.current;\n if (transcript.length) {\n await client.syncConversation(transcript, conversationTitle(transcript)).catch(() => undefined);\n }\n if (mounted.current) setBusy(false);\n abortRef.current = null;\n }\n },\n [busy, client, context, patchAssistant, restored],\n );\n\n const stop = useCallback(() => abortRef.current?.abort(), []);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n client.resetSession();\n messagesRef.current = [];\n setMessages([]);\n setError(undefined);\n setBusy(false);\n setRestored(true);\n setLoadedSkills(null);\n try {\n if (client.persist) window.localStorage.removeItem(`${client.namespace}.messages`);\n } catch {\n /* ignore */\n }\n }, [client]);\n\n return { messages, busy, loadedSkills, restoring: !restored, ...(error ? { error } : {}), send, stop, reset };\n}\n\n\nfunction conversationTitle(messages: ChatMessage[]): string | undefined {\n const first = messages.find((message) => message.role === \"user\" && message.text.trim());\n if (!first) return undefined;\n const title = first.text.trim().replace(/\\s+/g, \" \");\n return title.length > 42 ? `${title.slice(0, 42)}…` : title;\n}\n","import type { FrankieServerEvent } from \"@frankieai/core\";\n\nexport interface ToolActivity {\n id: string;\n name: string;\n label: string;\n status: \"running\" | \"done\" | \"failed\" | \"denied\";\n detail?: string;\n}\n\n/** A file shown on a user message (name/type only — the bytes aren't kept in the transcript). */\nexport interface MessageAttachment {\n name: string;\n mimeType: string;\n}\n\nexport interface UserChatMessage {\n id: string;\n role: \"user\";\n text: string;\n attachments?: MessageAttachment[];\n createdAt: number;\n}\n\nexport interface AssistantChatMessage {\n id: string;\n role: \"assistant\";\n text: string;\n thinking: string;\n tools: ToolActivity[];\n status: \"streaming\" | \"done\" | \"error\";\n error?: string;\n createdAt: number;\n}\n\nexport type ChatMessage = UserChatMessage | AssistantChatMessage;\n\n/**\n * Fold one server event into the assistant message being built.\n *\n * Kept pure and separate from React so the streaming logic is testable without\n * a DOM, and so a host writing its own UI can reuse it.\n */\nexport function applyEvent(message: AssistantChatMessage, event: FrankieServerEvent): AssistantChatMessage {\n switch (event.type) {\n case \"text_delta\":\n return { ...message, text: message.text + event.text };\n\n case \"thinking_delta\":\n return { ...message, thinking: message.thinking + event.text };\n\n case \"tool_start\":\n return {\n ...message,\n tools: [\n ...message.tools,\n { id: event.toolUseId, name: event.name, label: event.label, status: \"running\" },\n ],\n };\n\n case \"tool_end\":\n return {\n ...message,\n tools: message.tools.map((tool) =>\n tool.id === event.toolUseId\n ? {\n ...tool,\n status: event.ok ? \"done\" : \"failed\",\n ...(event.preview ? { detail: event.preview } : {}),\n }\n : tool,\n ),\n };\n\n case \"tool_denied\":\n return {\n ...message,\n tools: upsertTool(message.tools, {\n id: event.toolUseId,\n name: event.name,\n label: event.name,\n status: \"denied\",\n detail: event.reason,\n }),\n };\n\n case \"turn_end\":\n return {\n ...message,\n status: message.status === \"error\" ? \"error\" : \"done\",\n // A turn that produced nothing still needs to say something.\n text: message.text || fallbackText(event.stopReason),\n };\n\n case \"error\":\n return { ...message, status: \"error\", error: event.message };\n\n default:\n return message;\n }\n}\n\nfunction upsertTool(tools: ToolActivity[], next: ToolActivity): ToolActivity[] {\n return tools.some((tool) => tool.id === next.id)\n ? tools.map((tool) => (tool.id === next.id ? { ...tool, ...next } : tool))\n : [...tools, next];\n}\n\nfunction fallbackText(stopReason: string): string {\n switch (stopReason) {\n case \"max_turns\":\n return \"I got stuck working on that. Could you narrow it down a little?\";\n case \"aborted\":\n return \"Stopped.\";\n case \"error\":\n return \"Something went wrong before I could answer. Try again?\";\n default:\n return \"\";\n }\n}\n\nexport function newAssistantMessage(id: string): AssistantChatMessage {\n return { id, role: \"assistant\", text: \"\", thinking: \"\", tools: [], status: \"streaming\", createdAt: Date.now() };\n}\n\nexport function newUserMessage(id: string, text: string, attachments?: MessageAttachment[]): UserChatMessage {\n return { id, role: \"user\", text, ...(attachments?.length ? { attachments } : {}), createdAt: Date.now() };\n}\n","\"use client\";\n\nimport { MessageCircle, X } from \"lucide-react\";\nimport { useEffect, useState } from \"react\";\nimport { useFrankie, useFrankieTheme } from \"../../hooks/FrankieProvider.jsx\";\nimport { resolveMode, themeToCssVars } from \"../../lib/theme.js\";\nimport { cn } from \"../../lib/utils.js\";\nimport { Button } from \"../ui/button.js\";\nimport { ChatPanel, type ChatPanelProps } from \"./ChatPanel.js\";\n\nexport interface FrankieWidgetProps extends ChatPanelProps {\n position?: \"bottom-right\" | \"bottom-left\";\n /** Distance from the viewport edges, in pixels. */\n offset?: number;\n defaultOpen?: boolean;\n /** Host overlays should sit above the assistant. Override for your layer system. */\n zIndex?: number;\n /** Controlled mode: pass both to drive open state from the host app. */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Replace the floating launcher button. */\n renderLauncher?: (props: { open: boolean; toggle: () => void; label: string }) => React.ReactNode;\n}\n\n/**\n * The drop-in embed: a floating launcher plus the chat panel.\n *\n * Renders `position: fixed` at the document level, so it does not care what\n * layout the host page uses.\n */\nexport function FrankieWidget({\n position = \"bottom-right\",\n offset = 24,\n defaultOpen = false,\n zIndex = 20,\n open: controlledOpen,\n onOpenChange,\n renderLauncher,\n ...panelProps\n}: FrankieWidgetProps) {\n const { config } = useFrankie();\n const theme = useFrankieTheme();\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n const open = controlledOpen ?? uncontrolledOpen;\n\n const setOpen = (next: boolean) => {\n if (controlledOpen === undefined) setUncontrolledOpen(next);\n onOpenChange?.(next);\n };\n\n // Escape closes the panel, matching every other overlay on the host's page.\n useEffect(() => {\n if (!open) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") setOpen(false);\n };\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n\n const label = config?.branding.launcherLabel ?? \"Need a hand?\";\n const mode = resolveMode(theme?.mode);\n const side = position === \"bottom-right\" ? { right: offset } : { left: offset };\n\n return (\n <div\n className={cn(\"frankie-root frankie-widget\", mode === \"dark\" && \"dark\")}\n style={{ ...themeToCssVars(theme), position: \"fixed\", bottom: offset, ...side, zIndex, pointerEvents: \"none\" }}\n data-frankie-mode={mode}\n >\n <div className={cn(\"flex flex-col gap-3\", position === \"bottom-left\" ? \"items-start\" : \"items-end\")}>\n {open ? <div style={{ pointerEvents: \"auto\", maxHeight: \"calc(100dvh - 100px)\", overflow: \"hidden\" }}><ChatPanel {...panelProps} className={cn(\"frankie-widget-panel\", panelProps.className)} onClose={() => setOpen(false)} autoFocus /></div> : null}\n <div style={{ pointerEvents: \"auto\" }}>\n {renderLauncher ? (\n renderLauncher({ open, toggle: () => setOpen(!open), label })\n ) : (\n <Button\n size=\"icon\"\n className=\"size-12 rounded-full shadow-lg\"\n onClick={() => setOpen(!open)}\n aria-expanded={open}\n aria-label={open ? \"Close the assistant\" : label}\n title={label}\n >\n {open ? <X className=\"size-5\" /> : <MessageCircle className=\"size-5\" />}\n </Button>\n )}</div>\n </div>\n </div>\n );\n}\n","import type { WidgetTheme } from \"@frankieai/core\";\nimport type { CSSProperties } from \"react\";\n\n/**\n * Map a theme to the CSS custom properties the widget's styles read.\n *\n * Anything not set falls through to the defaults in `frankie.css`, which are\n * themselves shadcn/ui token names — so a host that already runs shadcn can\n * drop the stylesheet and the widget inherits their design system instead.\n */\nexport function themeToCssVars(theme: WidgetTheme | undefined): CSSProperties {\n if (!theme) return {};\n const vars: Record<string, string> = {};\n if (theme.primary) vars[\"--frankie-primary\"] = theme.primary;\n if (theme.primaryForeground) vars[\"--frankie-primary-foreground\"] = theme.primaryForeground;\n if (theme.background) vars[\"--frankie-background\"] = theme.background;\n if (theme.foreground) vars[\"--frankie-foreground\"] = theme.foreground;\n if (theme.muted) vars[\"--frankie-muted\"] = theme.muted;\n if (theme.border) vars[\"--frankie-border\"] = theme.border;\n if (theme.radius) vars[\"--frankie-radius\"] = `${theme.radius}rem`;\n if (theme.fontFamily) vars[\"--frankie-font\"] = theme.fontFamily;\n return vars as CSSProperties;\n}\n\n/** Resolve `mode: \"system\"` against the browser, so the widget can hard-set a class. */\nexport function resolveMode(mode: WidgetTheme[\"mode\"]): \"light\" | \"dark\" {\n if (mode === \"light\" || mode === \"dark\") return mode;\n if (typeof window === \"undefined\" || !window.matchMedia) return \"light\";\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\";\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/** shadcn/ui's class helper: conditional classes with Tailwind conflict resolution. */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\nexport const buttonVariants = cva(\n \"frankie-focus inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[var(--frankie-radius)] text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:opacity-90\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-muted\",\n outline: \"border border-border bg-background hover:bg-muted\",\n ghost: \"hover:bg-muted\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-[calc(var(--frankie-radius)-2px)] px-3 text-xs\",\n lg: \"h-10 px-6\",\n icon: \"size-9\",\n },\n },\n defaultVariants: { variant: \"default\", size: \"default\" },\n },\n);\n\nexport interface ButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nexport function Button({ className, variant, size, asChild = false, ...props }: ButtonProps) {\n const Comp = asChild ? Slot : \"button\";\n return <Comp className={cn(buttonVariants({ variant, size }), className)} {...props} />;\n}\n","\"use client\";\n\nimport { RotateCcw, X } from \"lucide-react\";\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { useFrankie, useFrankieTheme } from \"../../hooks/FrankieProvider.jsx\";\nimport { useFrankieChat } from \"../../hooks/useFrankieChat.js\";\nimport type { ChatMessage, ToolActivity } from \"../../lib/messages.js\";\nimport { resolveMode, themeToCssVars } from \"../../lib/theme.js\";\nimport { cn } from \"../../lib/utils.js\";\nimport { Avatar } from \"../ui/avatar.js\";\nimport { Button } from \"../ui/button.js\";\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from \"../ui/card.js\";\nimport { ScrollArea } from \"../ui/scroll-area.js\";\nimport { AgentContext } from \"./AgentContext.js\";\nimport { Composer } from \"./Composer.js\";\nimport { MessageBubble } from \"./MessageBubble.js\";\nimport { SuggestedPrompts } from \"./SuggestedPrompts.js\";\n\nexport interface ChatPanelProps {\n className?: string;\n /** Replace the header entirely, or pass `false` to drop it. */\n header?: ReactNode | false;\n /** Rendered under the composer — good for a \"powered by\" or a privacy note. */\n footer?: ReactNode;\n /** Shown before the first message, in place of the default greeting block. */\n emptyState?: ReactNode;\n /** Take over message rendering completely. */\n renderMessage?: (message: ChatMessage) => ReactNode;\n /** Take over the tool-activity rows. */\n renderTool?: (tool: ToolActivity) => ReactNode;\n placeholder?: string;\n /** Shows a close button in the header when provided. */\n onClose?: () => void;\n autoFocus?: boolean;\n /** Fill the parent instead of the fixed floating size — for full-page use. */\n fill?: boolean;\n}\n\nexport function ChatPanel({\n className,\n header,\n footer,\n emptyState,\n renderMessage,\n renderTool,\n placeholder,\n onClose,\n autoFocus,\n fill,\n}: ChatPanelProps) {\n const { config, configError, loading } = useFrankie();\n const theme = useFrankieTheme();\n const { messages, busy, restoring, error, send, stop, reset } = useFrankieChat();\n const scrollRef = useRef<HTMLDivElement>(null);\n\n const features = config?.features;\n const pickerModels = features?.modelPicker.enabled ? features.modelPicker.models : [];\n const [model, setModel] = useState<string | undefined>(undefined);\n\n // Follow the stream, but only while the reader is already near the bottom.\n useEffect(() => {\n const node = scrollRef.current;\n if (!node) return;\n const distanceFromBottom = node.scrollHeight - node.scrollTop - node.clientHeight;\n if (distanceFromBottom < 160) node.scrollTop = node.scrollHeight;\n }, [messages]);\n\n const name = config?.branding.name ?? \"Assistant\";\n const mode = resolveMode(theme?.mode);\n\n return (\n <Card\n className={cn(\n \"frankie-root frankie-chat-panel\",\n fill && \"frankie-chat-panel-fill\",\n fill ? \"h-full w-full rounded-none border-0 shadow-none\" : \"h-[32rem] w-[22rem] max-w-[calc(100vw-2rem)]\",\n mode === \"dark\" && \"dark\",\n className,\n )}\n style={themeToCssVars(theme)}\n data-frankie-mode={mode}\n >\n {header === false ? null : header !== undefined ? (\n header\n ) : (\n <CardHeader>\n <Avatar {...(config?.branding.avatarUrl ? { src: config.branding.avatarUrl } : {})} name={name} />\n <div className=\"min-w-0 flex-1\">\n <CardTitle>{name}</CardTitle>\n {config?.branding.tagline ? <CardDescription>{config.branding.tagline}</CardDescription> : null}\n </div>\n <Button size=\"icon\" variant=\"ghost\" onClick={reset} aria-label=\"Start a new conversation\" title=\"New conversation\">\n <RotateCcw />\n </Button>\n {onClose ? (\n <Button size=\"icon\" variant=\"ghost\" onClick={onClose} aria-label=\"Close\">\n <X />\n </Button>\n ) : null}\n </CardHeader>\n )}\n\n <AgentContext />\n <CardContent className=\"frankie-conversation-content\">\n <ScrollArea ref={scrollRef} className=\"frankie-transcript flex h-full flex-col gap-4 p-4\" aria-live=\"polite\">\n {configError ? (\n <div className=\"frankie-config-error\" role=\"alert\">\n <strong>Frankie couldn’t start</strong>\n <p>{configError}</p>\n <p>Refresh this page after checking the workspace’s allowed origin and sign-in settings.</p>\n </div>\n ) : loading ? (\n <p className=\"text-sm text-muted-foreground\">Starting Frankie…</p>\n ) : messages.length === 0 ? (\n (emptyState ?? (\n <div className=\"flex flex-col gap-4\">\n <p className=\"text-sm text-muted-foreground\">{config?.greeting}</p>\n <SuggestedPrompts prompts={config?.suggestedPrompts ?? []} onPick={send} disabled={busy} />\n </div>\n ))\n ) : (\n <div className=\"frankie-message-list flex flex-col gap-4\">\n {messages.map((message) =>\n renderMessage ? (\n <div key={message.id}>{renderMessage(message)}</div>\n ) : (\n <MessageBubble\n key={message.id}\n message={message}\n assistantName={name}\n {...(config?.branding.avatarUrl ? { avatarUrl: config.branding.avatarUrl } : {})}\n showToolActivity={config?.showToolActivity ?? true}\n {...(renderTool ? { renderTool } : {})}\n />\n ),\n )}\n </div>\n )}\n </ScrollArea>\n </CardContent>\n\n <CardFooter className=\"frankie-composer-footer flex flex-col gap-2\">\n {error ? <p className=\"w-full text-xs text-red-600 dark:text-red-400\">{error}</p> : null}\n <div className=\"w-full\">\n <Composer\n onSend={send}\n onStop={stop}\n busy={busy}\n disabled={loading || restoring || Boolean(configError)}\n {...(placeholder ? { placeholder } : {})}\n {...(autoFocus ? { autoFocus } : {})}\n {...(features?.attachments.enabled ? { attachments: features.attachments } : {})}\n {...(pickerModels.length\n ? { modelPicker: { models: pickerModels, value: model ?? pickerModels[0]?.id, onChange: setModel } }\n : {})}\n />\n </div>\n {footer}\n </CardFooter>\n </Card>\n );\n}\n","\"use client\";\n\nimport { cn } from \"../../lib/utils.js\";\n\nexport interface AvatarProps {\n src?: string;\n name: string;\n className?: string;\n}\n\n/** Image avatar with an initials fallback — no image request when `src` is absent. */\nexport function Avatar({ src, name, className }: AvatarProps) {\n const initials = name\n .split(/\\s+/)\n .slice(0, 2)\n .map((part) => part[0]?.toUpperCase() ?? \"\")\n .join(\"\");\n\n return (\n <span\n className={cn(\n \"inline-flex size-7 shrink-0 items-center justify-center overflow-hidden rounded-full bg-primary text-[0.625rem] font-semibold text-primary-foreground\",\n className,\n )}\n aria-hidden=\"true\"\n >\n {src ? <img src={src} alt=\"\" className=\"size-full object-cover\" /> : initials}\n </span>\n );\n}\n","\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\nexport function Card({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn(\n \"flex flex-col rounded-[calc(var(--frankie-radius)+4px)] border border-border bg-background text-foreground shadow-lg\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport function CardHeader({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"flex items-center gap-3 border-b border-border px-4 py-3\", className)} {...props} />;\n}\n\nexport function CardTitle({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"text-sm font-semibold leading-tight\", className)} {...props} />;\n}\n\nexport function CardDescription({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"text-xs text-muted-foreground\", className)} {...props} />;\n}\n\nexport function CardContent({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"flex-1 overflow-hidden\", className)} {...props} />;\n}\n\nexport function CardFooter({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn(\"border-t border-border p-3\", className)} {...props} />;\n}\n","\"use client\";\n\nimport { forwardRef, type HTMLAttributes } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * A plain overflow container rather than Radix's ScrollArea: the widget lives\n * inside someone else's page, and a native scroller inherits their scrollbar\n * behaviour instead of fighting it.\n */\nexport const ScrollArea = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(\n function ScrollArea({ className, ...props }, ref) {\n return <div ref={ref} className={cn(\"frankie-scroll overflow-y-auto overscroll-contain\", className)} {...props} />;\n },\n);\n","\"use client\";\nimport { ArrowUpRight, Sparkles } from \"lucide-react\";\nimport { useFrankie } from \"../../hooks/FrankieProvider.jsx\";\nimport { useFrankieChat } from \"../../hooks/useFrankieChat.js\";\n\n/** Reports server-confirmed skills for the current turn; never implies drafts are active. */\nexport function AgentContext() {\n const { loading, configError } = useFrankie();\n const { loadedSkills, busy, restoring, error } = useFrankieChat();\n const status = configError || error ? \"Unavailable\" : loading || restoring ? \"Connecting\" : busy && loadedSkills === null ? \"Checking\" : loadedSkills?.length ? \"Active\" : loadedSkills ? \"Tools only\" : \"Ready\";\n return <div className=\"frankie-agent-context-wrap\">\n <details className=\"frankie-agent-context\">\n <summary aria-label=\"Agent context\"><Sparkles size={17} aria-hidden=\"true\" /><span>Agent context</span><span className=\"frankie-context-count\">{loadedSkills === null ? \"Not checked\" : `${loadedSkills.length} ${loadedSkills.length === 1 ? \"skill\" : \"skills\"}`}</span><span className=\"frankie-context-status\" data-active={status === \"Active\"}><i aria-hidden=\"true\" />{status}</span><ArrowUpRight size={15} aria-hidden=\"true\" /></summary>\n <div className=\"frankie-context-detail\">\n <strong>{loadedSkills === null ? \"Skills are checked when you send a message\" : loadedSkills.length ? `${loadedSkills.length} ${loadedSkills.length === 1 ? \"skill\" : \"skills\"} loaded` : \"No skills loaded for this turn\"}</strong>\n {loadedSkills?.length ? <ul>{loadedSkills.map(skill => <li key={skill.id}><span>{skill.name}</span><small>v{skill.revision}</small></li>)}</ul> : <p>Frankie can use the tools approved for this workspace. Drafts and skills without available tools are not loaded.</p>}\n <p>Published skills and updates are checked on every message. Only approved, available tools can run.</p>\n </div>\n </details>\n <span className=\"frankie-sr-only\" role=\"status\">{loadedSkills === null ? status : `${loadedSkills.length} ${loadedSkills.length === 1 ? \"skill\" : \"skills\"} loaded. ${status}.`}</span>\n </div>;\n}\n","\"use client\";\n\nimport { ArrowUp, Paperclip, Plus, Square, X } from \"lucide-react\";\nimport { useCallback, useEffect, useRef, useState, type KeyboardEvent } from \"react\";\nimport type { ChatAttachment } from \"@frankieai/core\";\nimport { Button } from \"../ui/button.js\";\nimport { Textarea } from \"../ui/textarea.js\";\n\nexport interface ComposerAttachmentsConfig {\n enabled: boolean;\n /** Accepted MIME patterns, e.g. \"image/*\". */\n accept: string[];\n maxCount: number;\n maxMb: number;\n}\n\nexport interface ComposerModelPicker {\n models: { id: string; label: string }[];\n value?: string;\n onChange: (id: string) => void;\n}\n\nexport interface ComposerProps {\n onSend: (text: string, opts?: { attachments?: ChatAttachment[]; model?: string }) => void;\n onStop: () => void;\n busy: boolean;\n placeholder?: string;\n disabled?: boolean;\n autoFocus?: boolean;\n /** Enables the attach button when provided and `enabled`. */\n attachments?: ComposerAttachmentsConfig;\n /** Enables a model dropdown when provided with at least one model. */\n modelPicker?: ComposerModelPicker;\n}\n\ninterface PickedFile extends ChatAttachment {\n id: string;\n}\n\nconst MAX_ROWS_PX = 140;\n\nexport function Composer({ onSend, onStop, busy, placeholder, disabled, autoFocus, attachments, modelPicker }: ComposerProps) {\n const [value, setValue] = useState(\"\");\n const [files, setFiles] = useState<PickedFile[]>([]);\n const [fileError, setFileError] = useState<string | undefined>(undefined);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const canAttach = Boolean(attachments?.enabled);\n const models = modelPicker?.models ?? [];\n\n // Grow with the content up to a cap, then scroll.\n useEffect(() => {\n const node = textareaRef.current;\n if (!node) return;\n node.style.height = \"auto\";\n node.style.height = `${Math.min(node.scrollHeight, MAX_ROWS_PX)}px`;\n }, [value]);\n\n const addFiles = useCallback(\n async (list: FileList | null) => {\n if (!list || !attachments) return;\n setFileError(undefined);\n const room = attachments.maxCount - files.length;\n const chosen = Array.from(list).slice(0, Math.max(0, room));\n if (Array.from(list).length > room) setFileError(`You can attach up to ${attachments.maxCount} file(s).`);\n\n const next: PickedFile[] = [];\n for (const file of chosen) {\n if (!mimeAccepted(file.type || \"application/octet-stream\", attachments.accept)) {\n setFileError(`Files of type ${file.type || \"unknown\"} aren't allowed.`);\n continue;\n }\n if (file.size > attachments.maxMb * 1024 * 1024) {\n setFileError(`Each file must be under ${attachments.maxMb} MB.`);\n continue;\n }\n try {\n next.push({\n id: `${file.name}-${file.size}-${Math.random().toString(36).slice(2, 7)}`,\n name: file.name,\n mimeType: file.type || \"application/octet-stream\",\n data: await readAsBase64(file),\n });\n } catch {\n setFileError(\"Couldn't read that file.\");\n }\n }\n if (next.length) setFiles((current) => [...current, ...next]);\n },\n [attachments, files.length],\n );\n\n const removeFile = (id: string) => setFiles((current) => current.filter((file) => file.id !== id));\n\n const submit = useCallback(() => {\n const text = value.trim();\n if ((!text && files.length === 0) || busy || disabled) return;\n setValue(\"\");\n const attached = files.map(({ name, mimeType, data }) => ({ name, mimeType, data }));\n setFiles([]);\n setFileError(undefined);\n onSend(text, {\n ...(attached.length ? { attachments: attached } : {}),\n ...(modelPicker?.value ? { model: modelPicker.value } : {}),\n });\n }, [busy, disabled, files, modelPicker?.value, onSend, value]);\n\n const onKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n if (event.key === \"Enter\" && !event.shiftKey && !event.nativeEvent.isComposing) {\n event.preventDefault();\n submit();\n }\n };\n\n const nothingToSend = value.trim().length === 0 && files.length === 0;\n\n return (\n <form\n className=\"frankie-composer flex flex-col gap-2\"\n onSubmit={(event) => {\n event.preventDefault();\n submit();\n }}\n >\n {files.length > 0 ? (\n <div className=\"flex flex-wrap gap-2\">\n {files.map((file) => (\n <span\n key={file.id}\n className=\"inline-flex max-w-[14rem] items-center gap-1.5 rounded-[var(--frankie-radius)] border border-border bg-muted px-2 py-1 text-xs\"\n >\n <Paperclip className=\"size-3 shrink-0 opacity-70\" />\n <span className=\"truncate\">{file.name}</span>\n <button\n type=\"button\"\n onClick={() => removeFile(file.id)}\n aria-label={`Remove ${file.name}`}\n className=\"frankie-focus shrink-0 opacity-60 hover:opacity-100\"\n >\n <X className=\"size-3\" />\n </button>\n </span>\n ))}\n </div>\n ) : null}\n\n {fileError ? <p className=\"text-xs text-red-600 dark:text-red-400\">{fileError}</p> : null}\n\n <div className=\"frankie-composer-controls flex items-end gap-2\">\n {canAttach ? (\n <>\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n hidden\n accept={attachments?.accept.join(\",\")}\n onChange={(event) => {\n void addFiles(event.target.files);\n event.target.value = \"\";\n }}\n />\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"outline\"\n disabled={disabled || files.length >= (attachments?.maxCount ?? 0)}\n onClick={() => fileInputRef.current?.click()}\n aria-label=\"Attach files\"\n title=\"Attach files\"\n >\n <Plus />\n </Button>\n </>\n ) : null}\n\n <Textarea\n ref={textareaRef}\n rows={1}\n value={value}\n disabled={disabled}\n autoFocus={autoFocus}\n onChange={(event) => setValue(event.target.value)}\n onKeyDown={onKeyDown}\n placeholder={placeholder ?? \"Ask anything…\"}\n aria-label=\"Message\"\n />\n\n {models.length > 0 ? (\n <select\n value={modelPicker?.value ?? models[0]?.id}\n onChange={(event) => modelPicker?.onChange(event.target.value)}\n disabled={disabled}\n aria-label=\"Model\"\n className=\"frankie-focus h-9 max-w-[8rem] rounded-[var(--frankie-radius)] border border-border bg-background px-2 text-sm\"\n >\n {models.map((model) => (\n <option key={model.id} value={model.id}>\n {model.label}\n </option>\n ))}\n </select>\n ) : null}\n\n {busy ? (\n <Button type=\"button\" size=\"icon\" variant=\"outline\" onClick={onStop} aria-label=\"Stop\">\n <Square />\n </Button>\n ) : (\n <Button type=\"submit\" size=\"icon\" disabled={disabled || nothingToSend} aria-label=\"Send\">\n <ArrowUp />\n </Button>\n )}\n </div>\n </form>\n );\n}\n\nfunction mimeAccepted(mimeType: string, accept: string[]): boolean {\n return accept.some((pattern) =>\n pattern.endsWith(\"/*\") ? mimeType.startsWith(pattern.slice(0, -1)) : pattern === mimeType,\n );\n}\n\n/** Read a File to a base64 string (no data-URL prefix), for the wire protocol. */\nfunction readAsBase64(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const result = String(reader.result);\n const comma = result.indexOf(\",\");\n resolve(comma >= 0 ? result.slice(comma + 1) : result);\n };\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n}\n\n","\"use client\";\n\nimport { forwardRef, type TextareaHTMLAttributes } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** `forwardRef` rather than React 19's ref-as-prop, so React 18 hosts work too. */\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaHTMLAttributes<HTMLTextAreaElement>>(\n function Textarea({ className, ...props }, ref) {\n return (\n <textarea\n ref={ref}\n className={cn(\n \"frankie-focus flex min-h-[2.25rem] w-full resize-none rounded-[var(--frankie-radius)] border border-border bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n {...props}\n />\n );\n },\n);\n","\"use client\";\n\nimport { Check, Copy, Paperclip } from \"lucide-react\";\nimport \"./message-actions.css\";\nimport { useState, type ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\nimport type { ChatMessage, ToolActivity } from \"../../lib/messages.js\";\nimport { Avatar } from \"../ui/avatar.js\";\nimport { Markdown } from \"./Markdown.js\";\nimport { ToolActivityList } from \"./ToolActivityList.js\";\n\nexport interface MessageBubbleProps {\n message: ChatMessage;\n assistantName: string;\n avatarUrl?: string;\n showToolActivity: boolean;\n renderTool?: (tool: ToolActivity) => ReactNode;\n}\n\nexport function MessageBubble({\n message,\n assistantName,\n avatarUrl,\n showToolActivity,\n renderTool,\n}: MessageBubbleProps) {\n if (message.role === \"user\") {\n return (\n <div className=\"frankie-user-message flex flex-col items-end gap-1\">\n {message.attachments?.length ? (\n <div className=\"flex max-w-[85%] flex-wrap justify-end gap-1\">\n {message.attachments.map((file, index) => (\n <span\n key={`${file.name}-${index}`}\n className=\"inline-flex max-w-[12rem] items-center gap-1 rounded-[var(--frankie-radius)] border border-border bg-muted px-2 py-1 text-xs\"\n >\n <Paperclip className=\"size-3 shrink-0 opacity-70\" />\n <span className=\"truncate\">{file.name}</span>\n </span>\n ))}\n </div>\n ) : null}\n {message.text ? (\n <div className=\"flex max-w-[85%] items-end gap-1\">\n <div className=\"frankie-user-bubble rounded-[var(--frankie-radius)] bg-primary px-3 py-2 text-sm text-primary-foreground\">{message.text}</div>\n <MessageCopyButton text={message.text} />\n </div>\n ) : null}\n </div>\n );\n }\n\n const empty = message.text.length === 0 && message.tools.length === 0;\n\n return (\n <div className=\"frankie-assistant-message flex gap-2\">\n <div className=\"frankie-assistant-actions mt-0.5 flex shrink-0 flex-col items-center gap-1\">\n <Avatar {...(avatarUrl ? { src: avatarUrl } : {})} name={assistantName} />\n {message.text ? <MessageCopyButton text={message.text} /> : null}\n </div>\n <div className=\"frankie-assistant-content min-w-0 max-w-[85%]\">\n {message.status === \"error\" ? (\n <p className=\"rounded-[var(--frankie-radius)] bg-red-500/10 px-3 py-2 text-sm text-red-600 dark:text-red-400\">\n {message.error}\n </p>\n ) : empty && message.status === \"streaming\" ? (\n <TypingDots />\n ) : (\n <Markdown text={message.text} className=\"text-sm\" />\n )}\n {showToolActivity ? (\n <ToolActivityList tools={message.tools} {...(renderTool ? { renderTool } : {})} />\n ) : null}\n </div>\n </div>\n );\n}\n\nfunction MessageCopyButton({ text }: { text: string }) {\n const [copied, setCopied] = useState(false);\n const copy = async () => {\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n window.setTimeout(() => setCopied(false), 1500);\n } catch { /* Clipboard access can be disabled by an embedding host. */ }\n };\n return <button type=\"button\" onClick={() => void copy()} className=\"frankie-message-copy inline-flex size-8 shrink-0 items-center justify-center rounded-md border border-transparent text-muted-foreground transition hover:border-border hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary\" aria-label={copied ? \"Copied\" : \"Copy message\"} title={copied ? \"Copied\" : \"Copy message\"}>{copied ? <Check className=\"size-3.5\" aria-hidden=\"true\" /> : <Copy className=\"size-3.5\" aria-hidden=\"true\" />}</button>;\n}\n\nexport function TypingDots() {\n return (\n <span className=\"frankie-thinking inline-flex items-center gap-1 py-2\" role=\"status\" aria-label=\"Thinking\">\n <span className=\"frankie-thinking-label\">Thinking</span>\n {[0, 1, 2].map((index) => (\n <span\n key={index}\n className={cn(\"size-1.5 animate-pulse rounded-full bg-muted-foreground\")}\n style={{ animationDelay: `${index * 150}ms` }}\n />\n ))}\n </span>\n );\n}\n\n","\"use client\";\n\nimport { Fragment, type ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * A deliberately small Markdown subset — paragraphs, lists, fenced code, bold,\n * italic, inline code and links.\n *\n * Everything is rendered as React elements; nothing goes through\n * `dangerouslySetInnerHTML`. Model output lands in someone else's production\n * page, so it is never trusted as markup.\n */\nexport function Markdown({ text, className }: { text: string; className?: string }) {\n return <div className={cn(\"frankie-prose\", className)}>{renderBlocks(text)}</div>;\n}\n\nfunction renderBlocks(text: string): ReactNode[] {\n const lines = text.split(\"\\n\");\n const blocks: ReactNode[] = [];\n let paragraph: string[] = [];\n let list: { ordered: boolean; items: string[] } | null = null;\n let code: { lang: string; lines: string[] } | null = null;\n\n const flushParagraph = () => {\n if (paragraph.length === 0) return;\n blocks.push(<p key={`p${blocks.length}`}>{renderInline(paragraph.join(\" \"))}</p>);\n paragraph = [];\n };\n const flushList = () => {\n if (!list) return;\n const items = list.items.map((item, index) => <li key={index}>{renderInline(item)}</li>);\n blocks.push(list.ordered ? <ol key={`l${blocks.length}`}>{items}</ol> : <ul key={`l${blocks.length}`}>{items}</ul>);\n list = null;\n };\n\n for (const line of lines) {\n const fence = /^```(\\w*)\\s*$/.exec(line);\n if (fence) {\n if (code) {\n blocks.push(\n <pre key={`c${blocks.length}`}>\n <code>{code.lines.join(\"\\n\")}</code>\n </pre>,\n );\n code = null;\n } else {\n flushParagraph();\n flushList();\n code = { lang: fence[1] ?? \"\", lines: [] };\n }\n continue;\n }\n if (code) {\n code.lines.push(line);\n continue;\n }\n\n const bullet = /^\\s*[-*+]\\s+(.*)$/.exec(line);\n const ordered = /^\\s*\\d+[.)]\\s+(.*)$/.exec(line);\n if (bullet ?? ordered) {\n flushParagraph();\n const isOrdered = Boolean(ordered);\n if (!list || list.ordered !== isOrdered) {\n flushList();\n list = { ordered: isOrdered, items: [] };\n }\n list.items.push((ordered?.[1] ?? bullet?.[1]) ?? \"\");\n continue;\n }\n\n if (line.trim() === \"\") {\n flushParagraph();\n flushList();\n continue;\n }\n\n const heading = /^#{1,6}\\s+(.*)$/.exec(line);\n if (heading) {\n flushParagraph();\n flushList();\n blocks.push(<p key={`h${blocks.length}`} className=\"font-semibold\">{renderInline(heading[1] ?? \"\")}</p>);\n continue;\n }\n\n flushList();\n paragraph.push(line.trim());\n }\n\n if (code) {\n blocks.push(\n <pre key={`c${blocks.length}`}>\n <code>{code.lines.join(\"\\n\")}</code>\n </pre>,\n );\n }\n flushParagraph();\n flushList();\n return blocks;\n}\n\nconst INLINE = /(\\*\\*[^*]+\\*\\*|`[^`]+`|\\[[^\\]]+\\]\\((?:https?:\\/\\/|\\/)[^)\\s]+\\)|\\bhttps?:\\/\\/[^\\s<>()]+)/g;\n\nfunction renderInline(text: string): ReactNode[] {\n const nodes: ReactNode[] = [];\n let lastIndex = 0;\n\n for (const match of text.matchAll(INLINE)) {\n const token = match[0];\n const start = match.index;\n if (start > lastIndex) nodes.push(text.slice(lastIndex, start));\n nodes.push(<Fragment key={start}>{renderToken(token)}</Fragment>);\n lastIndex = start + token.length;\n }\n\n if (lastIndex < text.length) nodes.push(text.slice(lastIndex));\n return nodes;\n}\n\nfunction renderToken(token: string): ReactNode {\n if (token.startsWith(\"**\")) return <strong>{token.slice(2, -2)}</strong>;\n if (token.startsWith(\"`\")) return <code>{token.slice(1, -1)}</code>;\n\n const link = /^\\[([^\\]]+)\\]\\(([^)]+)\\)$/.exec(token);\n const href = link ? (link[2] ?? \"\") : token;\n const label = link ? (link[1] ?? \"\") : token;\n\n // Only http(s) and same-site paths become links; anything else stays text,\n // so a model can never emit a `javascript:` href into the host page.\n if (!/^(https?:\\/\\/|\\/)/.test(href)) return token;\n return (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer nofollow\">\n {label}\n </a>\n );\n}\n","\"use client\";\n\nimport { Check, ChevronDown, Loader2, ShieldAlert, X } from \"lucide-react\";\nimport { Badge } from \"../ui/badge.js\";\nimport type { ToolActivity } from \"../../lib/messages.js\";\n\nexport interface ToolActivityListProps {\n tools: ToolActivity[];\n /** Replace the default row rendering entirely. */\n renderTool?: (tool: ToolActivity) => React.ReactNode;\n}\n\n/** The \"what the assistant is doing\" strip under a streaming answer. */\nexport function ToolActivityList({ tools, renderTool }: ToolActivityListProps) {\n if (tools.length === 0) return null;\n const running = tools.some((tool) => tool.status === \"running\");\n return (\n <details className=\"frankie-tool-activity mt-2\" open={running}>\n <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\">\n <ChevronDown className=\"frankie-tool-chevron size-3.5 transition-transform\" aria-hidden=\"true\" />\n <span>{running ? \"Working\" : \"Activity\"}</span>\n <span className=\"text-[11px]\">· {tools.length} tool call{tools.length === 1 ? \"\" : \"s\"}</span>\n </summary>\n <ul className=\"mt-1 flex flex-col gap-1 border-l border-border pl-2\">{tools.map((tool) => <li key={tool.id}>{renderTool ? renderTool(tool) : <ToolActivityRow tool={tool} />}</li>)}</ul>\n </details>\n );\n}\n\nexport function ToolActivityRow({ tool }: { tool: ToolActivity }) {\n return (\n <Badge variant={badgeVariant(tool.status)} title={tool.detail ?? tool.name}>\n <ToolIcon status={tool.status} />\n <span className=\"truncate\">{tool.label}</span>\n </Badge>\n );\n}\n\nfunction ToolIcon({ status }: { status: ToolActivity[\"status\"] }) {\n switch (status) {\n case \"running\":\n return <Loader2 className=\"size-3 animate-spin\" aria-hidden=\"true\" />;\n case \"done\":\n return <Check className=\"size-3\" aria-hidden=\"true\" />;\n case \"denied\":\n return <ShieldAlert className=\"size-3\" aria-hidden=\"true\" />;\n default:\n return <X className=\"size-3\" aria-hidden=\"true\" />;\n }\n}\n\nfunction badgeVariant(status: ToolActivity[\"status\"]): \"default\" | \"success\" | \"danger\" | \"outline\" {\n if (status === \"done\") return \"success\";\n if (status === \"failed\") return \"danger\";\n if (status === \"denied\") return \"outline\";\n return \"default\";\n}\n","\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\nconst badgeVariants = cva(\n \"inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[0.6875rem] font-medium\",\n {\n variants: {\n variant: {\n default: \"border-transparent bg-muted text-muted-foreground\",\n success: \"border-transparent bg-emerald-500/10 text-emerald-600 dark:text-emerald-400\",\n danger: \"border-transparent bg-red-500/10 text-red-600 dark:text-red-400\",\n outline: \"border-border text-muted-foreground\",\n },\n },\n defaultVariants: { variant: \"default\" },\n },\n);\n\nexport function Badge({\n className,\n variant,\n ...props\n}: HTMLAttributes<HTMLSpanElement> & VariantProps<typeof badgeVariants>) {\n return <span className={cn(badgeVariants({ variant }), className)} {...props} />;\n}\n","\"use client\";\n\nimport { Button } from \"../ui/button.js\";\n\nexport function SuggestedPrompts({\n prompts,\n onPick,\n disabled,\n}: {\n prompts: string[];\n onPick: (prompt: string) => void;\n disabled?: boolean;\n}) {\n if (prompts.length === 0) return null;\n return (\n <div className=\"flex flex-wrap gap-2\">\n {prompts.map((prompt) => (\n <Button\n key={prompt}\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={disabled}\n onClick={() => onPick(prompt)}\n >\n {prompt}\n </Button>\n ))}\n </div>\n );\n}\n","\"use client\";\n\nimport type { CSSProperties } from \"react\";\nimport { useFrankieTheme } from \"../../hooks/FrankieProvider.jsx\";\nimport { resolveMode, themeToCssVars } from \"../../lib/theme.js\";\nimport { cn } from \"../../lib/utils.js\";\nimport { ChatPanel, type ChatPanelProps } from \"./ChatPanel.js\";\n\nexport interface FrankieInlineProps extends ChatPanelProps {\n /** Extra styles on the filling wrapper — e.g. a `maxWidth` to centre the column. */\n style?: CSSProperties;\n}\n\n/**\n * Full-page (or any-container) chat: the panel fills its parent instead of\n * floating in a corner. Drop it into a route or a sized element — it brings its\n * own theme root, so it styles correctly wherever it lands.\n *\n * <div style={{ height: \"100dvh\" }}>\n * <FrankieProvider …><FrankieInline /></FrankieProvider>\n * </div>\n */\nexport function FrankieInline({ className, style, ...panelProps }: FrankieInlineProps) {\n const theme = useFrankieTheme();\n const mode = resolveMode(theme?.mode);\n return (\n <div\n className={cn(\"frankie-root frankie-inline\", mode === \"dark\" && \"dark\", className)}\n style={{ ...themeToCssVars(theme), display: \"flex\", height: \"100%\", width: \"100%\", ...style }}\n data-frankie-mode={mode}\n >\n <ChatPanel {...panelProps} fill />\n </div>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef, useState, type CSSProperties } from \"react\";\nimport { History, Menu, Plus, Settings, X } from \"lucide-react\";\nimport type { FrankieProviderProps } from \"../../hooks/FrankieProvider.jsx\";\nimport { FrankieProvider, useFrankie, useFrankieTheme } from \"../../hooks/FrankieProvider.jsx\";\nimport { useFrankieChat } from \"../../hooks/useFrankieChat.js\";\nimport { themeToCssVars, resolveMode } from \"../../lib/theme.js\";\nimport type { ChatConversation } from \"../../lib/client.js\";\nimport { FrankieInline } from \"./FrankieInline.js\";\nimport type { ChatPanelProps } from \"./ChatPanel.js\";\n\nexport interface FrankieChatPageProps extends Omit<FrankieProviderProps, \"children\">,\n Pick<ChatPanelProps, \"header\" | \"footer\" | \"emptyState\" | \"renderMessage\" | \"renderTool\" | \"placeholder\" | \"autoFocus\"> {\n className?: string;\n style?: CSSProperties;\n /** Include the built-in conversation sidebar. Defaults to true. */\n showHistory?: boolean;\n /** Optional host navigation, e.g. a Back to dashboard link. */\n navigation?: React.ReactNode;\n}\n\nfunction PageEmptyState() {\n const { config } = useFrankie();\n const { send, busy, restoring } = useFrankieChat();\n const name = config?.branding.name ?? \"Frankie\";\n return <section className=\"frankie-page-empty\" aria-label=\"Start a conversation\">\n <span className=\"frankie-page-avatar\" aria-hidden>{name.trim().slice(0, 1).toUpperCase()}</span>\n <div><p className=\"frankie-page-kicker\">Your product assistant</p><h1>How can I help?</h1><p>{config?.greeting ?? \"Ask a question or choose a task to get started.\"}</p></div>\n <div className=\"frankie-page-prompts\">{config?.suggestedPrompts?.slice(0, 3).map(prompt => <button key={prompt} type=\"button\" disabled={busy || restoring} onClick={() => void send(prompt)}><strong>{prompt}</strong><b aria-hidden>↗</b></button>)}</div>\n </section>;\n}\n\nfunction PageChrome({ showHistory, navigation, currentId, onSelect, onNew, ...panel }: Pick<FrankieChatPageProps, \"header\" | \"footer\" | \"emptyState\" | \"renderMessage\" | \"renderTool\" | \"placeholder\" | \"autoFocus\" | \"navigation\"> & { showHistory: boolean; currentId: string; onSelect: (id: string) => void; onNew: () => void }) {\n const { client, config } = useFrankie();\n const { busy, messages } = useFrankieChat();\n const theme = useFrankieTheme();\n const [conversations, setConversations] = useState<ChatConversation[]>([]);\n const [historyError, setHistoryError] = useState(\"\");\n const [historyLoading, setHistoryLoading] = useState(false);\n const [drawerOpen, setDrawerOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const dialog = useRef<HTMLDialogElement>(null);\n const menu = useRef<HTMLButtonElement>(null);\n const requestVersion = useRef(0);\n const refresh = useCallback(async () => {\n if (!showHistory || !config || config.allowAnonymous) { setHistoryError(\"\"); return; }\n const version = ++requestVersion.current;\n setHistoryLoading(true); setHistoryError(\"\");\n try { const items = await client.listConversations(); if (version === requestVersion.current) setConversations(items); }\n catch { if (version === requestVersion.current) setHistoryError(\"History couldn’t load. Check your sign-in and try again.\"); }\n finally { if (version === requestVersion.current) setHistoryLoading(false); }\n }, [client, showHistory, config?.allowAnonymous]);\n useEffect(() => { if (!busy) void refresh(); return () => { requestVersion.current++; }; }, [refresh, busy]);\n useEffect(() => {\n const node = dialog.current;\n if (drawerOpen) { node?.showModal?.(); }\n else { node?.close?.(); }\n }, [drawerOpen]);\n const close = () => { setDrawerOpen(false); menu.current?.focus(); };\n const select = (id: string) => { if (!busy) { onSelect(id); close(); } };\n const history = <>\n <div className=\"frankie-history-heading\"><strong>Conversations</strong><button type=\"button\" className=\"frankie-mobile-only\" aria-label=\"Close conversations\" onClick={close}><X size={18} /></button></div>\n <button type=\"button\" className=\"frankie-new-chat\" disabled={busy} onClick={() => { onNew(); close(); }}><Plus size={17} />New chat</button>\n <label className=\"frankie-history-search\"><span>Search conversations</span><input type=\"search\" placeholder=\"Search chats…\" value={query} onChange={event => setQuery(event.target.value)} /></label>\n <nav className=\"frankie-history-list\" aria-label=\"Conversations\">{conversations.filter(item => item.title.toLowerCase().includes(query.toLowerCase())).map(item => <button type=\"button\" key={item.id} aria-current={item.id === currentId ? \"page\" : undefined} disabled={busy} onClick={() => select(item.id)}><span>{item.title}</span><small>{new Date(item.updatedAt).toLocaleDateString()}</small></button>)}</nav>\n {historyLoading ? <p role=\"status\">Loading history…</p> : historyError ? <p role=\"status\">{historyError}<button type=\"button\" onClick={() => void refresh()}>Try again</button></p> : !conversations.length ? <p>{config?.allowAnonymous ? \"Sign in to sync conversations across devices.\" : \"Your conversations will appear here.\"}</p> : null}\n {navigation ? <div className=\"frankie-host-navigation\">{navigation}</div> : null}\n </>;\n return <div className={\"frankie-page-shell\" + (resolveMode(theme?.mode) === \"dark\" ? \" dark\" : \"\")} style={themeToCssVars(theme)}>\n {showHistory ? <aside className=\"frankie-history-desktop\">{history}</aside> : null}\n <div className=\"frankie-page-main\">\n <header className=\"frankie-page-header\"><div>{showHistory ? <button type=\"button\" className=\"frankie-mobile-only\" ref={menu} aria-label=\"Open conversations\" aria-haspopup=\"dialog\" aria-expanded={drawerOpen} onClick={() => setDrawerOpen(true)}><Menu size={20} /></button> : null}<strong className=\"frankie-thread-title\">{conversations.find(item => item.id === currentId)?.title ?? messages.find(message => message.role === \"user\")?.text ?? \"New chat\"}</strong></div><div>\n <button type=\"button\" disabled={busy} onClick={onNew} aria-label=\"Start a new conversation\"><Plus size={16} /><span>New chat</span></button>\n <details className=\"frankie-chat-settings\"><summary aria-label=\"Chat settings\"><Settings size={19} /></summary><div><strong>Chat settings</strong><p>History syncs automatically for signed-in users.</p><button type=\"button\" onClick={() => void refresh()} disabled={historyLoading || !showHistory}><History size={16} />Refresh history</button><small>Skills are checked at the start of each message.</small></div></details>\n </div></header>\n <div className=\"frankie-page-canvas\"><FrankieInline {...panel} header={panel.header ?? false} emptyState={panel.emptyState ?? <PageEmptyState />} /></div>\n </div>\n {showHistory ? <dialog ref={dialog} className=\"frankie-history-dialog frankie-root\" aria-label=\"Chat conversations\" style={themeToCssVars(theme)} onCancel={close} onClick={event => { if (event.target === event.currentTarget) close(); }}><aside>{history}</aside></dialog> : null}\n </div>;\n}\n\n/** Reusable product chat with one shared conversation state and scoped styling. */\nexport function FrankieChatPage({ className, style, header, footer, emptyState, renderMessage, renderTool, placeholder, autoFocus, showHistory = true, navigation, ...provider }: FrankieChatPageProps) {\n const [id, setId] = useState(() => provider.conversationId ?? crypto.randomUUID());\n const onNew = () => setId(crypto.randomUUID());\n return <div className={[\"frankie-root\", \"frankie-chat-page\", className].filter(Boolean).join(\" \")} style={{ height: \"100%\", minHeight: \"min(36rem, 100dvh)\", width: \"100%\", ...style }}>\n <FrankieProvider {...provider} conversationId={id} storageNamespace={(provider.storageNamespace ?? \"frankie.\" + provider.publishableKey) + \".\" + id}>\n <PageChrome showHistory={showHistory} navigation={navigation} currentId={id} onSelect={setId} onNew={onNew} header={header} footer={footer} emptyState={emptyState} renderMessage={renderMessage} renderTool={renderTool} placeholder={placeholder} autoFocus={autoFocus} />\n </FrankieProvider>\n </div>;\n}\n","\"use client\";\n\nimport { cn } from \"../../lib/utils.js\";\n\nexport function Separator({ className }: { className?: string }) {\n return <div role=\"separator\" className={cn(\"h-px w-full bg-border\", className)} />;\n}\n"],"mappings":"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","names":["createContext","useContext","useEffect","useRef","useState","createContext","useRef","useState","useEffect","useContext","X","useEffect","useState","jsx","X","useEffect","useRef","useState","jsx","jsx","jsx","ScrollArea","jsx","useCallback","useEffect","useRef","useState","forwardRef","jsx","forwardRef","Textarea","jsx","jsxs","useState","useRef","useEffect","useCallback","Check","Paperclip","useState","Fragment","jsx","Fragment","X","cva","jsx","cva","jsx","jsxs","X","jsx","jsxs","Paperclip","useState","Check","jsx","jsx","jsxs","useRef","useState","useEffect","X","jsx","jsxs","useState","useEffect","X","jsx","useCallback","useEffect","useRef","useState","Plus","X","Fragment","jsx","jsxs","useState","useRef","useCallback","useEffect","X","Plus","jsx"]}