juneau 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/components/AiChat/AiChat.d.ts +9 -1
- package/dist/components/AiChat/AiChat.d.ts.map +1 -1
- package/dist/components/AiInput/AiInput.d.ts.map +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +659 -628
- package/dist/index.js.map +1 -1
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +86 -86
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/core/stream.ts","../src/core/history.ts","../src/adapters/mockAdapter.ts","../src/adapters/parseJuneauWire.ts","../src/adapters/createSseAdapter.ts","../src/adapters/createFetchStreamAdapter.ts","../src/hooks/useAiChat.ts","../src/i18n/locales/en.ts","../src/i18n/context.ts","../src/components/JuneauProvider/JuneauProvider.tsx","../src/context/AiChatContext.ts","../src/context/AiChatProvider.tsx","../src/i18n/locales/cs.ts","../src/components/icons.tsx","../src/components/parts/AiTablePart.tsx","../src/components/parts/AiProposalCard.tsx","../src/components/parts/AiActivityPart.tsx","../src/components/parts/AiEntityCard.tsx","../src/components/parts/AiEntityListPart.tsx","../src/components/parts/AiMessagePartRenderer.tsx","../src/components/AiMessageBubble/AiMessageBubble.tsx","../src/components/AiTypingIndicator/AiTypingIndicator.tsx","../src/components/AiMessageList/AiMessageList.tsx","../src/components/AiInput/AiInput.tsx","../src/components/AiError/AiError.tsx","../src/components/AiChat/AiChat.tsx","../src/components/AiChatHeader/AiChatHeader.tsx","../src/components/AiSidebar/AiSidebar.tsx","../src/components/AiChatHistoryList/AiChatHistoryList.tsx"],"sourcesContent":["import type { AiMessage, AiStreamEvent } from './types';\r\n\r\n/**\r\n * Prepares a message history array for sending to the backend adapter —\r\n * the exact same transformation Juneau applies internally before every request.\r\n *\r\n * Assistant messages that contain only activity or error parts (no text) are\r\n * replaced with an empty-text assistant turn so conversation alternation stays\r\n * valid. Models reject histories where two user messages appear consecutively\r\n * with no assistant turn in between.\r\n *\r\n * Use this to inspect or replicate what Juneau actually sends, e.g. when\r\n * building a custom adapter or debugging history shape:\r\n *\r\n * @example\r\n * const wire = serializeMessages(messages);\r\n * console.log(JSON.stringify(wire, null, 2));\r\n */\r\nexport function serializeMessages(messages: AiMessage[]): AiMessage[] {\r\n return messages.map(msg => {\r\n if (msg.role !== 'assistant') return msg;\r\n if (msg.parts.some(p => p.type === 'text')) return msg;\r\n return { ...msg, parts: [{ type: 'text' as const, text: '' }] };\r\n });\r\n}\r\n\r\nexport const delay = (ms: number): Promise<void> =>\r\n new Promise(resolve => setTimeout(resolve, ms));\r\n\r\n/**\r\n * Extracts the plain text content from a message.\r\n *\r\n * Concatenates all `text` parts in order. Non-text parts (tables, proposals,\r\n * errors) are skipped. Returns an empty string if the message has no text parts.\r\n *\r\n * Use this in your adapter when you need to read a message's text without\r\n * digging into the parts array yourself:\r\n *\r\n * @example\r\n * const { messages } = input;\r\n * const lastUser = [...messages].reverse().find(m => m.role === 'user');\r\n * const text = lastUser ? getMessageText(lastUser) : '';\r\n */\r\nexport function getMessageText(message: AiMessage): string {\r\n return message.parts\r\n .filter((p): p is import('./types').AiTextPart => p.type === 'text')\r\n .map(p => p.text)\r\n .join('');\r\n}\r\n\r\n/**\r\n * Iterates over an AsyncIterable of stream events and calls the handler for each.\r\n * Automatically handles cancellation via AbortSignal.\r\n */\r\nexport async function consumeStream(\r\n iterable: AsyncIterable<AiStreamEvent>,\r\n onEvent: (event: AiStreamEvent) => void,\r\n signal?: AbortSignal\r\n): Promise<void> {\r\n for await (const event of iterable) {\r\n if (signal?.aborted) break;\r\n onEvent(event);\r\n if (event.type === 'done' || event.type === 'error') break;\r\n }\r\n}\r\n","import type {\r\n AiChartPart,\r\n AiChatSummary,\r\n AiMessage,\r\n AiMessagePart,\r\n AiProposalPart,\r\n AiSerializedMessage,\r\n} from './types';\r\n\r\n/**\r\n * Narrows a part to a proposal. Needed because `AiCustomPart`'s index\r\n * signature keeps TypeScript from narrowing the union on `type` alone.\r\n */\r\nexport function isProposalPart(part: AiMessagePart): part is AiProposalPart {\r\n return part.type === 'proposal';\r\n}\r\n\r\n/**\r\n * Narrows a part to a chart. Checks structure, not just `type` — chart parts\r\n * may be restored from persisted history written by older consumers.\r\n */\r\nexport function isChartPart(part: AiMessagePart): part is AiChartPart {\r\n return part.type === 'chart' && Array.isArray((part as AiChartPart).series);\r\n}\r\n\r\n/**\r\n * Prepares messages for persistence. Returns plain JSON-safe objects:\r\n *\r\n * - `createdAt` dates become ISO strings\r\n * - unresolved proposals are marked `resolved: 'expired'` so a restored card\r\n * can never fire callbacks against a stale payload\r\n * - `running` activity parts are dropped — a restored \"in progress\" row would\r\n * look permanently stuck\r\n *\r\n * @example\r\n * localStorage.setItem('chat', JSON.stringify(serializeForStorage(messages)));\r\n */\r\n/** Current persistence format version written by {@link serializeForStorage}. */\r\nconst STORAGE_FORMAT_VERSION = 1;\r\n\r\nexport function serializeForStorage(messages: AiMessage[]): AiSerializedMessage[] {\r\n return messages.map(msg => ({\r\n ...msg,\r\n v: STORAGE_FORMAT_VERSION,\r\n createdAt: msg.createdAt.toISOString(),\r\n parts: msg.parts\r\n .filter(part => !(part.type === 'activity' && part.status === 'running'))\r\n .map(sanitizePart),\r\n }));\r\n}\r\n\r\nfunction sanitizePart(part: AiMessagePart): AiMessagePart {\r\n if (isProposalPart(part) && !part.proposal.resolved) {\r\n return { ...part, proposal: { ...part.proposal, resolved: 'expired' } };\r\n }\r\n return part;\r\n}\r\n\r\n/**\r\n * Restores messages persisted with {@link serializeForStorage} back into the\r\n * live `AiMessage[]` shape Juneau expects — revives `createdAt` dates.\r\n * Accepts the parsed JSON value, not the raw string.\r\n *\r\n * @example\r\n * const stored = JSON.parse(localStorage.getItem('chat') ?? '[]');\r\n * const messages = deserializeMessages(stored);\r\n */\r\nexport function deserializeMessages(stored: AiSerializedMessage[]): AiMessage[] {\r\n // Missing `v` means v1 (pre-versioned histories) — same shape, parses as-is\r\n return stored.map(({ v: _v, ...msg }) => ({\r\n ...msg,\r\n createdAt: new Date(msg.createdAt),\r\n }));\r\n}\r\n\r\n/**\r\n * Trims a conversation to at most `limit` messages for sending to the model,\r\n * keeping the most recent ones. Purely a token-saving measure — rendering is\r\n * never trimmed.\r\n *\r\n * The cut never lands mid-exchange: if the oldest surviving message is an\r\n * assistant turn, it is dropped too, so the history always starts with a user\r\n * (or system) message and alternation stays valid.\r\n */\r\nexport function trimHistory(messages: AiMessage[], limit: number): AiMessage[] {\r\n if (limit <= 0 || messages.length <= limit) return messages;\r\n let start = messages.length - limit;\r\n while (start < messages.length && messages[start].role === 'assistant') {\r\n start++;\r\n }\r\n return messages.slice(start);\r\n}\r\n\r\n/**\r\n * Enforces an overall chats limit: returns the `limit` most recently updated\r\n * chats. Use the returned list to know which chats to keep; delete the rest\r\n * from your storage.\r\n */\r\nexport function trimChats(chats: AiChatSummary[], limit: number): AiChatSummary[] {\r\n if (limit <= 0 || chats.length <= limit) return [...chats].sort(byUpdatedDesc);\r\n return [...chats].sort(byUpdatedDesc).slice(0, limit);\r\n}\r\n\r\nconst byUpdatedDesc = (a: AiChatSummary, b: AiChatSummary): number =>\r\n b.updatedAt.getTime() - a.updatedAt.getTime();\r\n","import { delay, getMessageText } from '../core/stream';\nimport type { AiBackendAdapter, AiAdapterInput, AiStreamEvent } from '../core/types';\n\n/**\n * Simulates AI streaming responses for development and testing.\n * Triggers different scenarios based on keywords in the last user message.\n * Replace with a real adapter (OpenAI, Anthropic, custom backend) in production.\n */\nexport const mockAdapter: AiBackendAdapter = {\n async *sendMessage(input: AiAdapterInput): AsyncIterable<AiStreamEvent> {\n const lastUserMessage = [...input.messages].reverse().find(m => m.role === 'user');\n const query = lastUserMessage ? getMessageText(lastUserMessage).toLowerCase() : '';\n\n if (query.includes('activity') || query.includes('progress') || query.includes('document') || query.includes('dokument')) {\n yield* scenarioActivity();\n } else if (query.includes('table') || query.includes('data') || query.includes('list') || query.includes('show')) {\n yield* scenarioTable();\n } else if (query.includes('proposal') || query.includes('suggest') || query.includes('recommend')) {\n yield* scenarioProposal();\n } else if (query.includes('entity') || query.includes('card') || query.includes('detail') || query.includes('find')) {\n yield* scenarioEntity();\n } else if (query.includes('help') || query.includes('what can') || query.includes('how do')) {\n yield* scenarioHelp();\n } else if (query.includes('error') || query.includes('fail') || query.includes('break')) {\n yield* scenarioError();\n } else {\n yield* scenarioDefault(query);\n }\n }\n};\n\nasync function* scenarioActivity(): AsyncIterable<AiStreamEvent> {\n yield {\n type: 'part',\n part: {\n type: 'activity',\n id: 'select-skill',\n title: 'Selecting skill',\n description: 'Looking for the best skill for this request.',\n status: 'running',\n },\n };\n\n await delay(700);\n\n yield {\n type: 'part',\n part: {\n type: 'activity',\n id: 'select-skill',\n title: 'Skill selected',\n description: 'Using Document Search.',\n status: 'done',\n },\n };\n\n await delay(300);\n\n yield {\n type: 'part',\n part: {\n type: 'activity',\n id: 'search-document',\n title: 'Searching document',\n description: 'Looking up document by ID.',\n status: 'running',\n },\n };\n\n await delay(900);\n\n yield {\n type: 'part',\n part: {\n type: 'activity',\n id: 'search-document',\n title: 'Document found',\n description: 'Found document INV-2024-0894.',\n status: 'done',\n },\n };\n\n await delay(300);\n\n yield* streamText('\\nFound document **INV-2024-0894** from **DataSys a.s.** for **CZK 390 000**.', 25);\n yield { type: 'done' };\n}\n\nasync function* scenarioTable(): AsyncIterable<AiStreamEvent> {\n yield* streamText('Here is a summary of the data you requested:\\n\\n', 30);\n await delay(400);\n\n yield {\n type: 'part',\n part: {\n type: 'table',\n columns: ['Name', 'Category', 'Value', 'Status'],\n rows: [\n { Name: 'Item Alpha', Category: 'Type A', Value: '1,200', Status: 'Active' },\n { Name: 'Item Beta', Category: 'Type B', Value: '840', Status: 'Active' },\n { Name: 'Item Gamma', Category: 'Type A', Value: '3,050', Status: 'Pending' },\n { Name: 'Item Delta', Category: 'Type C', Value: '610', Status: 'Inactive' },\n { Name: 'Item Epsilon', Category: 'Type B', Value: '2,200', Status: 'Active' },\n ]\n }\n };\n\n await delay(300);\n yield* streamText('\\nTotal across all entries: **7,900** — Type A accounts for the largest share at 53%.', 25);\n yield { type: 'done' };\n}\n\nasync function* scenarioProposal(): AsyncIterable<AiStreamEvent> {\n yield* streamText('Based on the current data, I have a suggestion for you:\\n\\n', 30);\n await delay(500);\n\n yield {\n type: 'part',\n part: {\n type: 'proposal',\n proposal: {\n id: 'mock-proposal-1',\n title: 'Save this as a recurring report',\n description: 'This summary can be automatically generated on a schedule so you always have up-to-date insights.',\n confirmLabel: 'Save report',\n cancelLabel: 'Dismiss',\n payload: { reportType: 'summary', schedule: 'weekly' }\n }\n }\n };\n\n yield { type: 'done' };\n}\n\nasync function* scenarioEntity(): AsyncIterable<AiStreamEvent> {\n yield* streamText('I found these records matching your request:\\n\\n', 30);\n await delay(400);\n\n yield {\n type: 'part',\n part: {\n type: 'entity-list',\n title: '2 records found',\n entityType: 'record',\n entities: [\n {\n id: 'rec-2024-0894',\n title: 'REC-2024-0894',\n subtitle: 'DataSys a.s.',\n fields: [\n { label: 'Amount', value: 'CZK 390 000' },\n { label: 'Due date', value: '2024-08-15' },\n { label: 'Status', value: 'Approved', badge: 'success' },\n ],\n },\n {\n id: 'rec-2024-0895',\n title: 'REC-2024-0895',\n subtitle: 'NetFlow s.r.o.',\n fields: [\n { label: 'Amount', value: 'CZK 218 500' },\n { label: 'Due date', value: '2024-08-22' },\n { label: 'Status', value: 'Pending', badge: 'warning' },\n ],\n },\n ],\n },\n };\n\n await delay(300);\n\n yield* streamText('\\nHere is the detail of the first one:\\n\\n', 25);\n await delay(300);\n\n yield {\n type: 'part',\n part: {\n type: 'entity',\n entityType: 'record',\n entity: {\n id: 'rec-2024-0894',\n title: 'REC-2024-0894',\n subtitle: 'DataSys a.s. — Consulting',\n fields: [\n { label: 'Amount', value: 'CZK 390 000' },\n { label: 'Issued', value: '2024-07-15' },\n { label: 'Due date', value: '2024-08-15' },\n { label: 'Status', value: 'Approved', badge: 'success' },\n ],\n },\n },\n };\n\n yield { type: 'done' };\n}\n\nasync function* scenarioHelp(): AsyncIterable<AiStreamEvent> {\n yield* streamText('I\\'m a general-purpose AI assistant. Here\\'s what I can help with:\\n\\n', 30);\n await delay(200);\n yield* streamText('- **Summarise data** — ask me to show, list, or summarise information\\n', 22);\n await delay(150);\n yield* streamText('- **Make suggestions** — ask me to recommend or propose something\\n', 22);\n await delay(150);\n yield* streamText('- **Answer questions** — ask me anything and I\\'ll do my best\\n', 22);\n await delay(200);\n yield* streamText('\\nTry asking: *\"Show me the data\"* or *\"Can you suggest something?\"*', 25);\n yield { type: 'done' };\n}\n\nasync function* scenarioError(): AsyncIterable<AiStreamEvent> {\n yield* streamText('Attempting to process your request…', 30);\n await delay(800);\n yield { type: 'error', message: 'Simulated error: the upstream service returned an unexpected response.' };\n}\n\nasync function* scenarioDefault(query: string): AsyncIterable<AiStreamEvent> {\n yield* streamText(`Got it — you asked about *\"${query || 'your request'}\"*.\\n\\n`, 30);\n await delay(400);\n yield* streamText('I\\'m a **mock adapter** used for development. I respond to a few trigger words:\\n\\n', 25);\n await delay(200);\n yield* streamText('- Say **\"show\"**, **\"list\"**, **\"data\"**, or **\"table\"** → renders a data table\\n', 22);\n await delay(150);\n yield* streamText('- Say **\"suggest\"**, **\"recommend\"**, or **\"proposal\"** → renders a proposal card\\n', 22);\n await delay(150);\n yield* streamText('- Say **\"entity\"**, **\"card\"**, **\"detail\"**, or **\"find\"** → renders entity cards\\n', 22);\n await delay(150);\n yield* streamText('- Say **\"help\"** or **\"what can you do\"** → shows capabilities\\n', 22);\n await delay(150);\n yield* streamText('- Say **\"error\"** or **\"fail\"** → simulates an error response\\n', 22);\n yield { type: 'done' };\n}\n\nasync function* streamText(text: string, chunkDelayMs: number): AsyncIterable<AiStreamEvent> {\n const chunkSize = 3;\n for (let i = 0; i < text.length; i += chunkSize) {\n yield { type: 'text', text: text.slice(i, i + chunkSize) };\n await delay(chunkDelayMs);\n }\n}\n","import type { AiStreamEvent, JuneauWireEvent } from '../core/types';\r\n\r\n/**\r\n * Parses a single JSON string as a Juneau wire protocol event and maps it\r\n * to one or more AiStreamEvents.\r\n *\r\n * Used by both createSseAdapter and createFetchStreamAdapter as their default\r\n * parser when the backend streams Juneau-compatible JSON.\r\n *\r\n * Returns an empty array for unrecognised or unparseable input — never throws.\r\n */\r\nexport function parseJuneauWire(raw: string): AiStreamEvent[] {\r\n if (!raw || raw === '[DONE]') return [];\r\n\r\n let wire: JuneauWireEvent;\r\n try {\r\n wire = JSON.parse(raw) as JuneauWireEvent;\r\n } catch {\r\n return [];\r\n }\r\n\r\n switch (wire.type) {\r\n case 'text':\r\n return wire.text ? [{ type: 'text', text: wire.text }] : [];\r\n\r\n case 'activity':\r\n return [{\r\n type: 'part',\r\n part: {\r\n type: 'activity',\r\n id: wire.id,\r\n title: wire.title,\r\n description: wire.description,\r\n status: wire.status,\r\n metadata: wire.metadata,\r\n },\r\n }];\r\n\r\n case 'part':\r\n return [{ type: 'part', part: wire.part }];\r\n\r\n case 'done':\r\n return [{ type: 'done' }];\r\n\r\n case 'error':\r\n return [{ type: 'error', message: wire.message }];\r\n\r\n default:\r\n return [];\r\n }\r\n}\r\n","import type { AiBackendAdapter, AiAdapterInput, AiStreamEvent, JuneauWireEvent } from '../core/types';\r\nimport { parseJuneauWire } from './parseJuneauWire';\r\n\r\n/**\r\n * How to map a parsed SSE data payload to Juneau stream events.\r\n *\r\n * Return an array — most lines produce one event, but you can return multiple\r\n * or an empty array to skip a line entirely.\r\n */\r\nexport type SseEventParser = (data: string) => AiStreamEvent[];\r\n\r\n/**\r\n * Options for createSseAdapter.\r\n */\r\nexport type SseAdapterOptions = {\r\n /**\r\n * HTTP method. Defaults to 'POST'.\r\n */\r\n method?: string;\r\n\r\n /**\r\n * Static headers merged with Content-Type. Use for auth tokens etc.\r\n * For dynamic headers (e.g. per-request auth), use getHeaders instead.\r\n *\r\n * @example { Authorization: 'Bearer sk-...' }\r\n */\r\n headers?: Record<string, string>;\r\n\r\n /**\r\n * Dynamic headers — called before every request with the current adapter input.\r\n * Merged on top of `headers`. Use this when the token is fetched at runtime.\r\n */\r\n getHeaders?: (input: AiAdapterInput) => Record<string, string> | Promise<Record<string, string>>;\r\n\r\n /**\r\n * Override the request body. By default sends `{ messages, context }`.\r\n * Return anything JSON-serialisable.\r\n */\r\n getBody?: (input: AiAdapterInput) => unknown;\r\n\r\n /**\r\n * Transform the message history before it is sent to the backend.\r\n * Called with the full `AiMessage[]` that would normally be sent and must\r\n * return the transformed array (or a promise of one).\r\n *\r\n * Use this to remap roles, filter messages, or convert to a backend-specific\r\n * schema without having to write a full custom adapter.\r\n *\r\n * @example\r\n * // Strip system messages before sending:\r\n * getMessages: (msgs) => msgs.filter(m => m.role !== 'system')\r\n *\r\n * @example\r\n * // Convert to Anthropic SDK message format:\r\n * getMessages: (msgs) => toSdkMessages(msgs)\r\n */\r\n getMessages?: (messages: AiAdapterInput['messages']) => AiAdapterInput['messages'] | Promise<AiAdapterInput['messages']>;\r\n\r\n /**\r\n * Credentials mode passed to fetch. Use `'include'` for cross-origin requests\r\n * that require cookies (e.g. session-based auth to a different domain).\r\n * Defaults to browser default (`'same-origin'`).\r\n *\r\n * @example\r\n * credentials: 'include'\r\n */\r\n credentials?: RequestCredentials;\r\n\r\n /**\r\n * Custom SSE line parser. Receives the raw string after `data: ` and returns\r\n * zero or more Juneau stream events.\r\n *\r\n * Defaults to an OpenAI-compatible parser that reads\r\n * `choices[0].delta.content` and handles `[DONE]`.\r\n *\r\n * @example\r\n * // For a backend that streams { text: \"...\" } JSON lines:\r\n * parseEvent: (data) => {\r\n * const json = JSON.parse(data);\r\n * return json.text ? [{ type: 'text', text: json.text }] : [];\r\n * }\r\n */\r\n parseEvent?: SseEventParser;\r\n};\r\n\r\n/**\r\n * Creates an adapter that connects to a **Server-Sent Events (SSE)** streaming\r\n * endpoint — the format used by OpenAI, Anthropic, and most AI backend proxies.\r\n *\r\n * The default parser understands OpenAI's streaming format out of the box.\r\n * Override `parseEvent` for any other SSE schema.\r\n *\r\n * @example\r\n * // OpenAI-compatible backend proxy — works with zero configuration:\r\n * const adapter = createSseAdapter('/api/chat');\r\n *\r\n * @example\r\n * // With auth header:\r\n * const adapter = createSseAdapter('/api/chat', {\r\n * getHeaders: async () => ({\r\n * Authorization: `Bearer ${await getToken()}`,\r\n * }),\r\n * });\r\n *\r\n * @example\r\n * // Custom body shape:\r\n * const adapter = createSseAdapter('/api/chat', {\r\n * getBody: ({ messages, context }) => ({\r\n * messages,\r\n * model: 'gpt-4o',\r\n * stream: true,\r\n * ...(context?.systemPrompt ? { system: context.systemPrompt } : {}),\r\n * }),\r\n * });\r\n *\r\n * @example\r\n * // Custom SSE schema (backend streams { text: \"...\" }):\r\n * const adapter = createSseAdapter('/api/chat', {\r\n * parseEvent: (data) => {\r\n * try {\r\n * const json = JSON.parse(data);\r\n * return json.text ? [{ type: 'text', text: json.text }] : [];\r\n * } catch {\r\n * return [];\r\n * }\r\n * },\r\n * });\r\n */\r\nexport function createSseAdapter(url: string, options: SseAdapterOptions = {}): AiBackendAdapter {\r\n const {\r\n method = 'POST',\r\n headers: staticHeaders = {},\r\n getHeaders,\r\n getBody,\r\n getMessages,\r\n parseEvent = defaultOpenAiParser,\r\n credentials,\r\n } = options;\r\n\r\n return {\r\n async *sendMessage(input: AiAdapterInput): AsyncIterable<AiStreamEvent> {\r\n const dynamicHeaders = getHeaders ? await getHeaders(input) : {};\r\n\r\n const messages = getMessages ? await getMessages(input.messages) : input.messages;\r\n const resolvedInput: AiAdapterInput = { ...input, messages };\r\n\r\n const body = getBody\r\n ? getBody(resolvedInput)\r\n : { messages: resolvedInput.messages, context: resolvedInput.context };\r\n\r\n const response = await fetch(url, {\r\n method,\r\n credentials,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...staticHeaders,\r\n ...dynamicHeaders,\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!response.ok) {\r\n const message = await response.text().catch(() => `HTTP ${response.status}`);\r\n yield { type: 'error', message: `Request failed (${response.status}): ${message}` };\r\n return;\r\n }\r\n\r\n if (!response.body) {\r\n yield { type: 'error', message: 'Response body is empty — server may not support streaming.' };\r\n return;\r\n }\r\n\r\n yield* readSseStream(response.body, parseEvent);\r\n },\r\n };\r\n}\r\n\r\n// ─── SSE stream reader ────────────────────────────────────────────────────────\r\n\r\nasync function* readSseStream(\r\n body: ReadableStream<Uint8Array>,\r\n parseEvent: SseEventParser,\r\n): AsyncIterable<AiStreamEvent> {\r\n const reader = body.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n\r\n // SSE lines are separated by \\n\\n (double newline)\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() ?? ''; // keep the incomplete last line\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n if (!trimmed || trimmed.startsWith(':')) continue; // empty or SSE comment\r\n\r\n if (trimmed.startsWith('data: ')) {\r\n const data = trimmed.slice(6); // strip \"data: \"\r\n\r\n if (data === '[DONE]') {\r\n yield { type: 'done' };\r\n return;\r\n }\r\n\r\n const events = parseEvent(data);\r\n for (const event of events) {\r\n yield event;\r\n if (event.type === 'done' || event.type === 'error') return;\r\n }\r\n }\r\n }\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n\r\n yield { type: 'done' };\r\n}\r\n\r\n// ─── Default parser ───────────────────────────────────────────────────────────\r\n//\r\n// Tries Juneau wire protocol first. If the line looks like an OpenAI streaming\r\n// response instead (choices[0].delta.content), falls back to that so the adapter\r\n// works out of the box with OpenAI-compatible backends too.\r\n\r\nconst defaultOpenAiParser: SseEventParser = (data) => {\r\n if (!data || data === '[DONE]') return [];\r\n\r\n // Try Juneau wire protocol first\r\n const wire = parseJuneauWire(data);\r\n if (wire.length > 0) return wire;\r\n\r\n // Fallback: OpenAI chat completions streaming format\r\n try {\r\n const json = JSON.parse(data) as {\r\n choices?: Array<{ delta?: { content?: string | null }; finish_reason?: string | null }>;\r\n error?: { message?: string };\r\n };\r\n\r\n if (json.error?.message) {\r\n return [{ type: 'error', message: json.error.message }];\r\n }\r\n\r\n const delta = json.choices?.[0]?.delta;\r\n const finishReason = json.choices?.[0]?.finish_reason;\r\n\r\n if (finishReason === 'stop') return [{ type: 'done' }];\r\n if (delta?.content) return [{ type: 'text', text: delta.content }];\r\n\r\n return [];\r\n } catch {\r\n return [];\r\n }\r\n};\r\n","import type { AiBackendAdapter, AiAdapterInput, AiStreamEvent, JuneauWireEvent } from '../core/types';\r\nimport { parseJuneauWire } from './parseJuneauWire';\r\n\r\n/**\r\n * How to map a raw text chunk from the response body to Juneau stream events.\r\n *\r\n * Return an array — a chunk may produce one event, multiple, or none (empty array to skip).\r\n * The chunk is whatever the server sent — could be a full JSON line, a partial one,\r\n * or plain text depending on your backend.\r\n */\r\nexport type FetchChunkParser = (chunk: string) => AiStreamEvent[];\r\n\r\n/**\r\n * Options for createFetchStreamAdapter.\r\n */\r\nexport type FetchStreamAdapterOptions = {\r\n /**\r\n * HTTP method. Defaults to 'POST'.\r\n */\r\n method?: string;\r\n\r\n /**\r\n * Static headers merged with Content-Type. Use for auth tokens etc.\r\n * For dynamic headers (e.g. per-request auth), use getHeaders instead.\r\n *\r\n * @example { Authorization: 'Bearer sk-...' }\r\n */\r\n headers?: Record<string, string>;\r\n\r\n /**\r\n * Dynamic headers — called before every request with the current adapter input.\r\n * Merged on top of `headers`. Use this when the token is fetched at runtime.\r\n */\r\n getHeaders?: (input: AiAdapterInput) => Record<string, string> | Promise<Record<string, string>>;\r\n\r\n /**\r\n * Override the request body. By default sends `{ messages, context }`.\r\n * Return anything JSON-serialisable.\r\n */\r\n getBody?: (input: AiAdapterInput) => unknown;\r\n\r\n /**\r\n * Credentials mode passed to fetch. Use `'include'` for cross-origin requests\r\n * that require cookies (e.g. session-based auth to a different domain).\r\n * Defaults to browser default (`'same-origin'`).\r\n *\r\n * @example\r\n * credentials: 'include'\r\n */\r\n credentials?: RequestCredentials;\r\n\r\n /**\r\n * How to parse each chunk from the response stream into Juneau events.\r\n *\r\n * Defaults to a newline-delimited JSON (NDJSON) parser that expects each\r\n * line to be either `{ text: \"...\" }` or `{ done: true }`.\r\n *\r\n * @example\r\n * // Plain text streaming — treat every chunk as raw text:\r\n * parseChunk: (chunk) => chunk ? [{ type: 'text', text: chunk }] : []\r\n *\r\n * @example\r\n * // Custom JSON lines format:\r\n * parseChunk: (chunk) => {\r\n * try {\r\n * const json = JSON.parse(chunk);\r\n * if (json.error) return [{ type: 'error', message: json.error }];\r\n * if (json.done) return [{ type: 'done' }];\r\n * if (json.delta) return [{ type: 'text', text: json.delta }];\r\n * return [];\r\n * } catch { return []; }\r\n * }\r\n */\r\n parseChunk?: FetchChunkParser;\r\n};\r\n\r\n/**\r\n * Creates an adapter that connects to a **raw chunked HTTP streaming** endpoint —\r\n * for backends that stream newline-delimited JSON (NDJSON) or plain text,\r\n * rather than SSE.\r\n *\r\n * Use `createSseAdapter` instead if your backend streams Server-Sent Events\r\n * (the format used by OpenAI, Anthropic, and most AI APIs).\r\n *\r\n * @example\r\n * // NDJSON backend streaming { text: \"...\" } lines — works with zero config:\r\n * const adapter = createFetchStreamAdapter('/api/chat');\r\n *\r\n * @example\r\n * // Plain text streaming (each chunk is raw text, no JSON):\r\n * const adapter = createFetchStreamAdapter('/api/chat', {\r\n * parseChunk: (chunk) => chunk ? [{ type: 'text', text: chunk }] : [],\r\n * });\r\n *\r\n * @example\r\n * // Custom body + auth:\r\n * const adapter = createFetchStreamAdapter('/api/chat', {\r\n * getHeaders: async () => ({ Authorization: `Bearer ${await getToken()}` }),\r\n * getBody: ({ messages, context }) => ({\r\n * history: messages,\r\n * model: context?.model ?? 'default',\r\n * }),\r\n * });\r\n */\r\nexport function createFetchStreamAdapter(\r\n url: string,\r\n options: FetchStreamAdapterOptions = {},\r\n): AiBackendAdapter {\r\n const {\r\n method = 'POST',\r\n headers: staticHeaders = {},\r\n getHeaders,\r\n getBody,\r\n parseChunk = defaultNdjsonParser,\r\n credentials,\r\n } = options;\r\n\r\n return {\r\n async *sendMessage(input: AiAdapterInput): AsyncIterable<AiStreamEvent> {\r\n const dynamicHeaders = getHeaders ? await getHeaders(input) : {};\r\n\r\n const body = getBody\r\n ? getBody(input)\r\n : { messages: input.messages, context: input.context };\r\n\r\n const response = await fetch(url, {\r\n method,\r\n credentials,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...staticHeaders,\r\n ...dynamicHeaders,\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!response.ok) {\r\n const message = await response.text().catch(() => `HTTP ${response.status}`);\r\n yield { type: 'error', message: `Request failed (${response.status}): ${message}` };\r\n return;\r\n }\r\n\r\n if (!response.body) {\r\n yield { type: 'error', message: 'Response body is empty — server may not support streaming.' };\r\n return;\r\n }\r\n\r\n yield* readChunkedStream(response.body, parseChunk);\r\n },\r\n };\r\n}\r\n\r\n// ─── Chunked stream reader ────────────────────────────────────────────────────\r\n\r\nasync function* readChunkedStream(\r\n body: ReadableStream<Uint8Array>,\r\n parseChunk: FetchChunkParser,\r\n): AsyncIterable<AiStreamEvent> {\r\n const reader = body.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n\r\n // Split on newlines — each complete line is one NDJSON record\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() ?? ''; // keep the incomplete trailing line\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n if (!trimmed) continue;\r\n\r\n const events = parseChunk(trimmed);\r\n for (const event of events) {\r\n yield event;\r\n if (event.type === 'done' || event.type === 'error') return;\r\n }\r\n }\r\n }\r\n\r\n // Flush any remaining buffered content\r\n if (buffer.trim()) {\r\n const events = parseChunk(buffer.trim());\r\n for (const event of events) {\r\n yield event;\r\n if (event.type === 'done' || event.type === 'error') return;\r\n }\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n\r\n yield { type: 'done' };\r\n}\r\n\r\n// ─── Default parser: Juneau wire protocol (NDJSON) ───────────────────────────\r\n//\r\n// Each newline-delimited chunk is parsed as a JuneauWireEvent.\r\n// Falls back to treating the chunk as plain text if it can't be parsed.\r\n\r\nconst defaultNdjsonParser: FetchChunkParser = (chunk) => {\r\n const wire = parseJuneauWire(chunk);\r\n if (wire.length > 0) return wire;\r\n\r\n // Not a Juneau wire event — treat the raw chunk as plain text\r\n return chunk ? [{ type: 'text', text: chunk }] : [];\r\n};\r\n","import { useState, useCallback, useRef, useEffect, useMemo } from 'react';\nimport { consumeStream, serializeMessages } from '../core/stream';\nimport { trimHistory, isProposalPart } from '../core/history';\nimport type {\n AiMessage,\n AiMessagePart,\n AiBackendAdapter,\n AiStreamEvent\n} from '../core/types';\n\nlet messageIdCounter = 0;\nconst nextId = (): string => `msg-${++messageIdCounter}-${Date.now()}`;\n\n/** Internal alias used throughout this hook. */\nconst serializeHistory = serializeMessages;\n\nexport type UseAiChatOptions = {\n adapter: AiBackendAdapter;\n /** Optional context passed through to every adapter call */\n context?: Record<string, unknown>;\n /** Called when a proposal is confirmed */\n onProposalConfirm?: (proposalId: string, payload: unknown) => void;\n /** Called when a proposal is cancelled */\n onProposalCancel?: (proposalId: string) => void;\n /**\n * Restored conversation to start with — typically the output of\n * `deserializeMessages`. Read once on mount; switch chats later via\n * `reset(nextMessages)`.\n */\n initialMessages?: AiMessage[];\n /**\n * Maximum number of messages sent to the adapter per request — a\n * token-saving measure. Rendering is never trimmed; the cut keeps the most\n * recent messages and never splits a user/assistant exchange. Unlimited by\n * default.\n */\n historyLimit?: number;\n /**\n * Called whenever the conversation settles: an exchange finishes streaming,\n * a proposal is resolved, or the chat is reset. Never called per streamed\n * token. Use this to persist the conversation (see `serializeForStorage`).\n */\n onMessagesChange?: (messages: AiMessage[]) => void;\n};\n\nexport type UseAiChatReturn = {\n messages: AiMessage[];\n input: string;\n setInput: (value: string) => void;\n sendMessage: () => Promise<void>;\n /** Sends a message with the given text without touching the input field. Useful for programmatic/init triggers. */\n sendMessageWithText: (text: string) => Promise<void>;\n /**\n * Triggers the adapter with a synthetic context message and streams the response\n * as an assistant message — no user bubble is shown. Use this for proactive\n * greetings or page-load summaries where the AI speaks first.\n */\n sendGreeting: (contextHint: string) => Promise<void>;\n /** Aborts the in-flight stream. No-op if nothing is streaming. */\n stop: () => void;\n isLoading: boolean;\n /**\n * True from the moment a message is sent until the first token arrives from the stream.\n * Use this to show a \"connecting…\" state distinct from the typing indicator shown\n * while tokens are actively streaming in.\n */\n isConnecting: boolean;\n error: string | null;\n /**\n * Clears the conversation and aborts any in-flight stream. Pass\n * `nextMessages` to load a different stored chat instead of starting empty.\n */\n reset: (nextMessages?: AiMessage[]) => void;\n confirmProposal: (proposalId: string, payload: unknown) => void;\n cancelProposal: (proposalId: string) => void;\n};\n\nexport function useAiChat({\n adapter,\n context,\n onProposalConfirm,\n onProposalCancel,\n initialMessages,\n historyLimit,\n onMessagesChange\n}: UseAiChatOptions): UseAiChatReturn {\n const [messages, setMessages] = useState<AiMessage[]>(initialMessages ?? []);\n const [input, setInput] = useState('');\n const [isLoading, setIsLoading] = useState(false);\n const [isConnecting, setIsConnecting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Ref so consumeStream callback always sees latest messages without stale closure\n const abortRef = useRef<AbortController | null>(null);\n\n // onMessagesChange fires only when the conversation settles (stream done,\n // proposal resolved, reset) — never per token. The flag is raised at those\n // points and consumed here once React has committed the final message state.\n const shouldNotifyRef = useRef(false);\n const onMessagesChangeRef = useRef(onMessagesChange);\n useEffect(() => {\n onMessagesChangeRef.current = onMessagesChange;\n });\n useEffect(() => {\n if (!shouldNotifyRef.current || isLoading) return;\n shouldNotifyRef.current = false;\n onMessagesChangeRef.current?.(messages);\n }, [messages, isLoading]);\n\n const appendPartToLast = useCallback((part: AiMessagePart) => {\n setMessages(prev => {\n const last = prev[prev.length - 1];\n if (!last || last.role !== 'assistant') return prev;\n\n // Activity parts with a stable id upsert in-place instead of appending\n if (part.type === 'activity' && part.id) {\n const parts = [...last.parts];\n const existingIndex = parts.findIndex(\n p => p.type === 'activity' && p.id === part.id\n );\n if (existingIndex !== -1) {\n parts[existingIndex] = part;\n return [...prev.slice(0, -1), { ...last, parts }];\n }\n }\n\n return [\n ...prev.slice(0, -1),\n { ...last, parts: [...last.parts, part] }\n ];\n });\n }, []);\n\n const appendTextToLast = useCallback((chunk: string) => {\n setMessages(prev => {\n const last = prev[prev.length - 1];\n if (!last || last.role !== 'assistant') return prev;\n\n const parts = [...last.parts];\n const lastPart = parts[parts.length - 1];\n\n if (lastPart?.type === 'text') {\n parts[parts.length - 1] = { type: 'text', text: lastPart.text + chunk };\n } else {\n parts.push({ type: 'text', text: chunk });\n }\n\n return [...prev.slice(0, -1), { ...last, parts }];\n });\n }, []);\n\n const sendMessageCore = useCallback(async (text: string, currentMessages: AiMessage[]) => {\n setError(null);\n\n const userMessage: AiMessage = {\n id: nextId(),\n role: 'user',\n parts: [{ type: 'text', text }],\n createdAt: new Date(),\n };\n\n // Don't add the assistant placeholder upfront — add it lazily on the first\n // event so an immediate error doesn't leave a blank bubble in the UI.\n const assistantId = nextId();\n let assistantAdded = false;\n\n const ensureAssistantBubble = () => {\n if (assistantAdded) return;\n assistantAdded = true;\n const assistantMessage: AiMessage = {\n id: assistantId,\n role: 'assistant',\n parts: [],\n createdAt: new Date(),\n };\n setMessages(prev => [...prev, assistantMessage]);\n };\n\n setMessages(prev => [...prev, userMessage]);\n setIsLoading(true);\n setIsConnecting(true);\n\n abortRef.current?.abort();\n const abort = new AbortController();\n abortRef.current = abort;\n\n try {\n const history = trimHistory(\n [...currentMessages, userMessage],\n historyLimit ?? Number.POSITIVE_INFINITY\n );\n const stream = adapter.sendMessage({ messages: serializeHistory(history), context });\n\n await consumeStream(\n stream,\n (event: AiStreamEvent) => {\n // First event of any kind means we're no longer just connecting\n setIsConnecting(false);\n switch (event.type) {\n case 'text':\n ensureAssistantBubble();\n appendTextToLast(event.text);\n break;\n case 'part':\n ensureAssistantBubble();\n appendPartToLast(event.part);\n break;\n case 'error':\n ensureAssistantBubble();\n appendPartToLast({ type: 'error', message: event.message });\n setError(event.message);\n break;\n case 'done': break;\n }\n },\n abort.signal\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(message);\n ensureAssistantBubble();\n appendPartToLast({ type: 'error', message });\n } finally {\n shouldNotifyRef.current = true;\n setIsLoading(false);\n setIsConnecting(false);\n }\n }, [adapter, context, historyLimit, appendTextToLast, appendPartToLast]);\n\n const sendMessage = useCallback(async () => {\n const trimmed = input.trim();\n if (!trimmed || isLoading) return;\n setInput('');\n await sendMessageCore(trimmed, messages);\n }, [input, isLoading, messages, sendMessageCore]);\n\n const sendMessageWithText = useCallback(async (text: string) => {\n if (!text.trim() || isLoading) return;\n await sendMessageCore(text, messages);\n }, [isLoading, messages, sendMessageCore]);\n\n const sendGreeting = useCallback(async (contextHint: string) => {\n if (isLoading) return;\n setError(null);\n setIsLoading(true);\n setIsConnecting(true);\n\n // Add only an assistant placeholder — no user bubble\n const assistantMessage: AiMessage = {\n id: nextId(),\n role: 'assistant',\n parts: [],\n createdAt: new Date(),\n };\n setMessages(prev => [...prev, assistantMessage]);\n\n abortRef.current?.abort();\n const abort = new AbortController();\n abortRef.current = abort;\n\n // Pass the hint as a system message so the adapter knows what to generate\n const syntheticContext: AiMessage = {\n id: nextId(),\n role: 'system',\n parts: [{ type: 'text', text: contextHint }],\n createdAt: new Date(),\n };\n\n try {\n const stream = adapter.sendMessage({ messages: serializeHistory([syntheticContext]), context });\n await consumeStream(\n stream,\n (event: AiStreamEvent) => {\n setIsConnecting(false);\n switch (event.type) {\n case 'text': appendTextToLast(event.text); break;\n case 'part': appendPartToLast(event.part); break;\n case 'error':\n appendPartToLast({ type: 'error', message: event.message });\n setError(event.message);\n break;\n case 'done': break;\n }\n },\n abort.signal\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(message);\n appendPartToLast({ type: 'error', message });\n } finally {\n shouldNotifyRef.current = true;\n setIsLoading(false);\n setIsConnecting(false);\n }\n }, [isLoading, adapter, context, appendTextToLast, appendPartToLast]);\n\n const stop = useCallback(() => {\n abortRef.current?.abort();\n setIsLoading(false);\n setIsConnecting(false);\n }, []);\n\n const reset = useCallback((nextMessages?: AiMessage[]) => {\n abortRef.current?.abort();\n shouldNotifyRef.current = true;\n setMessages(nextMessages ?? []);\n setInput('');\n setError(null);\n setIsLoading(false);\n setIsConnecting(false);\n }, []);\n\n // Marking the proposal resolved in state disables its card, so the same\n // proposal can never fire callbacks twice or survive persistence as actionable.\n const resolveProposal = useCallback((proposalId: string, resolved: 'confirmed' | 'cancelled') => {\n shouldNotifyRef.current = true;\n setMessages(prev => prev.map(msg => ({\n ...msg,\n parts: msg.parts.map(part =>\n isProposalPart(part) && part.proposal.id === proposalId\n ? { ...part, proposal: { ...part.proposal, resolved } }\n : part\n ),\n })));\n }, []);\n\n const confirmProposal = useCallback((proposalId: string, payload: unknown) => {\n resolveProposal(proposalId, 'confirmed');\n onProposalConfirm?.(proposalId, payload);\n }, [onProposalConfirm, resolveProposal]);\n\n const cancelProposal = useCallback((proposalId: string) => {\n resolveProposal(proposalId, 'cancelled');\n onProposalCancel?.(proposalId);\n }, [onProposalCancel, resolveProposal]);\n\n // Stable reference — callbacks are useCallback-stable, so this only changes\n // when actual state changes. Lets AiChatProvider memoize its context value.\n return useMemo(() => ({\n messages,\n input,\n setInput,\n sendMessage,\n sendMessageWithText,\n sendGreeting,\n stop,\n isLoading,\n isConnecting,\n error,\n reset,\n confirmProposal,\n cancelProposal\n }), [\n messages,\n input,\n sendMessage,\n sendMessageWithText,\n sendGreeting,\n stop,\n isLoading,\n isConnecting,\n error,\n reset,\n confirmProposal,\n cancelProposal\n ]);\n}\n","import type { JuneauLabels } from '../types';\r\n\r\nexport const juneauEn: JuneauLabels = {\r\n sidebarTitle: 'AI Assistant',\r\n clearConversation: 'Clear conversation',\r\n resetConversation: 'Reset conversation',\r\n minimizeSidebar: 'Minimize',\r\n expandSidebar: 'Expand',\r\n userLabel: 'You',\r\n inputPlaceholder: 'Ask a question… (Enter to send)',\r\n sendMessage: 'Send message',\r\n stopMessage: 'Stop',\r\n typingMessage: 'Assistant is typing',\r\n connectingMessage: 'Connecting…',\r\n emptyStateText: 'How can I help you today?',\r\n emptyStateHint: 'Try: \"Show me the data\" or \"Can you suggest something?\"',\r\n proposalConfirm: 'Confirm',\r\n proposalCancel: 'Cancel',\r\n proposalConfirmed: 'Confirmed',\r\n proposalCancelled: 'Cancelled',\r\n proposalExpired: 'No longer available',\r\n errorDismiss: 'Dismiss',\r\n actionAddFile: 'Add file',\r\n actionQuickActions: 'Quick actions',\r\n actionNew: 'New',\r\n actionHistory: 'History',\r\n actionRules: 'Rules',\r\n historyEmpty: 'No previous chats',\r\n historyDeleteChat: 'Delete chat',\r\n};\r\n","import { createContext, useContext } from 'react';\r\nimport type { JuneauLabels } from './types';\r\nimport { juneauEn } from './locales/en';\r\n\r\nexport const JuneauLabelsContext = createContext<JuneauLabels>(juneauEn);\r\n\r\n/**\r\n * Returns the active label set. Falls back to English defaults for any\r\n * key not provided by the consumer's `labels` prop on `JuneauProvider`.\r\n */\r\nexport function useLabels(): JuneauLabels {\r\n return useContext(JuneauLabelsContext);\r\n}\r\n","import type { CSSProperties, ReactNode } from 'react';\nimport '../../styles/tokens.css';\nimport { JuneauLabelsContext } from '../../i18n/context';\nimport { juneauEn } from '../../i18n/locales/en';\nimport type { JuneauLabels } from '../../i18n/types';\nimport styles from './JuneauProvider.module.css';\n\nexport type { JuneauLabels };\n\nexport type JuneauTheme = {\n colorPrimary?: string;\n colorPrimaryDark?: string;\n colorPrimaryLight?: string;\n colorPrimaryBorder?: string;\n colorAccent?: string;\n colorAccentDark?: string;\n colorAccentLight?: string;\n colorAccentBorder?: string;\n colorSurface?: string;\n colorSurfaceRaised?: string;\n colorSurfaceHover?: string;\n colorBorder?: string;\n colorBorderSubtle?: string;\n colorTextPrimary?: string;\n colorTextSecondary?: string;\n colorTextMuted?: string;\n colorTextFaint?: string;\n colorTextInverse?: string;\n colorAssistantAvatar?: string;\n colorErrorBg?: string;\n colorErrorBorder?: string;\n colorErrorText?: string;\n colorSuccessBg?: string;\n colorSuccessText?: string;\n colorWarningBg?: string;\n colorWarningText?: string;\n colorDangerBg?: string;\n colorDangerText?: string;\n radiusSm?: string;\n radiusMd?: string;\n radiusLg?: string;\n radiusFull?: string;\n fontSizeXs?: string;\n fontSizeSm?: string;\n fontSizeBase?: string;\n fontSizeMd?: string;\n fontSizeLg?: string;\n fontSizeXl?: string;\n fontSize2xl?: string;\n fontSize3xl?: string;\n /** Override the font family used across all Juneau components. */\n fontFamily?: string;\n /** Duration for all transitions, e.g. '0.2s'. */\n transitionFast?: string;\n};\n\ntype Props = {\n children: ReactNode;\n theme?: JuneauTheme;\n /**\n * Override any subset of UI strings. Unspecified keys fall back to English.\n * Use the exported `juneauCs` or `juneauEn` objects, or build your own from `JuneauLabels`.\n */\n labels?: Partial<JuneauLabels>;\n /**\n * Sets the sidebar title globally for every `AiSidebar` rendered inside this\n * provider. Equivalent to overriding `labels.sidebarTitle` but more\n * discoverable — no need to spread the whole labels object just to set a name.\n *\n * A `title` prop passed directly to `AiSidebar` still takes precedence.\n *\n * @example\n * <JuneauProvider defaultTitle=\"Tappeer AI\">…</JuneauProvider>\n */\n defaultTitle?: string;\n className?: string;\n style?: CSSProperties;\n};\n\nexport function JuneauProvider({ children, theme, labels, defaultTitle, className, style }: Props) {\n const resolvedLabels: JuneauLabels = {\n ...juneauEn,\n ...(defaultTitle ? { sidebarTitle: defaultTitle } : {}),\n ...labels,\n };\n\n const themeVars = theme ? buildThemeVars(theme) : undefined;\n\n return (\n <JuneauLabelsContext.Provider value={resolvedLabels}>\n <div\n className={[styles.root, className].filter(Boolean).join(' ')}\n style={{ ...themeVars, ...style }}\n >\n {children}\n </div>\n </JuneauLabelsContext.Provider>\n );\n}\n\nfunction buildThemeVars(theme: JuneauTheme): CSSProperties {\n const map: Record<string, string | undefined> = {\n '--juneau-color-primary': theme.colorPrimary,\n '--juneau-color-primary-dark': theme.colorPrimaryDark,\n '--juneau-color-primary-light': theme.colorPrimaryLight,\n '--juneau-color-primary-border': theme.colorPrimaryBorder,\n '--juneau-color-accent': theme.colorAccent,\n '--juneau-color-accent-dark': theme.colorAccentDark,\n '--juneau-color-accent-light': theme.colorAccentLight,\n '--juneau-color-accent-border': theme.colorAccentBorder,\n '--juneau-color-surface': theme.colorSurface,\n '--juneau-color-surface-raised': theme.colorSurfaceRaised,\n '--juneau-color-surface-hover': theme.colorSurfaceHover,\n '--juneau-color-border': theme.colorBorder,\n '--juneau-color-border-subtle': theme.colorBorderSubtle,\n '--juneau-color-text-primary': theme.colorTextPrimary,\n '--juneau-color-text-secondary': theme.colorTextSecondary,\n '--juneau-color-text-muted': theme.colorTextMuted,\n '--juneau-color-text-faint': theme.colorTextFaint,\n '--juneau-color-text-inverse': theme.colorTextInverse,\n '--juneau-color-assistant-avatar': theme.colorAssistantAvatar,\n '--juneau-color-error-bg': theme.colorErrorBg,\n '--juneau-color-error-border': theme.colorErrorBorder,\n '--juneau-color-error-text': theme.colorErrorText,\n '--juneau-color-success-bg': theme.colorSuccessBg,\n '--juneau-color-success-text': theme.colorSuccessText,\n '--juneau-color-warning-bg': theme.colorWarningBg,\n '--juneau-color-warning-text': theme.colorWarningText,\n '--juneau-color-danger-bg': theme.colorDangerBg,\n '--juneau-color-danger-text': theme.colorDangerText,\n '--juneau-radius-sm': theme.radiusSm,\n '--juneau-radius-md': theme.radiusMd,\n '--juneau-radius-lg': theme.radiusLg,\n '--juneau-radius-full': theme.radiusFull,\n '--juneau-font-size-xs': theme.fontSizeXs,\n '--juneau-font-size-sm': theme.fontSizeSm,\n '--juneau-font-size-base': theme.fontSizeBase,\n '--juneau-font-size-md': theme.fontSizeMd,\n '--juneau-font-size-lg': theme.fontSizeLg,\n '--juneau-font-size-xl': theme.fontSizeXl,\n '--juneau-font-size-2xl': theme.fontSize2xl,\n '--juneau-font-size-3xl': theme.fontSize3xl,\n '--juneau-font-family': theme.fontFamily,\n '--juneau-transition-fast': theme.transitionFast,\n };\n\n return Object.fromEntries(\n Object.entries(map).filter(([, v]) => v !== undefined)\n ) as CSSProperties;\n}\n","import { createContext, useContext } from 'react';\nimport type { UseAiChatReturn } from '../hooks/useAiChat';\n\nexport type AiChatContextValue = UseAiChatReturn & {\n /**\n * Update the context forwarded to every adapter.sendMessage call.\n * Call this on each page/view to tell the AI where the user is,\n * what tools are available, etc.\n *\n * Passing an object REPLACES the whole context. To merge with what's\n * already there (e.g. keep a sessionId while updating the page), use the\n * updater form:\n *\n * @example\n * setContext(prev => ({ ...prev, pageId: 'invoices' }));\n */\n setContext: (\n ctx:\n | Record<string, unknown>\n | ((prev: Record<string, unknown> | undefined) => Record<string, unknown>)\n ) => void;\n};\n\nexport const AiChatContext = createContext<AiChatContextValue | null>(null);\n\n/**\n * Returns the shared chat state from the nearest AiChatProvider.\n * Throws if called outside of one — fail fast is better than silent undefined.\n */\nexport function useAiChatContext(): AiChatContextValue {\n const ctx = useContext(AiChatContext);\n if (!ctx) {\n throw new Error(\n 'useAiChatContext must be used inside <AiChatProvider>. ' +\n 'Wrap your app (or layout) with <AiChatProvider adapter={...}>.'\n );\n }\n return ctx;\n}\n\n/**\n * Like {@link useAiChatContext}, but returns null outside a provider instead\n * of throwing. Use in components that render both inside and outside the chat.\n */\nexport function useAiChatContextSafe(): AiChatContextValue | null {\n return useContext(AiChatContext);\n}\n","import { useState, useCallback, useMemo, type ReactNode } from 'react';\nimport { useAiChat } from '../hooks/useAiChat';\nimport type { AiMessage, AiBackendAdapter } from '../core/types';\nimport { AiChatContext } from './AiChatContext';\n\ntype Props = {\n adapter: AiBackendAdapter;\n /** Initial context passed to the adapter. Update it per-page via setContext(). */\n context?: Record<string, unknown>;\n onProposalConfirm?: (proposalId: string, payload: unknown) => void;\n onProposalCancel?: (proposalId: string) => void;\n /** Restored conversation to start with — typically the output of `deserializeMessages`. */\n initialMessages?: AiMessage[];\n /** Max messages sent to the adapter per request. Rendering is never trimmed. */\n historyLimit?: number;\n /** Called when the conversation settles. Use to persist via `serializeForStorage`. */\n onMessagesChange?: (messages: AiMessage[]) => void;\n children: ReactNode;\n};\n\nexport function AiChatProvider({\n adapter,\n context: initialContext,\n onProposalConfirm,\n onProposalCancel,\n initialMessages,\n historyLimit,\n onMessagesChange,\n children,\n}: Props) {\n const [context, setContextState] = useState<Record<string, unknown> | undefined>(initialContext);\n\n // Object form replaces the whole context; updater form enables merging\n // without stale closures: setContext(prev => ({ ...prev, pageId: 'x' })).\n const setContext = useCallback((\n ctx:\n | Record<string, unknown>\n | ((prev: Record<string, unknown> | undefined) => Record<string, unknown>)\n ) => {\n if (typeof ctx === 'function') {\n setContextState(prev => ctx(prev));\n } else {\n setContextState(ctx);\n }\n }, []);\n\n const chat = useAiChat({\n adapter,\n context,\n onProposalConfirm,\n onProposalCancel,\n initialMessages,\n historyLimit,\n onMessagesChange,\n });\n\n // Memoized so consumers only re-render when chat state actually changes\n const value = useMemo(\n () => ({ ...chat, setContext }),\n [chat, setContext]\n );\n\n return (\n <AiChatContext.Provider value={value}>\n {children}\n </AiChatContext.Provider>\n );\n}\n","import type { JuneauLabels } from '../types';\r\n\r\nexport const juneauCs: JuneauLabels = {\r\n sidebarTitle: 'AI Asistent',\r\n clearConversation: 'Vymazat konverzaci',\r\n resetConversation: 'Resetovat konverzaci',\r\n minimizeSidebar: 'Minimalizovat',\r\n expandSidebar: 'Rozbalit',\r\n userLabel: 'Vy',\r\n inputPlaceholder: 'Zeptejte se na cokoliv… (Enter pro odeslání)',\r\n sendMessage: 'Odeslat zprávu',\r\n stopMessage: 'Zastavit',\r\n typingMessage: 'Asistent píše',\r\n connectingMessage: 'Připojování…',\r\n emptyStateText: 'Jak vám mohu dnes pomoci?',\r\n emptyStateHint: 'Zkuste: „Ukáž mi data\" nebo „Máš nějaký návrh?\"',\r\n proposalConfirm: 'Potvrdit',\r\n proposalCancel: 'Zrušit',\r\n proposalConfirmed: 'Potvrzeno',\r\n proposalCancelled: 'Zrušeno',\r\n proposalExpired: 'Již není k dispozici',\r\n errorDismiss: 'Zavřít',\r\n actionAddFile: 'Přidat soubor',\r\n actionQuickActions: 'Rychlé akce',\r\n actionNew: 'Nový',\r\n actionHistory: 'Historie',\r\n actionRules: 'Pravidla',\r\n historyEmpty: 'Žádné předchozí konverzace',\r\n historyDeleteChat: 'Smazat konverzaci',\r\n};\r\n","import type { CSSProperties } from 'react';\r\n\r\ntype IconProps = {\r\n className?: string;\r\n style?: CSSProperties;\r\n 'aria-hidden'?: boolean | 'true' | 'false';\r\n};\r\n\r\nexport function IconWandMagicSparkles({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 640 512\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n fill=\"currentColor\"\r\n className={className}\r\n style={style}\r\n aria-hidden={ariaHidden}\r\n >\r\n {/* Font Awesome \"crow\" solid (FA 6 free) — viewBox 0 0 640 512 */}\r\n <path d=\"M456 0c-48.6 0-88 39.4-88 88l0 29.2L12.5 390.6c-14 10.8-16.6 30.9-5.9 44.9s30.9 16.6 44.9 5.9L126.1 384l133.1 0 46.6 113.1c5 12.3 19.1 18.1 31.3 13.1s18.1-19.1 13.1-31.3L311.1 384l40.9 0c1.1 0 2.1 0 3.2 0l46.6 113.2c5 12.3 19.1 18.1 31.3 13.1s18.1-19.1 13.1-31.3l-42-102C484.9 354.1 544 280 544 192l0-64 0-8 80.5-20.1c8.6-2.1 13.8-10.8 11.6-19.4C629 52 603.4 32 574 32l-50.1 0C507.7 12.5 483.3 0 456 0zm0 64a24 24 0 1 1 0 48 24 24 0 1 1 0-48z\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function IconPaperPlane({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 512 512\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n fill=\"currentColor\"\r\n className={className}\r\n style={style}\r\n aria-hidden={ariaHidden}\r\n >\r\n {/* FA \"paper-plane\" solid */}\r\n <path d=\"M498.1 5.6c10.1 7 15.4 19.1 13.5 31.2l-64 416c-1.5 9.7-7.4 18.2-16 23s-18.9 5.4-28 1.6L284 427.7l-68.5 74.1c-8.9 9.7-22.9 12.9-35.2 8.1S160 493.2 160 480V396.4c0-4 1.5-7.8 4.2-10.8L331.8 202.8c5.8-6.3 5.6-16-.4-22s-15.7-6.4-22-.7L106 360.8 17.7 316.6C7.1 311.3 .3 300.7 0 288.9s6.2-22.8 16.4-28.7l448-256c10.7-6.1 23.9-5.5 34 1.4z\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function IconPaperclip({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 448 512\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n fill=\"currentColor\"\r\n className={className}\r\n style={style}\r\n aria-hidden={ariaHidden}\r\n >\r\n {/* FA \"paperclip\" solid */}\r\n <path d=\"M364.2 83.8c-24.4-24.4-64-24.4-88.4 0l-184 184c-42.1 42.1-42.1 110.3 0 152.4s110.3 42.1 152.4 0l152-152c10.9-10.9 28.7-10.9 39.6 0s10.9 28.7 0 39.6l-152 152c-64 64-167.6 64-231.6 0s-64-167.6 0-231.6l184-184c46.3-46.3 121.3-46.3 167.6 0s46.3 121.3 0 167.6l-176 176c-28.6 28.6-75 28.6-103.6 0s-28.6-75 0-103.6l144-144c10.9-10.9 28.7-10.9 39.6 0s10.9 28.7 0 39.6l-144 144c-6.7 6.7-6.7 17.7 0 24.4s17.7 6.7 24.4 0l176-176c24.4-24.4 24.4-64 0-88.4z\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function IconBolt({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 448 512\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n fill=\"currentColor\"\r\n className={className}\r\n style={style}\r\n aria-hidden={ariaHidden}\r\n >\r\n {/* FA \"bolt\" solid */}\r\n <path d=\"M349.4 44.6c5.9-13.7 1.5-29.7-10.6-38.5s-28.6-8-39.9 1.8l-256 224c-10 8.8-13.6 22.9-8.9 35.3S50.7 288 64 288l111.5 0L98.6 467.4c-5.9 13.7-1.5 29.7 10.6 38.5s28.6 8 39.9-1.8l256-224c10-8.8 13.6-22.9 8.9-35.3s-16.6-20.7-30-20.7l-111.5 0L349.4 44.6z\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function IconPlus({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 448 512\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n fill=\"currentColor\"\r\n className={className}\r\n style={style}\r\n aria-hidden={ariaHidden}\r\n >\r\n {/* FA \"plus\" solid */}\r\n <path d=\"M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 144L48 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l144 0 0 144c0 17.7 14.3 32 32 32s32-14.3 32-32l0-144 144 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-144 0 0-144z\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function IconClockRotateLeft({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 512 512\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n fill=\"currentColor\"\r\n className={className}\r\n style={style}\r\n aria-hidden={ariaHidden}\r\n >\r\n {/* FA \"clock-rotate-left\" / \"history\" solid */}\r\n <path d=\"M75 75L41 41C25.9 25.9 0 36.6 0 57.9L0 168c0 13.3 10.7 24 24 24l110.1 0c21.4 0 32.1-25.9 17-41l-31.8-31.8C143.9 83.5 196.2 64 252.6 64C370.8 64 464 157.8 464 276c0 77.5-40.8 145.4-102 182.9c-15.1 9.2-19.9 29-10.7 44.1s29 19.9 44.1 10.7C471 467.5 528 378.4 528 276C528 124.1 404.5 0 252.6 0C186 0 125.3 26.4 80 70.2L75 75zM256 152c-13.3 0-24 10.7-24 24l0 104c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65 0-94.1c0-13.3-10.7-24-24-24z\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function IconScroll({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 576 512\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n fill=\"currentColor\"\r\n className={className}\r\n style={style}\r\n aria-hidden={ariaHidden}\r\n >\r\n {/* FA \"scroll\" solid */}\r\n <path d=\"M0 80C0 53.5 21.5 32 48 32l96 0c26.5 0 48 21.5 48 48l0 16 192 0 0-16c0-26.5 21.5-48 48-48l96 0c26.5 0 48 21.5 48 48l0 96c0 26.5-21.5 48-48 48l-26.6 0c-25.8 50.9-72.7 88.5-129.4 99.8L384 416l32 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-256 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l32 0 0-72.2C135.3 332.5 88.4 294.9 62.6 244L48 244c-26.5 0-48-21.5-48-48L0 80zM128 240c0 70.7 57.3 128 128 128s128-57.3 128-128l0-128L128 112l0 128zM512 176l0-64-64 0 0 64-48 0 0 16c0 8.8-.7 17.4-2 25.8c3.3 .1 6.6 .2 9.9 .2l56 0c26.5 0 48-21.5 48-48l0-64zM48 176c0 26.5 21.5 48 48 48l56 0c3.4 0 6.7-.1 9.9-.2c-1.3-8.4-2-17-2-25.8l0-16-48 0 0-64-64 0 0 58z\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function IconWindowMinimize({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 512 512\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n fill=\"currentColor\"\r\n className={className}\r\n style={style}\r\n aria-hidden={ariaHidden}\r\n >\r\n {/* Font Awesome \"window-minimize\" solid (FA 6 free) */}\r\n <path d=\"M32 416c-17.7 0-32 14.3-32 32s14.3 32 32 32l448 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 416z\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function IconWindowRestore({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 512 512\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n fill=\"currentColor\"\r\n className={className}\r\n style={style}\r\n aria-hidden={ariaHidden}\r\n >\r\n {/* Font Awesome \"window-restore\" solid (FA 6 free) */}\r\n <path d=\"M432 64L208 64c-8.8 0-16 7.2-16 16l0 16-64 0 0-16c0-44.2 35.8-80 80-80L432 0c44.2 0 80 35.8 80 80l0 224c0 44.2-35.8 80-80 80l-16 0 0-64 16 0c8.8 0 16-7.2 16-16l0-224c0-8.8-7.2-16-16-16zM0 192c0-35.3 28.7-64 64-64l256 0c35.3 0 64 28.7 64 64l0 256c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64L0 192zm64 32c0 17.7 14.3 32 32 32l192 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L96 192c-17.7 0-32 14.3-32 32z\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function IconArrowRotateLeft({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 512 512\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n fill=\"currentColor\"\r\n className={className}\r\n style={style}\r\n aria-hidden={ariaHidden}\r\n >\r\n {/* FA \"arrow-rotate-left\" solid */}\r\n <path d=\"M125.7 160H176c17.7 0 32 14.3 32 32s-14.3 32-32 32H48c-17.7 0-32-14.3-32-32V64c0-17.7 14.3-32 32-32s32 14.3 32 32v51.2L97.6 97.6c87.5-87.5 229.3-87.5 316.8 0s87.5 229.3 0 316.8s-229.3 87.5-316.8 0c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0c62.5 62.5 163.8 62.5 226.3 0s62.5-163.8 0-226.3s-163.8-62.5-226.3 0L125.7 160z\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function IconWarning({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\r\n return (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 20 20\"\r\n width=\"1em\"\r\n height=\"1em\"\r\n fill=\"currentColor\"\r\n className={className}\r\n style={style}\r\n aria-hidden={ariaHidden}\r\n >\r\n <path fillRule=\"evenodd\" d=\"M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z\" clipRule=\"evenodd\" />\r\n </svg>\r\n );\r\n}\r\n","import type { AiTablePart as AiTablePartType } from '../../core/types';\nimport styles from './AiTablePart.module.css';\n\ntype Props = {\n part: AiTablePartType;\n};\n\nexport function AiTablePart({ part }: Props) {\n return (\n <div className={styles.wrapper} data-juneau=\"table-part\">\n <table className={styles.table}>\n <thead>\n <tr>\n {part.columns.map(col => (\n <th key={col} className={styles.th}>{col}</th>\n ))}\n </tr>\n </thead>\n <tbody>\n {part.rows.map((row, i) => (\n <tr key={i} className={styles.tr}>\n {part.columns.map(col => (\n <td key={col} className={styles.td}>\n {String(row[col] ?? '')}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n","import type { AiProposalPart } from '../../core/types';\nimport { useLabels } from '../../i18n/context';\nimport styles from './AiProposalCard.module.css';\n\ntype Props = {\n part: AiProposalPart;\n onConfirm: (proposalId: string, payload: unknown) => void;\n onCancel: (proposalId: string) => void;\n};\n\nexport function AiProposalCard({ part, onConfirm, onCancel }: Props) {\n const labels = useLabels();\n const { proposal } = part;\n\n const resolvedLabel =\n proposal.resolved === 'confirmed' ? labels.proposalConfirmed\n : proposal.resolved === 'cancelled' ? labels.proposalCancelled\n : proposal.resolved === 'expired' ? labels.proposalExpired\n : null;\n\n return (\n <div\n className={proposal.resolved ? `${styles.card} ${styles.cardResolved}` : styles.card}\n data-juneau=\"proposal-card\"\n >\n <div className={styles.header}>\n <svg className={styles.icon} viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M10 1a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 1zM5.05 3.05a.75.75 0 011.06 1.06l-1.06 1.06a.75.75 0 11-1.06-1.06l1.06-1.06zm9.9 0a.75.75 0 010 1.06l-1.06 1.06a.75.75 0 11-1.06-1.06l1.06-1.06a.75.75 0 011.06 0zM10 6a4 4 0 100 8 4 4 0 000-8zm-9 4a.75.75 0 01.75-.75h1.5a.75.75 0 010 1.5h-1.5A.75.75 0 011 10zm15.75-.75a.75.75 0 000 1.5h1.5a.75.75 0 000-1.5h-1.5zM4.11 14.89a.75.75 0 010 1.06l-1.06 1.06a.75.75 0 11-1.06-1.06l1.06-1.06a.75.75 0 011.06 0zm11.84 1.06a.75.75 0 10-1.06-1.06l-1.06 1.06a.75.75 0 101.06 1.06l1.06-1.06zM10 17.25a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5a.75.75 0 01.75-.75z\" />\n </svg>\n <span className={styles.title}>{proposal.title}</span>\n </div>\n {proposal.description && (\n <p className={styles.description}>{proposal.description}</p>\n )}\n {resolvedLabel ? (\n <span className={styles.resolvedBadge}>{resolvedLabel}</span>\n ) : (\n <div className={styles.actions}>\n <button\n className={styles.confirm}\n onClick={() => onConfirm(proposal.id, proposal.payload)}\n >\n {proposal.confirmLabel ?? labels.proposalConfirm}\n </button>\n <button\n className={styles.cancel}\n onClick={() => onCancel(proposal.id)}\n >\n {proposal.cancelLabel ?? labels.proposalCancel}\n </button>\n </div>\n )}\n </div>\n );\n}\n","import type { AiActivityPart as AiActivityPartType } from '../../core/types';\nimport styles from './AiActivityPart.module.css';\n\ntype Props = {\n part: AiActivityPartType;\n};\n\nexport function AiActivityPart({ part }: Props) {\n return (\n <div className={styles.activity} data-status={part.status} data-juneau=\"activity-part\">\n <span className={styles.indicator} aria-hidden=\"true\" />\n\n <div className={styles.content}>\n <div className={styles.title}>{part.title}</div>\n\n {part.description && (\n <div className={styles.description}>{part.description}</div>\n )}\n </div>\n </div>\n );\n}\n","import type { AiEntity, AiEntityBadgeTone, AiEntityPart } from '../../core/types';\nimport styles from './AiEntityCard.module.css';\n\ntype Props = {\n part: AiEntityPart;\n /** Optional click handler — the card becomes interactive when provided */\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\n};\n\nconst badgeClass: Record<AiEntityBadgeTone, string> = {\n success: styles.badgeSuccess,\n warning: styles.badgeWarning,\n danger: styles.badgeDanger,\n neutral: styles.badgeNeutral,\n};\n\nexport function AiEntityCard({ part, onEntityClick }: Props) {\n const { entity, entityType } = part;\n const clickable = onEntityClick !== undefined;\n\n const body = (\n <>\n <div className={styles.header}>\n <span className={styles.title}>{entity.title}</span>\n {entity.subtitle && <span className={styles.subtitle}>{entity.subtitle}</span>}\n </div>\n {entity.fields && entity.fields.length > 0 && (\n <dl className={styles.fields}>\n {entity.fields.map((field, i) => (\n <div key={i} className={styles.fieldRow}>\n <dt className={styles.fieldLabel}>{field.label}</dt>\n <dd className={styles.fieldValue}>\n {field.badge ? (\n <span className={`${styles.badge} ${badgeClass[field.badge]}`}>{field.value}</span>\n ) : (\n field.value\n )}\n </dd>\n </div>\n ))}\n </dl>\n )}\n </>\n );\n\n if (clickable) {\n return (\n <button\n type='button'\n className={`${styles.card} ${styles.cardClickable}`}\n onClick={() => onEntityClick(entity, entityType)}\n data-juneau=\"entity-card\"\n >\n {body}\n </button>\n );\n }\n\n return <div className={styles.card} data-juneau=\"entity-card\">{body}</div>;\n}\n","import type { AiEntity, AiEntityListPart as AiEntityListPartType } from '../../core/types';\nimport { AiEntityCard } from './AiEntityCard';\nimport styles from './AiEntityListPart.module.css';\n\ntype Props = {\n part: AiEntityListPartType;\n /** Optional click handler — cards become interactive when provided */\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\n};\n\nexport function AiEntityListPart({ part, onEntityClick }: Props) {\n return (\n <div className={styles.list} data-juneau=\"entity-list-part\">\n {part.title && <span className={styles.listTitle}>{part.title}</span>}\n {part.entities.map((entity, i) => (\n <AiEntityCard\n key={entity.id ?? i}\n part={{ type: 'entity', entity, entityType: part.entityType }}\n onEntityClick={onEntityClick}\n />\n ))}\n </div>\n );\n}\n","import type { ReactNode } from 'react';\nimport Markdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport type {\n AiEntity,\n AiMessagePart,\n AiTextPart,\n AiTablePart as AiTablePartType,\n AiProposalPart,\n AiActivityPart as AiActivityPartType,\n AiEntityPart as AiEntityPartType,\n AiEntityListPart as AiEntityListPartType,\n AiErrorPart,\n} from '../../core/types';\nimport { IconWarning } from '../icons';\nimport { AiTablePart } from './AiTablePart';\nimport { AiProposalCard } from './AiProposalCard';\nimport { AiActivityPart } from './AiActivityPart';\nimport { AiEntityCard } from './AiEntityCard';\nimport { AiEntityListPart } from './AiEntityListPart';\nimport styles from './AiMessagePartRenderer.module.css';\n\n/**\n * Consumer escape hatch for rendering custom part types (or overriding\n * built-in ones). Receives the raw part object with no narrowing or\n * validation applied — the consumer owns all type assertions.\n * Return null/undefined to fall through to the built-in renderers.\n */\nexport type RenderPartFn = (part: AiMessagePart) => ReactNode | null | undefined;\n\ntype Props = {\n part: AiMessagePart;\n onProposalConfirm: (proposalId: string, payload: unknown) => void;\n onProposalCancel: (proposalId: string) => void;\n /** Makes entity cards clickable — receives the entity and its optional entityType. */\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\n /** Called before the built-in switch — a non-nullish return value wins. */\n renderPart?: RenderPartFn;\n};\n\nexport function AiMessagePartRenderer({ part, onProposalConfirm, onProposalCancel, onEntityClick, renderPart }: Props) {\n // Consumer renderer takes priority — lets it override built-ins too\n if (renderPart) {\n const custom = renderPart(part);\n if (custom !== null && custom !== undefined) {\n return <>{custom}</>;\n }\n }\n\n // AiCustomPart's `type: string` absorbs literal narrowing, so the built-in\n // cases cast explicitly. The shapes are guaranteed by the wire protocol.\n switch (part.type) {\n case 'text':\n return (\n <div className={styles.markdown}>\n {/* react-markdown never uses dangerouslySetInnerHTML — safe against XSS by default */}\n <Markdown remarkPlugins={[remarkGfm]}>{(part as AiTextPart).text}</Markdown>\n </div>\n );\n case 'table':\n return <AiTablePart part={part as AiTablePartType} />;\n case 'activity':\n return <AiActivityPart part={part as AiActivityPartType} />;\n case 'proposal':\n return (\n <AiProposalCard\n part={part as AiProposalPart}\n onConfirm={onProposalConfirm}\n onCancel={onProposalCancel}\n />\n );\n case 'entity':\n return <AiEntityCard part={part as AiEntityPartType} onEntityClick={onEntityClick} />;\n case 'entity-list':\n return <AiEntityListPart part={part as AiEntityListPartType} onEntityClick={onEntityClick} />;\n case 'error':\n return (\n <span className={styles.errorText}>\n <IconWarning className={styles.errorIcon} />\n {(part as AiErrorPart).message}\n </span>\n );\n default:\n // Unknown custom part with no renderPart handler. Invisible in\n // production; a visible outline in dev so it's never a silent mystery.\n // Structural globalThis access: `process` may not exist in browsers and\n // the lib compiles without @types/node.\n const nodeEnv = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env?.NODE_ENV;\n if (nodeEnv !== 'production') {\n return (\n <div className={styles.unknownPart}>\n Unhandled part type: <code>{part.type}</code> — pass a{' '}\n <code>renderPart</code> prop to render it.\n </div>\n );\n }\n return null;\n }\n}\n","import type { ReactNode } from 'react';\r\nimport { IconWandMagicSparkles } from '../icons';\r\nimport type { AiEntity, AiMessage, AiMessagePart } from '../../core/types';\r\nimport { useLabels } from '../../i18n/context';\r\nimport { AiMessagePartRenderer } from '../parts/AiMessagePartRenderer';\r\nimport type { RenderPartFn } from '../parts/AiMessagePartRenderer';\r\nimport styles from './AiMessageBubble.module.css';\r\n\r\ntype Props = {\r\n message: AiMessage;\r\n onProposalConfirm: (proposalId: string, payload: unknown) => void;\r\n onProposalCancel: (proposalId: string) => void;\r\n /** Override the assistant avatar icon. Pass any ReactNode — an SVG, img, or component. Defaults to a brain icon. */\r\n assistantIcon?: ReactNode;\r\n /** Makes entity cards clickable — forwarded to every AiMessagePartRenderer. */\r\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\r\n /** Custom part renderer — forwarded to every AiMessagePartRenderer. */\r\n renderPart?: RenderPartFn;\r\n};\r\n\r\n/** Part types that read as prose and stay inside the padded chat bubble. */\r\nconst INLINE_PART_TYPES = new Set(['text', 'error', 'activity']);\r\n\r\n/** Cards (tables, entities, proposals, custom parts) render full-width outside the bubble. */\r\nfunction isCardPart(part: AiMessagePart): boolean {\r\n return !INLINE_PART_TYPES.has(part.type);\r\n}\r\n\r\ntype Segment = { card: boolean; parts: { part: AiMessagePart; index: number }[] };\r\n\r\n/** Groups consecutive parts so prose runs share one bubble and each card stands alone. */\r\nfunction toSegments(parts: AiMessagePart[]): Segment[] {\r\n const segments: Segment[] = [];\r\n parts.forEach((part, index) => {\r\n const card = isCardPart(part);\r\n const last = segments[segments.length - 1];\r\n // Each card is its own segment so it gets full width and its own spacing.\r\n if (last && !card && !last.card) {\r\n last.parts.push({ part, index });\r\n return;\r\n }\r\n segments.push({ card, parts: [{ part, index }] });\r\n });\r\n return segments;\r\n}\r\n\r\nexport function AiMessageBubble({ message, onProposalConfirm, onProposalCancel, onEntityClick, assistantIcon, renderPart }: Props) {\r\n const labels = useLabels();\r\n const isUser = message.role === 'user';\r\n\r\n const renderOne = (part: AiMessagePart, index: number) => (\r\n <AiMessagePartRenderer\r\n key={index}\r\n part={part}\r\n onProposalConfirm={onProposalConfirm}\r\n onProposalCancel={onProposalCancel}\r\n onEntityClick={onEntityClick}\r\n renderPart={renderPart}\r\n />\r\n );\r\n\r\n // Plain conversational messages keep the classic single-bubble layout untouched —\r\n // only messages carrying a card opt into the full-width column below.\r\n const hasCard = message.parts.some(isCardPart);\r\n\r\n return (\r\n <div\r\n className={`${styles.wrapper} ${isUser ? styles.user : styles.assistant}`}\r\n data-juneau=\"message\"\r\n data-juneau-role={message.role}\r\n >\r\n {!isUser && (\r\n <div className={styles.avatar} aria-hidden=\"true\" data-juneau=\"assistant-avatar\">\r\n {assistantIcon ?? <IconWandMagicSparkles />}\r\n </div>\r\n )}\r\n {hasCard ? (\r\n <div className={styles.content}>\r\n {toSegments(message.parts).map((segment, i) => (\r\n <div\r\n key={i}\r\n className={segment.card ? styles.card : styles.bubble}\r\n data-juneau-segment={segment.card ? 'card' : 'bubble'}\r\n >\r\n {segment.parts.map(({ part, index }) => renderOne(part, index))}\r\n </div>\r\n ))}\r\n </div>\r\n ) : (\r\n <div className={styles.bubble} data-juneau-segment=\"bubble\">\r\n {message.parts.map((part, i) => renderOne(part, i))}\r\n {message.parts.length === 0 && <span className={styles.empty} />}\r\n </div>\r\n )}\r\n {isUser && <div className={styles.avatar}>{labels.userLabel}</div>}\r\n </div>\r\n );\r\n}\r\n","import { useLabels } from '../../i18n/context';\nimport styles from './AiTypingIndicator.module.css';\n\ntype Props = {\n /** When true, shows a \"Connecting…\" label instead of just the dots. */\n connecting?: boolean;\n};\n\nexport function AiTypingIndicator({ connecting = false }: Props) {\n const labels = useLabels();\n\n return (\n <div\n className={styles.wrapper}\n aria-label={connecting ? labels.connectingMessage : labels.typingMessage}\n data-juneau=\"typing-indicator\"\n >\n <span className={styles.dot} />\n <span className={styles.dot} />\n <span className={styles.dot} />\n {connecting && (\n <span className={styles.connectingLabel}>{labels.connectingMessage}</span>\n )}\n </div>\n );\n}\n","import { useEffect, useRef } from 'react';\nimport type { ReactNode } from 'react';\nimport type { AiEntity, AiMessage } from '../../core/types';\nimport { useLabels } from '../../i18n/context';\nimport { AiMessageBubble } from '../AiMessageBubble/AiMessageBubble';\nimport { AiTypingIndicator } from '../AiTypingIndicator/AiTypingIndicator';\nimport type { RenderPartFn } from '../parts/AiMessagePartRenderer';\nimport styles from './AiMessageList.module.css';\n\ntype Props = {\n messages: AiMessage[];\n isLoading: boolean;\n /** True while waiting for the first token — shows a \"connecting\" label inside the typing indicator. */\n isConnecting: boolean;\n onProposalConfirm: (proposalId: string, payload: unknown) => void;\n onProposalCancel: (proposalId: string) => void;\n /** Override the assistant avatar icon. Forwarded to every AiMessageBubble. */\n assistantIcon?: ReactNode;\n /** Makes entity cards clickable — forwarded to every AiMessageBubble. */\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\n /** Custom part renderer — forwarded to every AiMessageBubble. */\n renderPart?: RenderPartFn;\n /**\n * Rendered instead of the default empty-state text when there are no messages.\n * Use it for a rich \"get started\" hero — headline, suggestion chips, anything.\n */\n emptyState?: ReactNode;\n};\n\nexport function AiMessageList({ messages, isLoading, isConnecting, onProposalConfirm, onProposalCancel, onEntityClick, assistantIcon, renderPart, emptyState }: Props) {\n const labels = useLabels();\n const bottomRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, [messages, isLoading]);\n\n return (\n <div className={styles.list} data-juneau=\"message-list\">\n {messages.length === 0 &&\n (emptyState ?? (\n <div className={styles.empty} data-juneau=\"empty-state\">\n <p>{labels.emptyStateText}</p>\n <p className={styles.hint}>\n <em>{labels.emptyStateHint}</em>\n </p>\n </div>\n ))}\n {messages.map(message => (\n <AiMessageBubble\n key={message.id}\n message={message}\n onProposalConfirm={onProposalConfirm}\n onProposalCancel={onProposalCancel}\n onEntityClick={onEntityClick}\n assistantIcon={assistantIcon}\n renderPart={renderPart}\n />\n ))}\n {isLoading && (\n <div className={styles.typing}>\n <AiTypingIndicator connecting={isConnecting} />\n </div>\n )}\n <div ref={bottomRef} />\n </div>\n );\n}\n","import type { KeyboardEvent, ReactNode } from 'react';\nimport { useEffect, useRef } from 'react';\nimport {\n IconPaperPlane,\n IconPaperclip,\n IconBolt,\n IconPlus,\n IconClockRotateLeft,\n IconScroll,\n} from '../icons';\nimport { useLabels } from '../../i18n/context';\nimport styles from './AiInput.module.css';\n\nexport type AiInputAction = {\n /** Icon rendered inside the button. */\n icon: ReactNode;\n /** Visible label and aria-label for the button. */\n label: string;\n onClick?: () => void;\n};\n\ntype Props = {\n value: string;\n onChange: (value: string) => void;\n onSend: () => void;\n /** When provided, the send button becomes a stop button while isLoading is true. */\n onStop?: () => void;\n isLoading: boolean;\n /** Overrides the `inputPlaceholder` label for this specific instance. */\n placeholder?: string;\n /**\n * Toolbar action buttons rendered left of the send button.\n * Pass an empty array to hide the toolbar entirely.\n * Defaults to five built-in actions (attach, quick actions, new, history, rules).\n */\n actions?: AiInputAction[];\n /** Override the send button icon. Defaults to a paper-plane icon. */\n sendIcon?: ReactNode;\n};\n\nexport function AiInput({ value, onChange, onSend, onStop, isLoading, placeholder, actions, sendIcon }: Props) {\n const labels = useLabels();\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const wasLoadingRef = useRef(false);\n\n // Restore focus when streaming finishes. The textarea stays enabled during\n // streaming so the user can keep typing, but if focus was lost anyway\n // (e.g. the user clicked the stop button), give it back.\n useEffect(() => {\n if (wasLoadingRef.current && !isLoading) {\n textareaRef.current?.focus();\n }\n wasLoadingRef.current = isLoading;\n }, [isLoading]);\n\n const defaultActions: AiInputAction[] = [\n { icon: <IconPaperclip />, label: labels.actionAddFile },\n { icon: <IconBolt />, label: labels.actionQuickActions },\n { icon: <IconPlus />, label: labels.actionNew },\n { icon: <IconClockRotateLeft />, label: labels.actionHistory },\n { icon: <IconScroll />, label: labels.actionRules },\n ];\n\n const resolvedActions = actions ?? defaultActions;\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n // Typing stays enabled during streaming, but Enter must not send —\n // useAiChat also guards this, this is just belt and braces.\n if (!isLoading) onSend();\n }\n };\n\n return (\n <div className={styles.wrapper} data-juneau=\"input\">\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n data-juneau=\"input-textarea\"\n value={value}\n onChange={e => onChange(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder ?? labels.inputPlaceholder}\n rows={3}\n aria-label={labels.sendMessage}\n />\n\n <div className={styles.toolbar}>\n {resolvedActions.length > 0 && (\n <div className={styles.actions}>\n {resolvedActions.map((action, i) => (\n <button\n key={i}\n className={styles.actionBtn}\n type=\"button\"\n disabled={isLoading}\n aria-label={action.label}\n onClick={action.onClick}\n >\n {action.icon}\n <span>{action.label}</span>\n </button>\n ))}\n </div>\n )}\n\n {isLoading && onStop ? (\n <button\n className={styles.stopBtn}\n onClick={onStop}\n aria-label={labels.stopMessage}\n type=\"button\"\n >\n <svg className={styles.stopIcon} viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <rect x=\"6\" y=\"6\" width=\"12\" height=\"12\" rx=\"2\" />\n </svg>\n <span>{labels.stopMessage}</span>\n </button>\n ) : (\n <button\n className={styles.sendBtn}\n onClick={onSend}\n disabled={isLoading || !value.trim()}\n aria-label={labels.sendMessage}\n type=\"button\"\n >\n {isLoading ? (\n <svg className={styles.spinnerIcon} viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeDasharray=\"32\" strokeDashoffset=\"12\" />\n </svg>\n ) : (\n sendIcon ?? <IconPaperPlane />\n )}\n <span>{labels.sendMessage}</span>\n </button>\n )}\n </div>\n </div>\n );\n}\n","import { useLabels } from '../../i18n/context';\nimport styles from './AiError.module.css';\n\ntype Props = {\n message: string;\n onDismiss?: () => void;\n};\n\nexport function AiError({ message, onDismiss }: Props) {\n const labels = useLabels();\n\n return (\n <div className={styles.wrapper} role=\"alert\" data-juneau=\"error\">\n <svg className={styles.icon} viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fillRule=\"evenodd\" d=\"M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z\" clipRule=\"evenodd\" />\n </svg>\n <span className={styles.message}>{message}</span>\n {onDismiss && (\n <button className={styles.dismiss} onClick={onDismiss} aria-label={labels.errorDismiss}>\n <svg viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z\" />\n </svg>\n </button>\n )}\n </div>\n );\n}\n","import type { CSSProperties, ReactNode } from 'react';\nimport type { AiEntity, AiMessage } from '../../core/types';\nimport type { AiInputAction } from '../AiInput/AiInput';\nimport { AiMessageList } from '../AiMessageList/AiMessageList';\nimport { AiInput } from '../AiInput/AiInput';\nimport { AiError } from '../AiError/AiError';\nimport type { RenderPartFn } from '../parts/AiMessagePartRenderer';\nimport styles from './AiChat.module.css';\n\ntype Props = {\n messages: AiMessage[];\n input: string;\n isLoading: boolean;\n isConnecting: boolean;\n error: string | null;\n onInputChange: (value: string) => void;\n onSend: () => void;\n /** Called when the user cancels the in-flight stream. Shown as a stop button while isLoading. */\n onStop?: () => void;\n onProposalConfirm: (proposalId: string, payload: unknown) => void;\n onProposalCancel: (proposalId: string) => void;\n /** Makes entity cards clickable — receives the entity and its optional entityType. */\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\n placeholder?: string;\n /** Override the assistant avatar icon. Forwarded to every message bubble. */\n assistantIcon?: ReactNode;\n /**\n * Toolbar action buttons rendered left of the send button.\n * Pass an empty array to hide the toolbar entirely.\n * Defaults to five built-in actions (attach, quick actions, new, history, rules).\n */\n actions?: AiInputAction[];\n /** Override the send button icon. Defaults to a paper-plane icon. */\n sendIcon?: ReactNode;\n /**\n * Custom part renderer — called before the built-in renderers for every\n * message part. Return a ReactNode to render it, or null/undefined to fall\n * through to the built-ins. Enables custom part types like invoice cards.\n */\n renderPart?: RenderPartFn;\n /**\n * Rendered instead of the default empty-state text when there are no messages.\n * Use it for a rich \"get started\" hero — headline, suggestion chips, anything.\n */\n emptyState?: ReactNode;\n /**\n * Consumer content rendered between the message list / error banner and the\n * input, e.g. a feedback prompt. When omitted nothing renders — not even the\n * wrapper — so the default layout is unaffected.\n */\n aboveInput?: ReactNode;\n className?: string;\n style?: CSSProperties;\n};\n\n/**\n * Presentational chat body — message list, input bar, and error banner.\n * Contains no state or hooks. The parent is responsible for calling useAiChat\n * and passing the results here.\n *\n * Used by AiSidebar (inside the sidebar chrome) and directly in dashboard\n * or any other layout where you want chat without the sidebar wrapper.\n */\nexport function AiChat({\n messages,\n input,\n isLoading,\n isConnecting,\n error,\n onInputChange,\n onSend,\n onStop,\n onProposalConfirm,\n onProposalCancel,\n onEntityClick,\n placeholder,\n assistantIcon,\n actions,\n sendIcon,\n renderPart,\n emptyState,\n aboveInput,\n className,\n style,\n}: Props) {\n return (\n <div\n className={[styles.chat, className].filter(Boolean).join(' ')}\n style={style}\n data-juneau=\"chat\"\n >\n <AiMessageList\n messages={messages}\n isLoading={isLoading}\n isConnecting={isConnecting}\n onProposalConfirm={onProposalConfirm}\n onProposalCancel={onProposalCancel}\n onEntityClick={onEntityClick}\n assistantIcon={assistantIcon}\n renderPart={renderPart}\n emptyState={emptyState}\n />\n\n {error && <AiError message={error} />}\n\n {aboveInput != null && (\n <div className={styles.aboveInput} data-juneau=\"above-input\" data-juneau-above-input=\"\">\n {aboveInput}\n </div>\n )}\n\n <AiInput\n value={input}\n onChange={onInputChange}\n onSend={onSend}\n onStop={onStop}\n isLoading={isLoading}\n placeholder={placeholder}\n actions={actions}\n sendIcon={sendIcon}\n />\n </div>\n );\n}\n","import type { ReactNode } from 'react';\r\nimport {\r\n IconArrowRotateLeft,\r\n IconWandMagicSparkles,\r\n IconWindowMinimize,\r\n IconWindowRestore,\r\n} from '../icons';\r\nimport { useLabels } from '../../i18n/context';\r\nimport styles from './AiChatHeader.module.css';\r\n\r\ntype Props = {\r\n title?: string;\r\n onMinimize?: () => void;\r\n isMinimized?: boolean;\r\n /** Override the avatar icon. Pass any ReactNode — an SVG, img, or component. Defaults to a wand icon. */\r\n icon?: ReactNode;\r\n /** Called when the reset button is clicked. When provided, a reset button is shown. */\r\n onReset?: () => void;\r\n /**\r\n * Rendered right of the title. Use it for an unread/notification badge.\r\n * Juneau renders it as given and never interprets it.\r\n */\r\n badge?: ReactNode;\r\n /**\r\n * Extra controls rendered left of the built-in reset/minimize buttons.\r\n * Juneau renders them as given and never interprets them — the consumer owns their behaviour.\r\n */\r\n headerActions?: ReactNode;\r\n};\r\n\r\nexport function AiChatHeader({\r\n title,\r\n onMinimize,\r\n isMinimized,\r\n icon,\r\n onReset,\r\n badge,\r\n headerActions,\r\n}: Props) {\r\n const labels = useLabels();\r\n\r\n return (\r\n <div className={styles.header} data-juneau=\"header\">\r\n <div className={styles.left}>\r\n <span className={styles.icon} aria-hidden=\"true\" data-juneau=\"header-icon\">\r\n {icon ?? <IconWandMagicSparkles />}\r\n </span>\r\n <span className={styles.title}>{title ?? labels.sidebarTitle}</span>\r\n {badge && (\r\n <span className={styles.badge} data-juneau=\"header-badge\">\r\n {badge}\r\n </span>\r\n )}\r\n </div>\r\n {(onMinimize || onReset || headerActions) && (\r\n <div className={styles.actions}>\r\n {headerActions}\r\n {onReset && (\r\n <button\r\n className={styles.resetBtn}\r\n onClick={onReset}\r\n title={labels.resetConversation}\r\n aria-label={labels.resetConversation}\r\n data-juneau=\"header-reset\"\r\n >\r\n <IconArrowRotateLeft />\r\n </button>\r\n )}\r\n {onMinimize && (\r\n <button\r\n className={styles.resetBtn}\r\n onClick={onMinimize}\r\n title={isMinimized ? labels.expandSidebar : labels.minimizeSidebar}\r\n aria-label={isMinimized ? labels.expandSidebar : labels.minimizeSidebar}\r\n data-juneau=\"header-minimize\"\r\n >\r\n {isMinimized ? <IconWindowRestore /> : <IconWindowMinimize />}\r\n </button>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import type { CSSProperties, ReactNode } from 'react';\r\nimport { useState } from 'react';\r\nimport type { AiEntity } from '../../core/types';\r\nimport { useAiChatContext } from '../../context/AiChatContext';\r\nimport type { AiInputAction } from '../AiInput/AiInput';\r\nimport { AiChat } from '../AiChat/AiChat';\r\nimport { AiChatHeader } from '../AiChatHeader/AiChatHeader';\r\nimport type { RenderPartFn } from '../parts/AiMessagePartRenderer';\r\nimport styles from './AiSidebar.module.css';\r\n\r\ntype Props = {\r\n /** Overrides the `sidebarTitle` label for this instance only. */\r\n title?: string;\r\n /** Override the header and assistant avatar icon. Defaults to a wand icon. */\r\n icon?: ReactNode;\r\n /** Override only the message avatar. Falls back to `icon` when omitted. */\r\n assistantIcon?: ReactNode;\r\n /**\r\n * Toolbar action buttons rendered left of the send button.\r\n * Pass an empty array to hide the toolbar entirely.\r\n */\r\n actions?: AiInputAction[];\r\n /** Override the send button icon. Defaults to a paper-plane icon. */\r\n sendIcon?: ReactNode;\r\n /**\r\n * Height of the sidebar when open. Any valid CSS value.\r\n * Defaults to '60vh'.\r\n */\r\n height?: string;\r\n className?: string;\r\n style?: CSSProperties;\r\n /**\r\n * Called when the user resets the conversation. When provided, a reset\r\n * button is shown in the header. Internally calls `useAiChatContext().reset()`\r\n * and then invokes this callback — no wrapper component needed.\r\n */\r\n onReset?: () => void;\r\n /**\r\n * Gate asked before the conversation is cleared. Resolve false to abort —\r\n * nothing is reset and `onReset` never fires. Use it for a confirm dialog.\r\n */\r\n confirmReset?: () => boolean | Promise<boolean>;\r\n /**\r\n * Custom part renderer — called before the built-in renderers for every\r\n * message part. Return a ReactNode to render it, or null/undefined to fall\r\n * through to the built-ins. Enables custom part types like invoice cards.\r\n */\r\n renderPart?: RenderPartFn;\r\n /** Makes entity cards clickable — receives the entity and its optional entityType. */\r\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\r\n /**\r\n * Extra controls rendered in the header, left of the reset/minimize buttons.\r\n * Use it for consumer-owned chrome such as a settings button.\r\n */\r\n headerActions?: ReactNode;\r\n /**\r\n * Rendered right of the header title. Use it for an unread/notification badge.\r\n * Juneau renders it as given and never interprets it.\r\n */\r\n badge?: ReactNode;\r\n /**\r\n * Collapsed state. Omit to let the sidebar own it; pass a value to control it\r\n * (e.g. to persist the choice) and keep it in sync via `onMinimizedChange`.\r\n */\r\n minimized?: boolean;\r\n /** Fires whenever the user toggles the collapsed state, controlled or not. */\r\n onMinimizedChange?: (minimized: boolean) => void;\r\n /**\r\n * Rendered instead of the default empty-state text when there are no messages.\r\n * Use it for a rich \"get started\" hero — headline, suggestion chips, anything.\r\n */\r\n emptyState?: ReactNode;\r\n /**\r\n * Consumer content rendered directly above the input, e.g. a feedback prompt.\r\n * Forwarded to `AiChat`; hidden together with the chat body while minimized.\r\n */\r\n aboveInput?: ReactNode;\r\n};\r\n\r\nexport function AiSidebar({\r\n title,\r\n icon,\r\n assistantIcon,\r\n actions,\r\n sendIcon,\r\n height = '60vh',\r\n className,\r\n style,\r\n onReset,\r\n confirmReset,\r\n renderPart,\r\n onEntityClick,\r\n headerActions,\r\n badge,\r\n minimized,\r\n onMinimizedChange,\r\n emptyState,\r\n aboveInput,\r\n}: Props) {\r\n const [uncontrolledMinimized, setUncontrolledMinimized] = useState(false);\r\n // Controlled when `minimized` is supplied; otherwise the sidebar keeps owning the state.\r\n const isControlled = minimized !== undefined;\r\n const isMinimized = isControlled ? minimized : uncontrolledMinimized;\r\n\r\n const toggleMinimized = (): void => {\r\n const next = !isMinimized;\r\n if (!isControlled) setUncontrolledMinimized(next);\r\n onMinimizedChange?.(next);\r\n };\r\n\r\n const {\r\n messages,\r\n input,\r\n setInput,\r\n sendMessage,\r\n stop,\r\n isLoading,\r\n isConnecting,\r\n error,\r\n reset,\r\n confirmProposal,\r\n cancelProposal,\r\n } = useAiChatContext();\r\n\r\n // The gate runs before the wipe, so a declined confirm leaves the chat untouched.\r\n const handleReset = onReset\r\n ? async () => {\r\n if (confirmReset && !(await confirmReset())) return;\r\n reset();\r\n onReset();\r\n }\r\n : undefined;\r\n\r\n return (\r\n <aside\r\n className={[styles.sidebar, isMinimized ? styles.minimized : '', className].filter(Boolean).join(' ')}\r\n style={{ height: isMinimized ? undefined : height, ...style }}\r\n data-juneau=\"sidebar\"\r\n >\r\n <AiChatHeader\r\n title={title}\r\n icon={icon}\r\n onMinimize={toggleMinimized}\r\n isMinimized={isMinimized}\r\n onReset={handleReset}\r\n badge={badge}\r\n headerActions={headerActions}\r\n />\r\n\r\n {!isMinimized && (\r\n <AiChat\r\n messages={messages}\r\n input={input}\r\n isLoading={isLoading}\r\n isConnecting={isConnecting}\r\n error={error}\r\n onInputChange={setInput}\r\n onSend={sendMessage}\r\n onStop={stop}\r\n onProposalConfirm={confirmProposal}\r\n onProposalCancel={cancelProposal}\r\n assistantIcon={assistantIcon ?? icon}\r\n actions={actions}\r\n sendIcon={sendIcon}\r\n renderPart={renderPart}\r\n onEntityClick={onEntityClick}\r\n emptyState={emptyState}\r\n aboveInput={aboveInput}\r\n />\r\n )}\r\n </aside>\r\n );\r\n}\r\n","import type { AiChatSummary } from '../../core/types';\nimport { useLabels } from '../../i18n/context';\nimport styles from './AiChatHistoryList.module.css';\n\ntype Props = {\n /** Stored chats to display — most recently updated first is recommended (see `trimChats`) */\n chats: AiChatSummary[];\n /** Called with the chat id when the user picks a chat */\n onSelect: (chatId: string) => void;\n /** Highlights the currently open chat, if any */\n activeChatId?: string;\n /** If provided, shows a delete button on each row */\n onDelete?: (chatId: string) => void;\n};\n\nexport function AiChatHistoryList({ chats, onSelect, activeChatId, onDelete }: Props) {\n const labels = useLabels();\n\n if (chats.length === 0) {\n return <p className={styles.empty}>{labels.historyEmpty}</p>;\n }\n\n return (\n <ul className={styles.list} data-juneau=\"history-list\">\n {chats.map(chat => (\n <li key={chat.id} className={styles.item}>\n <button\n className={chat.id === activeChatId ? `${styles.chat} ${styles.chatActive}` : styles.chat}\n onClick={() => onSelect(chat.id)}\n >\n <span className={styles.title}>{chat.title}</span>\n <span className={styles.date}>\n {chat.updatedAt.toLocaleDateString(undefined, { day: 'numeric', month: 'short' })}\n </span>\n </button>\n {onDelete && (\n <button\n className={styles.delete}\n onClick={() => onDelete(chat.id)}\n aria-label={labels.historyDeleteChat}\n >\n <svg viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z\" />\n </svg>\n </button>\n )}\n </li>\n ))}\n </ul>\n );\n}\n"],"names":["serializeMessages","messages","msg","p","delay","ms","resolve","getMessageText","message","consumeStream","iterable","onEvent","signal","event","isProposalPart","part","isChartPart","STORAGE_FORMAT_VERSION","serializeForStorage","sanitizePart","deserializeMessages","stored","_v","trimHistory","limit","start","trimChats","chats","byUpdatedDesc","a","b","mockAdapter","input","lastUserMessage","m","query","scenarioActivity","scenarioTable","scenarioProposal","scenarioEntity","scenarioHelp","scenarioError","scenarioDefault","streamText","text","chunkDelayMs","i","parseJuneauWire","raw","wire","createSseAdapter","url","options","method","staticHeaders","getHeaders","getBody","getMessages","parseEvent","defaultOpenAiParser","credentials","dynamicHeaders","resolvedInput","body","response","readSseStream","reader","decoder","buffer","done","value","lines","line","trimmed","data","events","json","delta","createFetchStreamAdapter","parseChunk","defaultNdjsonParser","readChunkedStream","chunk","messageIdCounter","nextId","serializeHistory","useAiChat","adapter","context","onProposalConfirm","onProposalCancel","initialMessages","historyLimit","onMessagesChange","setMessages","useState","setInput","isLoading","setIsLoading","isConnecting","setIsConnecting","error","setError","abortRef","useRef","shouldNotifyRef","onMessagesChangeRef","useEffect","appendPartToLast","useCallback","prev","last","parts","existingIndex","appendTextToLast","lastPart","sendMessageCore","currentMessages","userMessage","assistantId","assistantAdded","ensureAssistantBubble","assistantMessage","abort","history","stream","err","sendMessage","sendMessageWithText","sendGreeting","contextHint","syntheticContext","stop","reset","nextMessages","resolveProposal","proposalId","resolved","confirmProposal","payload","cancelProposal","useMemo","juneauEn","JuneauLabelsContext","createContext","useLabels","useContext","JuneauProvider","children","theme","labels","defaultTitle","className","style","resolvedLabels","themeVars","buildThemeVars","jsx","styles","map","v","AiChatContext","useAiChatContext","ctx","useAiChatContextSafe","AiChatProvider","initialContext","setContextState","setContext","chat","juneauCs","IconWandMagicSparkles","ariaHidden","IconPaperPlane","IconPaperclip","IconBolt","IconPlus","IconClockRotateLeft","IconScroll","IconWindowMinimize","IconWindowRestore","IconArrowRotateLeft","IconWarning","AiTablePart","jsxs","col","row","AiProposalCard","onConfirm","onCancel","proposal","resolvedLabel","AiActivityPart","badgeClass","AiEntityCard","onEntityClick","entity","entityType","clickable","Fragment","field","AiEntityListPart","AiMessagePartRenderer","renderPart","custom","Markdown","remarkGfm","INLINE_PART_TYPES","isCardPart","toSegments","segments","index","card","AiMessageBubble","assistantIcon","isUser","renderOne","hasCard","segment","AiTypingIndicator","connecting","AiMessageList","emptyState","bottomRef","AiInput","onChange","onSend","onStop","placeholder","actions","sendIcon","textareaRef","wasLoadingRef","defaultActions","resolvedActions","handleKeyDown","e","action","AiError","onDismiss","AiChat","onInputChange","aboveInput","AiChatHeader","title","onMinimize","isMinimized","icon","onReset","badge","headerActions","AiSidebar","height","confirmReset","minimized","onMinimizedChange","uncontrolledMinimized","setUncontrolledMinimized","isControlled","toggleMinimized","next","handleReset","AiChatHistoryList","onSelect","activeChatId","onDelete"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/core/stream.ts","../src/core/history.ts","../src/adapters/mockAdapter.ts","../src/adapters/parseJuneauWire.ts","../src/adapters/createSseAdapter.ts","../src/adapters/createFetchStreamAdapter.ts","../src/hooks/useAiChat.ts","../src/i18n/locales/en.ts","../src/i18n/context.ts","../src/components/JuneauProvider/JuneauProvider.tsx","../src/context/AiChatContext.ts","../src/context/AiChatProvider.tsx","../src/i18n/locales/cs.ts","../src/components/icons.tsx","../src/components/parts/AiTablePart.tsx","../src/components/parts/AiProposalCard.tsx","../src/components/parts/AiActivityPart.tsx","../src/components/parts/AiEntityCard.tsx","../src/components/parts/AiEntityListPart.tsx","../src/components/parts/AiMessagePartRenderer.tsx","../src/components/AiMessageBubble/AiMessageBubble.tsx","../src/components/AiTypingIndicator/AiTypingIndicator.tsx","../src/components/AiMessageList/AiMessageList.tsx","../src/components/AiInput/AiInput.tsx","../src/components/AiError/AiError.tsx","../src/components/AiChat/AiChat.tsx","../src/components/AiChatHeader/AiChatHeader.tsx","../src/components/AiSidebar/AiSidebar.tsx","../src/components/AiChatHistoryList/AiChatHistoryList.tsx"],"sourcesContent":["import type { AiMessage, AiStreamEvent } from './types';\n\n/**\n * Prepares a message history array for sending to the backend adapter —\n * the exact same transformation Juneau applies internally before every request.\n *\n * Assistant messages that contain only activity or error parts (no text) are\n * replaced with an empty-text assistant turn so conversation alternation stays\n * valid. Models reject histories where two user messages appear consecutively\n * with no assistant turn in between.\n *\n * Use this to inspect or replicate what Juneau actually sends, e.g. when\n * building a custom adapter or debugging history shape:\n *\n * @example\n * const wire = serializeMessages(messages);\n * console.log(JSON.stringify(wire, null, 2));\n */\nexport function serializeMessages(messages: AiMessage[]): AiMessage[] {\n return messages.map(msg => {\n if (msg.role !== 'assistant') return msg;\n if (msg.parts.some(p => p.type === 'text')) return msg;\n return { ...msg, parts: [{ type: 'text' as const, text: '' }] };\n });\n}\n\nexport const delay = (ms: number): Promise<void> =>\n new Promise(resolve => setTimeout(resolve, ms));\n\n/**\n * Extracts the plain text content from a message.\n *\n * Concatenates all `text` parts in order. Non-text parts (tables, proposals,\n * errors) are skipped. Returns an empty string if the message has no text parts.\n *\n * Use this in your adapter when you need to read a message's text without\n * digging into the parts array yourself:\n *\n * @example\n * const { messages } = input;\n * const lastUser = [...messages].reverse().find(m => m.role === 'user');\n * const text = lastUser ? getMessageText(lastUser) : '';\n */\nexport function getMessageText(message: AiMessage): string {\n return message.parts\n .filter((p): p is import('./types').AiTextPart => p.type === 'text')\n .map(p => p.text)\n .join('');\n}\n\n/**\n * Iterates over an AsyncIterable of stream events and calls the handler for each.\n * Automatically handles cancellation via AbortSignal.\n */\nexport async function consumeStream(\n iterable: AsyncIterable<AiStreamEvent>,\n onEvent: (event: AiStreamEvent) => void,\n signal?: AbortSignal\n): Promise<void> {\n for await (const event of iterable) {\n if (signal?.aborted) break;\n onEvent(event);\n if (event.type === 'done' || event.type === 'error') break;\n }\n}\n","import type {\n AiChartPart,\n AiChatSummary,\n AiMessage,\n AiMessagePart,\n AiProposalPart,\n AiSerializedMessage,\n} from './types';\n\n/**\n * Narrows a part to a proposal. Needed because `AiCustomPart`'s index\n * signature keeps TypeScript from narrowing the union on `type` alone.\n */\nexport function isProposalPart(part: AiMessagePart): part is AiProposalPart {\n return part.type === 'proposal';\n}\n\n/**\n * Narrows a part to a chart. Checks structure, not just `type` — chart parts\n * may be restored from persisted history written by older consumers.\n */\nexport function isChartPart(part: AiMessagePart): part is AiChartPart {\n return part.type === 'chart' && Array.isArray((part as AiChartPart).series);\n}\n\n/**\n * Prepares messages for persistence. Returns plain JSON-safe objects:\n *\n * - `createdAt` dates become ISO strings\n * - unresolved proposals are marked `resolved: 'expired'` so a restored card\n * can never fire callbacks against a stale payload\n * - `running` activity parts are dropped — a restored \"in progress\" row would\n * look permanently stuck\n *\n * @example\n * localStorage.setItem('chat', JSON.stringify(serializeForStorage(messages)));\n */\n/** Current persistence format version written by {@link serializeForStorage}. */\nconst STORAGE_FORMAT_VERSION = 1;\n\nexport function serializeForStorage(messages: AiMessage[]): AiSerializedMessage[] {\n return messages.map(msg => ({\n ...msg,\n v: STORAGE_FORMAT_VERSION,\n createdAt: msg.createdAt.toISOString(),\n parts: msg.parts\n .filter(part => !(part.type === 'activity' && part.status === 'running'))\n .map(sanitizePart),\n }));\n}\n\nfunction sanitizePart(part: AiMessagePart): AiMessagePart {\n if (isProposalPart(part) && !part.proposal.resolved) {\n return { ...part, proposal: { ...part.proposal, resolved: 'expired' } };\n }\n return part;\n}\n\n/**\n * Restores messages persisted with {@link serializeForStorage} back into the\n * live `AiMessage[]` shape Juneau expects — revives `createdAt` dates.\n * Accepts the parsed JSON value, not the raw string.\n *\n * @example\n * const stored = JSON.parse(localStorage.getItem('chat') ?? '[]');\n * const messages = deserializeMessages(stored);\n */\nexport function deserializeMessages(stored: AiSerializedMessage[]): AiMessage[] {\n // Missing `v` means v1 (pre-versioned histories) — same shape, parses as-is\n return stored.map(({ v: _v, ...msg }) => ({\n ...msg,\n createdAt: new Date(msg.createdAt),\n }));\n}\n\n/**\n * Trims a conversation to at most `limit` messages for sending to the model,\n * keeping the most recent ones. Purely a token-saving measure — rendering is\n * never trimmed.\n *\n * The cut never lands mid-exchange: if the oldest surviving message is an\n * assistant turn, it is dropped too, so the history always starts with a user\n * (or system) message and alternation stays valid.\n */\nexport function trimHistory(messages: AiMessage[], limit: number): AiMessage[] {\n if (limit <= 0 || messages.length <= limit) return messages;\n let start = messages.length - limit;\n while (start < messages.length && messages[start].role === 'assistant') {\n start++;\n }\n return messages.slice(start);\n}\n\n/**\n * Enforces an overall chats limit: returns the `limit` most recently updated\n * chats. Use the returned list to know which chats to keep; delete the rest\n * from your storage.\n */\nexport function trimChats(chats: AiChatSummary[], limit: number): AiChatSummary[] {\n if (limit <= 0 || chats.length <= limit) return [...chats].sort(byUpdatedDesc);\n return [...chats].sort(byUpdatedDesc).slice(0, limit);\n}\n\nconst byUpdatedDesc = (a: AiChatSummary, b: AiChatSummary): number =>\n b.updatedAt.getTime() - a.updatedAt.getTime();\n","import { delay, getMessageText } from '../core/stream';\nimport type { AiBackendAdapter, AiAdapterInput, AiStreamEvent } from '../core/types';\n\n/**\n * Simulates AI streaming responses for development and testing.\n * Triggers different scenarios based on keywords in the last user message.\n * Replace with a real adapter (OpenAI, Anthropic, custom backend) in production.\n */\nexport const mockAdapter: AiBackendAdapter = {\n async *sendMessage(input: AiAdapterInput): AsyncIterable<AiStreamEvent> {\n const lastUserMessage = [...input.messages].reverse().find(m => m.role === 'user');\n const query = lastUserMessage ? getMessageText(lastUserMessage).toLowerCase() : '';\n\n if (query.includes('activity') || query.includes('progress') || query.includes('document') || query.includes('dokument')) {\n yield* scenarioActivity();\n } else if (query.includes('table') || query.includes('data') || query.includes('list') || query.includes('show')) {\n yield* scenarioTable();\n } else if (query.includes('proposal') || query.includes('suggest') || query.includes('recommend')) {\n yield* scenarioProposal();\n } else if (query.includes('entity') || query.includes('card') || query.includes('detail') || query.includes('find')) {\n yield* scenarioEntity();\n } else if (query.includes('help') || query.includes('what can') || query.includes('how do')) {\n yield* scenarioHelp();\n } else if (query.includes('error') || query.includes('fail') || query.includes('break')) {\n yield* scenarioError();\n } else {\n yield* scenarioDefault(query);\n }\n }\n};\n\nasync function* scenarioActivity(): AsyncIterable<AiStreamEvent> {\n yield {\n type: 'part',\n part: {\n type: 'activity',\n id: 'select-skill',\n title: 'Selecting skill',\n description: 'Looking for the best skill for this request.',\n status: 'running',\n },\n };\n\n await delay(700);\n\n yield {\n type: 'part',\n part: {\n type: 'activity',\n id: 'select-skill',\n title: 'Skill selected',\n description: 'Using Document Search.',\n status: 'done',\n },\n };\n\n await delay(300);\n\n yield {\n type: 'part',\n part: {\n type: 'activity',\n id: 'search-document',\n title: 'Searching document',\n description: 'Looking up document by ID.',\n status: 'running',\n },\n };\n\n await delay(900);\n\n yield {\n type: 'part',\n part: {\n type: 'activity',\n id: 'search-document',\n title: 'Document found',\n description: 'Found document INV-2024-0894.',\n status: 'done',\n },\n };\n\n await delay(300);\n\n yield* streamText('\\nFound document **INV-2024-0894** from **DataSys a.s.** for **CZK 390 000**.', 25);\n yield { type: 'done' };\n}\n\nasync function* scenarioTable(): AsyncIterable<AiStreamEvent> {\n yield* streamText('Here is a summary of the data you requested:\\n\\n', 30);\n await delay(400);\n\n yield {\n type: 'part',\n part: {\n type: 'table',\n columns: ['Name', 'Category', 'Value', 'Status'],\n rows: [\n { Name: 'Item Alpha', Category: 'Type A', Value: '1,200', Status: 'Active' },\n { Name: 'Item Beta', Category: 'Type B', Value: '840', Status: 'Active' },\n { Name: 'Item Gamma', Category: 'Type A', Value: '3,050', Status: 'Pending' },\n { Name: 'Item Delta', Category: 'Type C', Value: '610', Status: 'Inactive' },\n { Name: 'Item Epsilon', Category: 'Type B', Value: '2,200', Status: 'Active' },\n ]\n }\n };\n\n await delay(300);\n yield* streamText('\\nTotal across all entries: **7,900** — Type A accounts for the largest share at 53%.', 25);\n yield { type: 'done' };\n}\n\nasync function* scenarioProposal(): AsyncIterable<AiStreamEvent> {\n yield* streamText('Based on the current data, I have a suggestion for you:\\n\\n', 30);\n await delay(500);\n\n yield {\n type: 'part',\n part: {\n type: 'proposal',\n proposal: {\n id: 'mock-proposal-1',\n title: 'Save this as a recurring report',\n description: 'This summary can be automatically generated on a schedule so you always have up-to-date insights.',\n confirmLabel: 'Save report',\n cancelLabel: 'Dismiss',\n payload: { reportType: 'summary', schedule: 'weekly' }\n }\n }\n };\n\n yield { type: 'done' };\n}\n\nasync function* scenarioEntity(): AsyncIterable<AiStreamEvent> {\n yield* streamText('I found these records matching your request:\\n\\n', 30);\n await delay(400);\n\n yield {\n type: 'part',\n part: {\n type: 'entity-list',\n title: '2 records found',\n entityType: 'record',\n entities: [\n {\n id: 'rec-2024-0894',\n title: 'REC-2024-0894',\n subtitle: 'DataSys a.s.',\n fields: [\n { label: 'Amount', value: 'CZK 390 000' },\n { label: 'Due date', value: '2024-08-15' },\n { label: 'Status', value: 'Approved', badge: 'success' },\n ],\n },\n {\n id: 'rec-2024-0895',\n title: 'REC-2024-0895',\n subtitle: 'NetFlow s.r.o.',\n fields: [\n { label: 'Amount', value: 'CZK 218 500' },\n { label: 'Due date', value: '2024-08-22' },\n { label: 'Status', value: 'Pending', badge: 'warning' },\n ],\n },\n ],\n },\n };\n\n await delay(300);\n\n yield* streamText('\\nHere is the detail of the first one:\\n\\n', 25);\n await delay(300);\n\n yield {\n type: 'part',\n part: {\n type: 'entity',\n entityType: 'record',\n entity: {\n id: 'rec-2024-0894',\n title: 'REC-2024-0894',\n subtitle: 'DataSys a.s. — Consulting',\n fields: [\n { label: 'Amount', value: 'CZK 390 000' },\n { label: 'Issued', value: '2024-07-15' },\n { label: 'Due date', value: '2024-08-15' },\n { label: 'Status', value: 'Approved', badge: 'success' },\n ],\n },\n },\n };\n\n yield { type: 'done' };\n}\n\nasync function* scenarioHelp(): AsyncIterable<AiStreamEvent> {\n yield* streamText('I\\'m a general-purpose AI assistant. Here\\'s what I can help with:\\n\\n', 30);\n await delay(200);\n yield* streamText('- **Summarise data** — ask me to show, list, or summarise information\\n', 22);\n await delay(150);\n yield* streamText('- **Make suggestions** — ask me to recommend or propose something\\n', 22);\n await delay(150);\n yield* streamText('- **Answer questions** — ask me anything and I\\'ll do my best\\n', 22);\n await delay(200);\n yield* streamText('\\nTry asking: *\"Show me the data\"* or *\"Can you suggest something?\"*', 25);\n yield { type: 'done' };\n}\n\nasync function* scenarioError(): AsyncIterable<AiStreamEvent> {\n yield* streamText('Attempting to process your request…', 30);\n await delay(800);\n yield { type: 'error', message: 'Simulated error: the upstream service returned an unexpected response.' };\n}\n\nasync function* scenarioDefault(query: string): AsyncIterable<AiStreamEvent> {\n yield* streamText(`Got it — you asked about *\"${query || 'your request'}\"*.\\n\\n`, 30);\n await delay(400);\n yield* streamText('I\\'m a **mock adapter** used for development. I respond to a few trigger words:\\n\\n', 25);\n await delay(200);\n yield* streamText('- Say **\"show\"**, **\"list\"**, **\"data\"**, or **\"table\"** → renders a data table\\n', 22);\n await delay(150);\n yield* streamText('- Say **\"suggest\"**, **\"recommend\"**, or **\"proposal\"** → renders a proposal card\\n', 22);\n await delay(150);\n yield* streamText('- Say **\"entity\"**, **\"card\"**, **\"detail\"**, or **\"find\"** → renders entity cards\\n', 22);\n await delay(150);\n yield* streamText('- Say **\"help\"** or **\"what can you do\"** → shows capabilities\\n', 22);\n await delay(150);\n yield* streamText('- Say **\"error\"** or **\"fail\"** → simulates an error response\\n', 22);\n yield { type: 'done' };\n}\n\nasync function* streamText(text: string, chunkDelayMs: number): AsyncIterable<AiStreamEvent> {\n const chunkSize = 3;\n for (let i = 0; i < text.length; i += chunkSize) {\n yield { type: 'text', text: text.slice(i, i + chunkSize) };\n await delay(chunkDelayMs);\n }\n}\n","import type { AiStreamEvent, JuneauWireEvent } from '../core/types';\n\n/**\n * Parses a single JSON string as a Juneau wire protocol event and maps it\n * to one or more AiStreamEvents.\n *\n * Used by both createSseAdapter and createFetchStreamAdapter as their default\n * parser when the backend streams Juneau-compatible JSON.\n *\n * Returns an empty array for unrecognised or unparseable input — never throws.\n */\nexport function parseJuneauWire(raw: string): AiStreamEvent[] {\n if (!raw || raw === '[DONE]') return [];\n\n let wire: JuneauWireEvent;\n try {\n wire = JSON.parse(raw) as JuneauWireEvent;\n } catch {\n return [];\n }\n\n switch (wire.type) {\n case 'text':\n return wire.text ? [{ type: 'text', text: wire.text }] : [];\n\n case 'activity':\n return [{\n type: 'part',\n part: {\n type: 'activity',\n id: wire.id,\n title: wire.title,\n description: wire.description,\n status: wire.status,\n metadata: wire.metadata,\n },\n }];\n\n case 'part':\n return [{ type: 'part', part: wire.part }];\n\n case 'done':\n return [{ type: 'done' }];\n\n case 'error':\n return [{ type: 'error', message: wire.message }];\n\n default:\n return [];\n }\n}\n","import type { AiBackendAdapter, AiAdapterInput, AiStreamEvent, JuneauWireEvent } from '../core/types';\nimport { parseJuneauWire } from './parseJuneauWire';\n\n/**\n * How to map a parsed SSE data payload to Juneau stream events.\n *\n * Return an array — most lines produce one event, but you can return multiple\n * or an empty array to skip a line entirely.\n */\nexport type SseEventParser = (data: string) => AiStreamEvent[];\n\n/**\n * Options for createSseAdapter.\n */\nexport type SseAdapterOptions = {\n /**\n * HTTP method. Defaults to 'POST'.\n */\n method?: string;\n\n /**\n * Static headers merged with Content-Type. Use for auth tokens etc.\n * For dynamic headers (e.g. per-request auth), use getHeaders instead.\n *\n * @example { Authorization: 'Bearer sk-...' }\n */\n headers?: Record<string, string>;\n\n /**\n * Dynamic headers — called before every request with the current adapter input.\n * Merged on top of `headers`. Use this when the token is fetched at runtime.\n */\n getHeaders?: (input: AiAdapterInput) => Record<string, string> | Promise<Record<string, string>>;\n\n /**\n * Override the request body. By default sends `{ messages, context }`.\n * Return anything JSON-serialisable.\n */\n getBody?: (input: AiAdapterInput) => unknown;\n\n /**\n * Transform the message history before it is sent to the backend.\n * Called with the full `AiMessage[]` that would normally be sent and must\n * return the transformed array (or a promise of one).\n *\n * Use this to remap roles, filter messages, or convert to a backend-specific\n * schema without having to write a full custom adapter.\n *\n * @example\n * // Strip system messages before sending:\n * getMessages: (msgs) => msgs.filter(m => m.role !== 'system')\n *\n * @example\n * // Convert to Anthropic SDK message format:\n * getMessages: (msgs) => toSdkMessages(msgs)\n */\n getMessages?: (messages: AiAdapterInput['messages']) => AiAdapterInput['messages'] | Promise<AiAdapterInput['messages']>;\n\n /**\n * Credentials mode passed to fetch. Use `'include'` for cross-origin requests\n * that require cookies (e.g. session-based auth to a different domain).\n * Defaults to browser default (`'same-origin'`).\n *\n * @example\n * credentials: 'include'\n */\n credentials?: RequestCredentials;\n\n /**\n * Custom SSE line parser. Receives the raw string after `data: ` and returns\n * zero or more Juneau stream events.\n *\n * Defaults to an OpenAI-compatible parser that reads\n * `choices[0].delta.content` and handles `[DONE]`.\n *\n * @example\n * // For a backend that streams { text: \"...\" } JSON lines:\n * parseEvent: (data) => {\n * const json = JSON.parse(data);\n * return json.text ? [{ type: 'text', text: json.text }] : [];\n * }\n */\n parseEvent?: SseEventParser;\n};\n\n/**\n * Creates an adapter that connects to a **Server-Sent Events (SSE)** streaming\n * endpoint — the format used by OpenAI, Anthropic, and most AI backend proxies.\n *\n * The default parser understands OpenAI's streaming format out of the box.\n * Override `parseEvent` for any other SSE schema.\n *\n * @example\n * // OpenAI-compatible backend proxy — works with zero configuration:\n * const adapter = createSseAdapter('/api/chat');\n *\n * @example\n * // With auth header:\n * const adapter = createSseAdapter('/api/chat', {\n * getHeaders: async () => ({\n * Authorization: `Bearer ${await getToken()}`,\n * }),\n * });\n *\n * @example\n * // Custom body shape:\n * const adapter = createSseAdapter('/api/chat', {\n * getBody: ({ messages, context }) => ({\n * messages,\n * model: 'gpt-4o',\n * stream: true,\n * ...(context?.systemPrompt ? { system: context.systemPrompt } : {}),\n * }),\n * });\n *\n * @example\n * // Custom SSE schema (backend streams { text: \"...\" }):\n * const adapter = createSseAdapter('/api/chat', {\n * parseEvent: (data) => {\n * try {\n * const json = JSON.parse(data);\n * return json.text ? [{ type: 'text', text: json.text }] : [];\n * } catch {\n * return [];\n * }\n * },\n * });\n */\nexport function createSseAdapter(url: string, options: SseAdapterOptions = {}): AiBackendAdapter {\n const {\n method = 'POST',\n headers: staticHeaders = {},\n getHeaders,\n getBody,\n getMessages,\n parseEvent = defaultOpenAiParser,\n credentials,\n } = options;\n\n return {\n async *sendMessage(input: AiAdapterInput): AsyncIterable<AiStreamEvent> {\n const dynamicHeaders = getHeaders ? await getHeaders(input) : {};\n\n const messages = getMessages ? await getMessages(input.messages) : input.messages;\n const resolvedInput: AiAdapterInput = { ...input, messages };\n\n const body = getBody\n ? getBody(resolvedInput)\n : { messages: resolvedInput.messages, context: resolvedInput.context };\n\n const response = await fetch(url, {\n method,\n credentials,\n headers: {\n 'Content-Type': 'application/json',\n ...staticHeaders,\n ...dynamicHeaders,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const message = await response.text().catch(() => `HTTP ${response.status}`);\n yield { type: 'error', message: `Request failed (${response.status}): ${message}` };\n return;\n }\n\n if (!response.body) {\n yield { type: 'error', message: 'Response body is empty — server may not support streaming.' };\n return;\n }\n\n yield* readSseStream(response.body, parseEvent);\n },\n };\n}\n\n// ─── SSE stream reader ────────────────────────────────────────────────────────\n\nasync function* readSseStream(\n body: ReadableStream<Uint8Array>,\n parseEvent: SseEventParser,\n): AsyncIterable<AiStreamEvent> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // SSE lines are separated by \\n\\n (double newline)\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? ''; // keep the incomplete last line\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(':')) continue; // empty or SSE comment\n\n if (trimmed.startsWith('data: ')) {\n const data = trimmed.slice(6); // strip \"data: \"\n\n if (data === '[DONE]') {\n yield { type: 'done' };\n return;\n }\n\n const events = parseEvent(data);\n for (const event of events) {\n yield event;\n if (event.type === 'done' || event.type === 'error') return;\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n yield { type: 'done' };\n}\n\n// ─── Default parser ───────────────────────────────────────────────────────────\n//\n// Tries Juneau wire protocol first. If the line looks like an OpenAI streaming\n// response instead (choices[0].delta.content), falls back to that so the adapter\n// works out of the box with OpenAI-compatible backends too.\n\nconst defaultOpenAiParser: SseEventParser = (data) => {\n if (!data || data === '[DONE]') return [];\n\n // Try Juneau wire protocol first\n const wire = parseJuneauWire(data);\n if (wire.length > 0) return wire;\n\n // Fallback: OpenAI chat completions streaming format\n try {\n const json = JSON.parse(data) as {\n choices?: Array<{ delta?: { content?: string | null }; finish_reason?: string | null }>;\n error?: { message?: string };\n };\n\n if (json.error?.message) {\n return [{ type: 'error', message: json.error.message }];\n }\n\n const delta = json.choices?.[0]?.delta;\n const finishReason = json.choices?.[0]?.finish_reason;\n\n if (finishReason === 'stop') return [{ type: 'done' }];\n if (delta?.content) return [{ type: 'text', text: delta.content }];\n\n return [];\n } catch {\n return [];\n }\n};\n","import type { AiBackendAdapter, AiAdapterInput, AiStreamEvent, JuneauWireEvent } from '../core/types';\nimport { parseJuneauWire } from './parseJuneauWire';\n\n/**\n * How to map a raw text chunk from the response body to Juneau stream events.\n *\n * Return an array — a chunk may produce one event, multiple, or none (empty array to skip).\n * The chunk is whatever the server sent — could be a full JSON line, a partial one,\n * or plain text depending on your backend.\n */\nexport type FetchChunkParser = (chunk: string) => AiStreamEvent[];\n\n/**\n * Options for createFetchStreamAdapter.\n */\nexport type FetchStreamAdapterOptions = {\n /**\n * HTTP method. Defaults to 'POST'.\n */\n method?: string;\n\n /**\n * Static headers merged with Content-Type. Use for auth tokens etc.\n * For dynamic headers (e.g. per-request auth), use getHeaders instead.\n *\n * @example { Authorization: 'Bearer sk-...' }\n */\n headers?: Record<string, string>;\n\n /**\n * Dynamic headers — called before every request with the current adapter input.\n * Merged on top of `headers`. Use this when the token is fetched at runtime.\n */\n getHeaders?: (input: AiAdapterInput) => Record<string, string> | Promise<Record<string, string>>;\n\n /**\n * Override the request body. By default sends `{ messages, context }`.\n * Return anything JSON-serialisable.\n */\n getBody?: (input: AiAdapterInput) => unknown;\n\n /**\n * Credentials mode passed to fetch. Use `'include'` for cross-origin requests\n * that require cookies (e.g. session-based auth to a different domain).\n * Defaults to browser default (`'same-origin'`).\n *\n * @example\n * credentials: 'include'\n */\n credentials?: RequestCredentials;\n\n /**\n * How to parse each chunk from the response stream into Juneau events.\n *\n * Defaults to a newline-delimited JSON (NDJSON) parser that expects each\n * line to be either `{ text: \"...\" }` or `{ done: true }`.\n *\n * @example\n * // Plain text streaming — treat every chunk as raw text:\n * parseChunk: (chunk) => chunk ? [{ type: 'text', text: chunk }] : []\n *\n * @example\n * // Custom JSON lines format:\n * parseChunk: (chunk) => {\n * try {\n * const json = JSON.parse(chunk);\n * if (json.error) return [{ type: 'error', message: json.error }];\n * if (json.done) return [{ type: 'done' }];\n * if (json.delta) return [{ type: 'text', text: json.delta }];\n * return [];\n * } catch { return []; }\n * }\n */\n parseChunk?: FetchChunkParser;\n};\n\n/**\n * Creates an adapter that connects to a **raw chunked HTTP streaming** endpoint —\n * for backends that stream newline-delimited JSON (NDJSON) or plain text,\n * rather than SSE.\n *\n * Use `createSseAdapter` instead if your backend streams Server-Sent Events\n * (the format used by OpenAI, Anthropic, and most AI APIs).\n *\n * @example\n * // NDJSON backend streaming { text: \"...\" } lines — works with zero config:\n * const adapter = createFetchStreamAdapter('/api/chat');\n *\n * @example\n * // Plain text streaming (each chunk is raw text, no JSON):\n * const adapter = createFetchStreamAdapter('/api/chat', {\n * parseChunk: (chunk) => chunk ? [{ type: 'text', text: chunk }] : [],\n * });\n *\n * @example\n * // Custom body + auth:\n * const adapter = createFetchStreamAdapter('/api/chat', {\n * getHeaders: async () => ({ Authorization: `Bearer ${await getToken()}` }),\n * getBody: ({ messages, context }) => ({\n * history: messages,\n * model: context?.model ?? 'default',\n * }),\n * });\n */\nexport function createFetchStreamAdapter(\n url: string,\n options: FetchStreamAdapterOptions = {},\n): AiBackendAdapter {\n const {\n method = 'POST',\n headers: staticHeaders = {},\n getHeaders,\n getBody,\n parseChunk = defaultNdjsonParser,\n credentials,\n } = options;\n\n return {\n async *sendMessage(input: AiAdapterInput): AsyncIterable<AiStreamEvent> {\n const dynamicHeaders = getHeaders ? await getHeaders(input) : {};\n\n const body = getBody\n ? getBody(input)\n : { messages: input.messages, context: input.context };\n\n const response = await fetch(url, {\n method,\n credentials,\n headers: {\n 'Content-Type': 'application/json',\n ...staticHeaders,\n ...dynamicHeaders,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const message = await response.text().catch(() => `HTTP ${response.status}`);\n yield { type: 'error', message: `Request failed (${response.status}): ${message}` };\n return;\n }\n\n if (!response.body) {\n yield { type: 'error', message: 'Response body is empty — server may not support streaming.' };\n return;\n }\n\n yield* readChunkedStream(response.body, parseChunk);\n },\n };\n}\n\n// ─── Chunked stream reader ────────────────────────────────────────────────────\n\nasync function* readChunkedStream(\n body: ReadableStream<Uint8Array>,\n parseChunk: FetchChunkParser,\n): AsyncIterable<AiStreamEvent> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // Split on newlines — each complete line is one NDJSON record\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? ''; // keep the incomplete trailing line\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n const events = parseChunk(trimmed);\n for (const event of events) {\n yield event;\n if (event.type === 'done' || event.type === 'error') return;\n }\n }\n }\n\n // Flush any remaining buffered content\n if (buffer.trim()) {\n const events = parseChunk(buffer.trim());\n for (const event of events) {\n yield event;\n if (event.type === 'done' || event.type === 'error') return;\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n yield { type: 'done' };\n}\n\n// ─── Default parser: Juneau wire protocol (NDJSON) ───────────────────────────\n//\n// Each newline-delimited chunk is parsed as a JuneauWireEvent.\n// Falls back to treating the chunk as plain text if it can't be parsed.\n\nconst defaultNdjsonParser: FetchChunkParser = (chunk) => {\n const wire = parseJuneauWire(chunk);\n if (wire.length > 0) return wire;\n\n // Not a Juneau wire event — treat the raw chunk as plain text\n return chunk ? [{ type: 'text', text: chunk }] : [];\n};\n","import { useState, useCallback, useRef, useEffect, useMemo } from 'react';\nimport { consumeStream, serializeMessages } from '../core/stream';\nimport { trimHistory, isProposalPart } from '../core/history';\nimport type {\n AiMessage,\n AiMessagePart,\n AiBackendAdapter,\n AiStreamEvent\n} from '../core/types';\n\nlet messageIdCounter = 0;\nconst nextId = (): string => `msg-${++messageIdCounter}-${Date.now()}`;\n\n/** Internal alias used throughout this hook. */\nconst serializeHistory = serializeMessages;\n\nexport type UseAiChatOptions = {\n adapter: AiBackendAdapter;\n /** Optional context passed through to every adapter call */\n context?: Record<string, unknown>;\n /** Called when a proposal is confirmed */\n onProposalConfirm?: (proposalId: string, payload: unknown) => void;\n /** Called when a proposal is cancelled */\n onProposalCancel?: (proposalId: string) => void;\n /**\n * Restored conversation to start with — typically the output of\n * `deserializeMessages`. Read once on mount; switch chats later via\n * `reset(nextMessages)`.\n */\n initialMessages?: AiMessage[];\n /**\n * Maximum number of messages sent to the adapter per request — a\n * token-saving measure. Rendering is never trimmed; the cut keeps the most\n * recent messages and never splits a user/assistant exchange. Unlimited by\n * default.\n */\n historyLimit?: number;\n /**\n * Called whenever the conversation settles: an exchange finishes streaming,\n * a proposal is resolved, or the chat is reset. Never called per streamed\n * token. Use this to persist the conversation (see `serializeForStorage`).\n */\n onMessagesChange?: (messages: AiMessage[]) => void;\n};\n\nexport type UseAiChatReturn = {\n messages: AiMessage[];\n input: string;\n setInput: (value: string) => void;\n sendMessage: () => Promise<void>;\n /** Sends a message with the given text without touching the input field. Useful for programmatic/init triggers. */\n sendMessageWithText: (text: string) => Promise<void>;\n /**\n * Triggers the adapter with a synthetic context message and streams the response\n * as an assistant message — no user bubble is shown. Use this for proactive\n * greetings or page-load summaries where the AI speaks first.\n */\n sendGreeting: (contextHint: string) => Promise<void>;\n /** Aborts the in-flight stream. No-op if nothing is streaming. */\n stop: () => void;\n isLoading: boolean;\n /**\n * True from the moment a message is sent until the first token arrives from the stream.\n * Use this to show a \"connecting…\" state distinct from the typing indicator shown\n * while tokens are actively streaming in.\n */\n isConnecting: boolean;\n error: string | null;\n /**\n * Clears the conversation and aborts any in-flight stream. Pass\n * `nextMessages` to load a different stored chat instead of starting empty.\n */\n reset: (nextMessages?: AiMessage[]) => void;\n confirmProposal: (proposalId: string, payload: unknown) => void;\n cancelProposal: (proposalId: string) => void;\n};\n\nexport function useAiChat({\n adapter,\n context,\n onProposalConfirm,\n onProposalCancel,\n initialMessages,\n historyLimit,\n onMessagesChange\n}: UseAiChatOptions): UseAiChatReturn {\n const [messages, setMessages] = useState<AiMessage[]>(initialMessages ?? []);\n const [input, setInput] = useState('');\n const [isLoading, setIsLoading] = useState(false);\n const [isConnecting, setIsConnecting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Ref so consumeStream callback always sees latest messages without stale closure\n const abortRef = useRef<AbortController | null>(null);\n\n // onMessagesChange fires only when the conversation settles (stream done,\n // proposal resolved, reset) — never per token. The flag is raised at those\n // points and consumed here once React has committed the final message state.\n const shouldNotifyRef = useRef(false);\n const onMessagesChangeRef = useRef(onMessagesChange);\n useEffect(() => {\n onMessagesChangeRef.current = onMessagesChange;\n });\n useEffect(() => {\n if (!shouldNotifyRef.current || isLoading) return;\n shouldNotifyRef.current = false;\n onMessagesChangeRef.current?.(messages);\n }, [messages, isLoading]);\n\n const appendPartToLast = useCallback((part: AiMessagePart) => {\n setMessages(prev => {\n const last = prev[prev.length - 1];\n if (!last || last.role !== 'assistant') return prev;\n\n // Activity parts with a stable id upsert in-place instead of appending\n if (part.type === 'activity' && part.id) {\n const parts = [...last.parts];\n const existingIndex = parts.findIndex(\n p => p.type === 'activity' && p.id === part.id\n );\n if (existingIndex !== -1) {\n parts[existingIndex] = part;\n return [...prev.slice(0, -1), { ...last, parts }];\n }\n }\n\n return [\n ...prev.slice(0, -1),\n { ...last, parts: [...last.parts, part] }\n ];\n });\n }, []);\n\n const appendTextToLast = useCallback((chunk: string) => {\n setMessages(prev => {\n const last = prev[prev.length - 1];\n if (!last || last.role !== 'assistant') return prev;\n\n const parts = [...last.parts];\n const lastPart = parts[parts.length - 1];\n\n if (lastPart?.type === 'text') {\n parts[parts.length - 1] = { type: 'text', text: lastPart.text + chunk };\n } else {\n parts.push({ type: 'text', text: chunk });\n }\n\n return [...prev.slice(0, -1), { ...last, parts }];\n });\n }, []);\n\n const sendMessageCore = useCallback(async (text: string, currentMessages: AiMessage[]) => {\n setError(null);\n\n const userMessage: AiMessage = {\n id: nextId(),\n role: 'user',\n parts: [{ type: 'text', text }],\n createdAt: new Date(),\n };\n\n // Don't add the assistant placeholder upfront — add it lazily on the first\n // event so an immediate error doesn't leave a blank bubble in the UI.\n const assistantId = nextId();\n let assistantAdded = false;\n\n const ensureAssistantBubble = () => {\n if (assistantAdded) return;\n assistantAdded = true;\n const assistantMessage: AiMessage = {\n id: assistantId,\n role: 'assistant',\n parts: [],\n createdAt: new Date(),\n };\n setMessages(prev => [...prev, assistantMessage]);\n };\n\n setMessages(prev => [...prev, userMessage]);\n setIsLoading(true);\n setIsConnecting(true);\n\n abortRef.current?.abort();\n const abort = new AbortController();\n abortRef.current = abort;\n\n try {\n const history = trimHistory(\n [...currentMessages, userMessage],\n historyLimit ?? Number.POSITIVE_INFINITY\n );\n const stream = adapter.sendMessage({ messages: serializeHistory(history), context });\n\n await consumeStream(\n stream,\n (event: AiStreamEvent) => {\n // First event of any kind means we're no longer just connecting\n setIsConnecting(false);\n switch (event.type) {\n case 'text':\n ensureAssistantBubble();\n appendTextToLast(event.text);\n break;\n case 'part':\n ensureAssistantBubble();\n appendPartToLast(event.part);\n break;\n case 'error':\n ensureAssistantBubble();\n appendPartToLast({ type: 'error', message: event.message });\n setError(event.message);\n break;\n case 'done': break;\n }\n },\n abort.signal\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(message);\n ensureAssistantBubble();\n appendPartToLast({ type: 'error', message });\n } finally {\n shouldNotifyRef.current = true;\n setIsLoading(false);\n setIsConnecting(false);\n }\n }, [adapter, context, historyLimit, appendTextToLast, appendPartToLast]);\n\n const sendMessage = useCallback(async () => {\n const trimmed = input.trim();\n if (!trimmed || isLoading) return;\n setInput('');\n await sendMessageCore(trimmed, messages);\n }, [input, isLoading, messages, sendMessageCore]);\n\n const sendMessageWithText = useCallback(async (text: string) => {\n if (!text.trim() || isLoading) return;\n await sendMessageCore(text, messages);\n }, [isLoading, messages, sendMessageCore]);\n\n const sendGreeting = useCallback(async (contextHint: string) => {\n if (isLoading) return;\n setError(null);\n setIsLoading(true);\n setIsConnecting(true);\n\n // Add only an assistant placeholder — no user bubble\n const assistantMessage: AiMessage = {\n id: nextId(),\n role: 'assistant',\n parts: [],\n createdAt: new Date(),\n };\n setMessages(prev => [...prev, assistantMessage]);\n\n abortRef.current?.abort();\n const abort = new AbortController();\n abortRef.current = abort;\n\n // Pass the hint as a system message so the adapter knows what to generate\n const syntheticContext: AiMessage = {\n id: nextId(),\n role: 'system',\n parts: [{ type: 'text', text: contextHint }],\n createdAt: new Date(),\n };\n\n try {\n const stream = adapter.sendMessage({ messages: serializeHistory([syntheticContext]), context });\n await consumeStream(\n stream,\n (event: AiStreamEvent) => {\n setIsConnecting(false);\n switch (event.type) {\n case 'text': appendTextToLast(event.text); break;\n case 'part': appendPartToLast(event.part); break;\n case 'error':\n appendPartToLast({ type: 'error', message: event.message });\n setError(event.message);\n break;\n case 'done': break;\n }\n },\n abort.signal\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(message);\n appendPartToLast({ type: 'error', message });\n } finally {\n shouldNotifyRef.current = true;\n setIsLoading(false);\n setIsConnecting(false);\n }\n }, [isLoading, adapter, context, appendTextToLast, appendPartToLast]);\n\n const stop = useCallback(() => {\n abortRef.current?.abort();\n setIsLoading(false);\n setIsConnecting(false);\n }, []);\n\n const reset = useCallback((nextMessages?: AiMessage[]) => {\n abortRef.current?.abort();\n shouldNotifyRef.current = true;\n setMessages(nextMessages ?? []);\n setInput('');\n setError(null);\n setIsLoading(false);\n setIsConnecting(false);\n }, []);\n\n // Marking the proposal resolved in state disables its card, so the same\n // proposal can never fire callbacks twice or survive persistence as actionable.\n const resolveProposal = useCallback((proposalId: string, resolved: 'confirmed' | 'cancelled') => {\n shouldNotifyRef.current = true;\n setMessages(prev => prev.map(msg => ({\n ...msg,\n parts: msg.parts.map(part =>\n isProposalPart(part) && part.proposal.id === proposalId\n ? { ...part, proposal: { ...part.proposal, resolved } }\n : part\n ),\n })));\n }, []);\n\n const confirmProposal = useCallback((proposalId: string, payload: unknown) => {\n resolveProposal(proposalId, 'confirmed');\n onProposalConfirm?.(proposalId, payload);\n }, [onProposalConfirm, resolveProposal]);\n\n const cancelProposal = useCallback((proposalId: string) => {\n resolveProposal(proposalId, 'cancelled');\n onProposalCancel?.(proposalId);\n }, [onProposalCancel, resolveProposal]);\n\n // Stable reference — callbacks are useCallback-stable, so this only changes\n // when actual state changes. Lets AiChatProvider memoize its context value.\n return useMemo(() => ({\n messages,\n input,\n setInput,\n sendMessage,\n sendMessageWithText,\n sendGreeting,\n stop,\n isLoading,\n isConnecting,\n error,\n reset,\n confirmProposal,\n cancelProposal\n }), [\n messages,\n input,\n sendMessage,\n sendMessageWithText,\n sendGreeting,\n stop,\n isLoading,\n isConnecting,\n error,\n reset,\n confirmProposal,\n cancelProposal\n ]);\n}\n","import type { JuneauLabels } from '../types';\n\nexport const juneauEn: JuneauLabels = {\n sidebarTitle: 'AI Assistant',\n clearConversation: 'Clear conversation',\n resetConversation: 'Reset conversation',\n minimizeSidebar: 'Minimize',\n expandSidebar: 'Expand',\n userLabel: 'You',\n inputPlaceholder: 'Ask a question… (Enter to send)',\n sendMessage: 'Send message',\n stopMessage: 'Stop',\n typingMessage: 'Assistant is typing',\n connectingMessage: 'Connecting…',\n emptyStateText: 'How can I help you today?',\n emptyStateHint: 'Try: \"Show me the data\" or \"Can you suggest something?\"',\n proposalConfirm: 'Confirm',\n proposalCancel: 'Cancel',\n proposalConfirmed: 'Confirmed',\n proposalCancelled: 'Cancelled',\n proposalExpired: 'No longer available',\n errorDismiss: 'Dismiss',\n actionAddFile: 'Add file',\n actionQuickActions: 'Quick actions',\n actionNew: 'New',\n actionHistory: 'History',\n actionRules: 'Rules',\n historyEmpty: 'No previous chats',\n historyDeleteChat: 'Delete chat',\n};\n","import { createContext, useContext } from 'react';\nimport type { JuneauLabels } from './types';\nimport { juneauEn } from './locales/en';\n\nexport const JuneauLabelsContext = createContext<JuneauLabels>(juneauEn);\n\n/**\n * Returns the active label set. Falls back to English defaults for any\n * key not provided by the consumer's `labels` prop on `JuneauProvider`.\n */\nexport function useLabels(): JuneauLabels {\n return useContext(JuneauLabelsContext);\n}\n","import type { CSSProperties, ReactNode } from 'react';\nimport '../../styles/tokens.css';\nimport { JuneauLabelsContext } from '../../i18n/context';\nimport { juneauEn } from '../../i18n/locales/en';\nimport type { JuneauLabels } from '../../i18n/types';\nimport styles from './JuneauProvider.module.css';\n\nexport type { JuneauLabels };\n\nexport type JuneauTheme = {\n colorPrimary?: string;\n colorPrimaryDark?: string;\n colorPrimaryLight?: string;\n colorPrimaryBorder?: string;\n colorAccent?: string;\n colorAccentDark?: string;\n colorAccentLight?: string;\n colorAccentBorder?: string;\n colorSurface?: string;\n colorSurfaceRaised?: string;\n colorSurfaceHover?: string;\n colorBorder?: string;\n colorBorderSubtle?: string;\n colorTextPrimary?: string;\n colorTextSecondary?: string;\n colorTextMuted?: string;\n colorTextFaint?: string;\n colorTextInverse?: string;\n colorAssistantAvatar?: string;\n colorErrorBg?: string;\n colorErrorBorder?: string;\n colorErrorText?: string;\n colorSuccessBg?: string;\n colorSuccessText?: string;\n colorWarningBg?: string;\n colorWarningText?: string;\n colorDangerBg?: string;\n colorDangerText?: string;\n radiusSm?: string;\n radiusMd?: string;\n radiusLg?: string;\n radiusFull?: string;\n fontSizeXs?: string;\n fontSizeSm?: string;\n fontSizeBase?: string;\n fontSizeMd?: string;\n fontSizeLg?: string;\n fontSizeXl?: string;\n fontSize2xl?: string;\n fontSize3xl?: string;\n /** Override the font family used across all Juneau components. */\n fontFamily?: string;\n /** Duration for all transitions, e.g. '0.2s'. */\n transitionFast?: string;\n};\n\ntype Props = {\n children: ReactNode;\n theme?: JuneauTheme;\n /**\n * Override any subset of UI strings. Unspecified keys fall back to English.\n * Use the exported `juneauCs` or `juneauEn` objects, or build your own from `JuneauLabels`.\n */\n labels?: Partial<JuneauLabels>;\n /**\n * Sets the sidebar title globally for every `AiSidebar` rendered inside this\n * provider. Equivalent to overriding `labels.sidebarTitle` but more\n * discoverable — no need to spread the whole labels object just to set a name.\n *\n * A `title` prop passed directly to `AiSidebar` still takes precedence.\n *\n * @example\n * <JuneauProvider defaultTitle=\"Tappeer AI\">…</JuneauProvider>\n */\n defaultTitle?: string;\n className?: string;\n style?: CSSProperties;\n};\n\nexport function JuneauProvider({ children, theme, labels, defaultTitle, className, style }: Props) {\n const resolvedLabels: JuneauLabels = {\n ...juneauEn,\n ...(defaultTitle ? { sidebarTitle: defaultTitle } : {}),\n ...labels,\n };\n\n const themeVars = theme ? buildThemeVars(theme) : undefined;\n\n return (\n <JuneauLabelsContext.Provider value={resolvedLabels}>\n <div\n className={[styles.root, className].filter(Boolean).join(' ')}\n style={{ ...themeVars, ...style }}\n >\n {children}\n </div>\n </JuneauLabelsContext.Provider>\n );\n}\n\nfunction buildThemeVars(theme: JuneauTheme): CSSProperties {\n const map: Record<string, string | undefined> = {\n '--juneau-color-primary': theme.colorPrimary,\n '--juneau-color-primary-dark': theme.colorPrimaryDark,\n '--juneau-color-primary-light': theme.colorPrimaryLight,\n '--juneau-color-primary-border': theme.colorPrimaryBorder,\n '--juneau-color-accent': theme.colorAccent,\n '--juneau-color-accent-dark': theme.colorAccentDark,\n '--juneau-color-accent-light': theme.colorAccentLight,\n '--juneau-color-accent-border': theme.colorAccentBorder,\n '--juneau-color-surface': theme.colorSurface,\n '--juneau-color-surface-raised': theme.colorSurfaceRaised,\n '--juneau-color-surface-hover': theme.colorSurfaceHover,\n '--juneau-color-border': theme.colorBorder,\n '--juneau-color-border-subtle': theme.colorBorderSubtle,\n '--juneau-color-text-primary': theme.colorTextPrimary,\n '--juneau-color-text-secondary': theme.colorTextSecondary,\n '--juneau-color-text-muted': theme.colorTextMuted,\n '--juneau-color-text-faint': theme.colorTextFaint,\n '--juneau-color-text-inverse': theme.colorTextInverse,\n '--juneau-color-assistant-avatar': theme.colorAssistantAvatar,\n '--juneau-color-error-bg': theme.colorErrorBg,\n '--juneau-color-error-border': theme.colorErrorBorder,\n '--juneau-color-error-text': theme.colorErrorText,\n '--juneau-color-success-bg': theme.colorSuccessBg,\n '--juneau-color-success-text': theme.colorSuccessText,\n '--juneau-color-warning-bg': theme.colorWarningBg,\n '--juneau-color-warning-text': theme.colorWarningText,\n '--juneau-color-danger-bg': theme.colorDangerBg,\n '--juneau-color-danger-text': theme.colorDangerText,\n '--juneau-radius-sm': theme.radiusSm,\n '--juneau-radius-md': theme.radiusMd,\n '--juneau-radius-lg': theme.radiusLg,\n '--juneau-radius-full': theme.radiusFull,\n '--juneau-font-size-xs': theme.fontSizeXs,\n '--juneau-font-size-sm': theme.fontSizeSm,\n '--juneau-font-size-base': theme.fontSizeBase,\n '--juneau-font-size-md': theme.fontSizeMd,\n '--juneau-font-size-lg': theme.fontSizeLg,\n '--juneau-font-size-xl': theme.fontSizeXl,\n '--juneau-font-size-2xl': theme.fontSize2xl,\n '--juneau-font-size-3xl': theme.fontSize3xl,\n '--juneau-font-family': theme.fontFamily,\n '--juneau-transition-fast': theme.transitionFast,\n };\n\n return Object.fromEntries(\n Object.entries(map).filter(([, v]) => v !== undefined)\n ) as CSSProperties;\n}\n","import { createContext, useContext } from 'react';\nimport type { UseAiChatReturn } from '../hooks/useAiChat';\n\nexport type AiChatContextValue = UseAiChatReturn & {\n /**\n * Update the context forwarded to every adapter.sendMessage call.\n * Call this on each page/view to tell the AI where the user is,\n * what tools are available, etc.\n *\n * Passing an object REPLACES the whole context. To merge with what's\n * already there (e.g. keep a sessionId while updating the page), use the\n * updater form:\n *\n * @example\n * setContext(prev => ({ ...prev, pageId: 'invoices' }));\n */\n setContext: (\n ctx:\n | Record<string, unknown>\n | ((prev: Record<string, unknown> | undefined) => Record<string, unknown>)\n ) => void;\n};\n\nexport const AiChatContext = createContext<AiChatContextValue | null>(null);\n\n/**\n * Returns the shared chat state from the nearest AiChatProvider.\n * Throws if called outside of one — fail fast is better than silent undefined.\n */\nexport function useAiChatContext(): AiChatContextValue {\n const ctx = useContext(AiChatContext);\n if (!ctx) {\n throw new Error(\n 'useAiChatContext must be used inside <AiChatProvider>. ' +\n 'Wrap your app (or layout) with <AiChatProvider adapter={...}>.'\n );\n }\n return ctx;\n}\n\n/**\n * Like {@link useAiChatContext}, but returns null outside a provider instead\n * of throwing. Use in components that render both inside and outside the chat.\n */\nexport function useAiChatContextSafe(): AiChatContextValue | null {\n return useContext(AiChatContext);\n}\n","import { useState, useCallback, useMemo, type ReactNode } from 'react';\nimport { useAiChat } from '../hooks/useAiChat';\nimport type { AiMessage, AiBackendAdapter } from '../core/types';\nimport { AiChatContext } from './AiChatContext';\n\ntype Props = {\n adapter: AiBackendAdapter;\n /** Initial context passed to the adapter. Update it per-page via setContext(). */\n context?: Record<string, unknown>;\n onProposalConfirm?: (proposalId: string, payload: unknown) => void;\n onProposalCancel?: (proposalId: string) => void;\n /** Restored conversation to start with — typically the output of `deserializeMessages`. */\n initialMessages?: AiMessage[];\n /** Max messages sent to the adapter per request. Rendering is never trimmed. */\n historyLimit?: number;\n /** Called when the conversation settles. Use to persist via `serializeForStorage`. */\n onMessagesChange?: (messages: AiMessage[]) => void;\n children: ReactNode;\n};\n\nexport function AiChatProvider({\n adapter,\n context: initialContext,\n onProposalConfirm,\n onProposalCancel,\n initialMessages,\n historyLimit,\n onMessagesChange,\n children,\n}: Props) {\n const [context, setContextState] = useState<Record<string, unknown> | undefined>(initialContext);\n\n // Object form replaces the whole context; updater form enables merging\n // without stale closures: setContext(prev => ({ ...prev, pageId: 'x' })).\n const setContext = useCallback((\n ctx:\n | Record<string, unknown>\n | ((prev: Record<string, unknown> | undefined) => Record<string, unknown>)\n ) => {\n if (typeof ctx === 'function') {\n setContextState(prev => ctx(prev));\n } else {\n setContextState(ctx);\n }\n }, []);\n\n const chat = useAiChat({\n adapter,\n context,\n onProposalConfirm,\n onProposalCancel,\n initialMessages,\n historyLimit,\n onMessagesChange,\n });\n\n // Memoized so consumers only re-render when chat state actually changes\n const value = useMemo(\n () => ({ ...chat, setContext }),\n [chat, setContext]\n );\n\n return (\n <AiChatContext.Provider value={value}>\n {children}\n </AiChatContext.Provider>\n );\n}\n","import type { JuneauLabels } from '../types';\n\nexport const juneauCs: JuneauLabels = {\n sidebarTitle: 'AI Asistent',\n clearConversation: 'Vymazat konverzaci',\n resetConversation: 'Resetovat konverzaci',\n minimizeSidebar: 'Minimalizovat',\n expandSidebar: 'Rozbalit',\n userLabel: 'Vy',\n inputPlaceholder: 'Zeptejte se na cokoliv… (Enter pro odeslání)',\n sendMessage: 'Odeslat zprávu',\n stopMessage: 'Zastavit',\n typingMessage: 'Asistent píše',\n connectingMessage: 'Připojování…',\n emptyStateText: 'Jak vám mohu dnes pomoci?',\n emptyStateHint: 'Zkuste: „Ukáž mi data\" nebo „Máš nějaký návrh?\"',\n proposalConfirm: 'Potvrdit',\n proposalCancel: 'Zrušit',\n proposalConfirmed: 'Potvrzeno',\n proposalCancelled: 'Zrušeno',\n proposalExpired: 'Již není k dispozici',\n errorDismiss: 'Zavřít',\n actionAddFile: 'Přidat soubor',\n actionQuickActions: 'Rychlé akce',\n actionNew: 'Nový',\n actionHistory: 'Historie',\n actionRules: 'Pravidla',\n historyEmpty: 'Žádné předchozí konverzace',\n historyDeleteChat: 'Smazat konverzaci',\n};\n","import type { CSSProperties } from 'react';\n\ntype IconProps = {\n className?: string;\n style?: CSSProperties;\n 'aria-hidden'?: boolean | 'true' | 'false';\n};\n\nexport function IconWandMagicSparkles({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 640 512\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n className={className}\n style={style}\n aria-hidden={ariaHidden}\n >\n {/* Font Awesome \"crow\" solid (FA 6 free) — viewBox 0 0 640 512 */}\n <path d=\"M456 0c-48.6 0-88 39.4-88 88l0 29.2L12.5 390.6c-14 10.8-16.6 30.9-5.9 44.9s30.9 16.6 44.9 5.9L126.1 384l133.1 0 46.6 113.1c5 12.3 19.1 18.1 31.3 13.1s18.1-19.1 13.1-31.3L311.1 384l40.9 0c1.1 0 2.1 0 3.2 0l46.6 113.2c5 12.3 19.1 18.1 31.3 13.1s18.1-19.1 13.1-31.3l-42-102C484.9 354.1 544 280 544 192l0-64 0-8 80.5-20.1c8.6-2.1 13.8-10.8 11.6-19.4C629 52 603.4 32 574 32l-50.1 0C507.7 12.5 483.3 0 456 0zm0 64a24 24 0 1 1 0 48 24 24 0 1 1 0-48z\" />\n </svg>\n );\n}\n\nexport function IconPaperPlane({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 512 512\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n className={className}\n style={style}\n aria-hidden={ariaHidden}\n >\n {/* FA \"paper-plane\" solid */}\n <path d=\"M498.1 5.6c10.1 7 15.4 19.1 13.5 31.2l-64 416c-1.5 9.7-7.4 18.2-16 23s-18.9 5.4-28 1.6L284 427.7l-68.5 74.1c-8.9 9.7-22.9 12.9-35.2 8.1S160 493.2 160 480V396.4c0-4 1.5-7.8 4.2-10.8L331.8 202.8c5.8-6.3 5.6-16-.4-22s-15.7-6.4-22-.7L106 360.8 17.7 316.6C7.1 311.3 .3 300.7 0 288.9s6.2-22.8 16.4-28.7l448-256c10.7-6.1 23.9-5.5 34 1.4z\" />\n </svg>\n );\n}\n\nexport function IconPaperclip({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 448 512\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n className={className}\n style={style}\n aria-hidden={ariaHidden}\n >\n {/* FA \"paperclip\" solid */}\n <path d=\"M364.2 83.8c-24.4-24.4-64-24.4-88.4 0l-184 184c-42.1 42.1-42.1 110.3 0 152.4s110.3 42.1 152.4 0l152-152c10.9-10.9 28.7-10.9 39.6 0s10.9 28.7 0 39.6l-152 152c-64 64-167.6 64-231.6 0s-64-167.6 0-231.6l184-184c46.3-46.3 121.3-46.3 167.6 0s46.3 121.3 0 167.6l-176 176c-28.6 28.6-75 28.6-103.6 0s-28.6-75 0-103.6l144-144c10.9-10.9 28.7-10.9 39.6 0s10.9 28.7 0 39.6l-144 144c-6.7 6.7-6.7 17.7 0 24.4s17.7 6.7 24.4 0l176-176c24.4-24.4 24.4-64 0-88.4z\" />\n </svg>\n );\n}\n\nexport function IconBolt({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 448 512\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n className={className}\n style={style}\n aria-hidden={ariaHidden}\n >\n {/* FA \"bolt\" solid */}\n <path d=\"M349.4 44.6c5.9-13.7 1.5-29.7-10.6-38.5s-28.6-8-39.9 1.8l-256 224c-10 8.8-13.6 22.9-8.9 35.3S50.7 288 64 288l111.5 0L98.6 467.4c-5.9 13.7-1.5 29.7 10.6 38.5s28.6 8 39.9-1.8l256-224c10-8.8 13.6-22.9 8.9-35.3s-16.6-20.7-30-20.7l-111.5 0L349.4 44.6z\" />\n </svg>\n );\n}\n\nexport function IconPlus({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 448 512\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n className={className}\n style={style}\n aria-hidden={ariaHidden}\n >\n {/* FA \"plus\" solid */}\n <path d=\"M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 144L48 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l144 0 0 144c0 17.7 14.3 32 32 32s32-14.3 32-32l0-144 144 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-144 0 0-144z\" />\n </svg>\n );\n}\n\nexport function IconClockRotateLeft({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 512 512\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n className={className}\n style={style}\n aria-hidden={ariaHidden}\n >\n {/* FA \"clock-rotate-left\" / \"history\" solid */}\n <path d=\"M75 75L41 41C25.9 25.9 0 36.6 0 57.9L0 168c0 13.3 10.7 24 24 24l110.1 0c21.4 0 32.1-25.9 17-41l-31.8-31.8C143.9 83.5 196.2 64 252.6 64C370.8 64 464 157.8 464 276c0 77.5-40.8 145.4-102 182.9c-15.1 9.2-19.9 29-10.7 44.1s29 19.9 44.1 10.7C471 467.5 528 378.4 528 276C528 124.1 404.5 0 252.6 0C186 0 125.3 26.4 80 70.2L75 75zM256 152c-13.3 0-24 10.7-24 24l0 104c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65 0-94.1c0-13.3-10.7-24-24-24z\" />\n </svg>\n );\n}\n\nexport function IconScroll({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 576 512\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n className={className}\n style={style}\n aria-hidden={ariaHidden}\n >\n {/* FA \"scroll\" solid */}\n <path d=\"M0 80C0 53.5 21.5 32 48 32l96 0c26.5 0 48 21.5 48 48l0 16 192 0 0-16c0-26.5 21.5-48 48-48l96 0c26.5 0 48 21.5 48 48l0 96c0 26.5-21.5 48-48 48l-26.6 0c-25.8 50.9-72.7 88.5-129.4 99.8L384 416l32 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-256 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l32 0 0-72.2C135.3 332.5 88.4 294.9 62.6 244L48 244c-26.5 0-48-21.5-48-48L0 80zM128 240c0 70.7 57.3 128 128 128s128-57.3 128-128l0-128L128 112l0 128zM512 176l0-64-64 0 0 64-48 0 0 16c0 8.8-.7 17.4-2 25.8c3.3 .1 6.6 .2 9.9 .2l56 0c26.5 0 48-21.5 48-48l0-64zM48 176c0 26.5 21.5 48 48 48l56 0c3.4 0 6.7-.1 9.9-.2c-1.3-8.4-2-17-2-25.8l0-16-48 0 0-64-64 0 0 58z\" />\n </svg>\n );\n}\n\nexport function IconWindowMinimize({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 512 512\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n className={className}\n style={style}\n aria-hidden={ariaHidden}\n >\n {/* Font Awesome \"window-minimize\" solid (FA 6 free) */}\n <path d=\"M32 416c-17.7 0-32 14.3-32 32s14.3 32 32 32l448 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 416z\" />\n </svg>\n );\n}\n\nexport function IconWindowRestore({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 512 512\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n className={className}\n style={style}\n aria-hidden={ariaHidden}\n >\n {/* Font Awesome \"window-restore\" solid (FA 6 free) */}\n <path d=\"M432 64L208 64c-8.8 0-16 7.2-16 16l0 16-64 0 0-16c0-44.2 35.8-80 80-80L432 0c44.2 0 80 35.8 80 80l0 224c0 44.2-35.8 80-80 80l-16 0 0-64 16 0c8.8 0 16-7.2 16-16l0-224c0-8.8-7.2-16-16-16zM0 192c0-35.3 28.7-64 64-64l256 0c35.3 0 64 28.7 64 64l0 256c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64L0 192zm64 32c0 17.7 14.3 32 32 32l192 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L96 192c-17.7 0-32 14.3-32 32z\" />\n </svg>\n );\n}\n\nexport function IconArrowRotateLeft({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 512 512\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n className={className}\n style={style}\n aria-hidden={ariaHidden}\n >\n {/* FA \"arrow-rotate-left\" solid */}\n <path d=\"M125.7 160H176c17.7 0 32 14.3 32 32s-14.3 32-32 32H48c-17.7 0-32-14.3-32-32V64c0-17.7 14.3-32 32-32s32 14.3 32 32v51.2L97.6 97.6c87.5-87.5 229.3-87.5 316.8 0s87.5 229.3 0 316.8s-229.3 87.5-316.8 0c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0c62.5 62.5 163.8 62.5 226.3 0s62.5-163.8 0-226.3s-163.8-62.5-226.3 0L125.7 160z\" />\n </svg>\n );\n}\n\nexport function IconWarning({ className, style, 'aria-hidden': ariaHidden = true }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n className={className}\n style={style}\n aria-hidden={ariaHidden}\n >\n <path fillRule=\"evenodd\" d=\"M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z\" clipRule=\"evenodd\" />\n </svg>\n );\n}\n","import type { AiTablePart as AiTablePartType } from '../../core/types';\nimport styles from './AiTablePart.module.css';\n\ntype Props = {\n part: AiTablePartType;\n};\n\nexport function AiTablePart({ part }: Props) {\n return (\n <div className={styles.wrapper} data-juneau=\"table-part\">\n <table className={styles.table}>\n <thead>\n <tr>\n {part.columns.map(col => (\n <th key={col} className={styles.th}>{col}</th>\n ))}\n </tr>\n </thead>\n <tbody>\n {part.rows.map((row, i) => (\n <tr key={i} className={styles.tr}>\n {part.columns.map(col => (\n <td key={col} className={styles.td}>\n {String(row[col] ?? '')}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n","import type { AiProposalPart } from '../../core/types';\nimport { useLabels } from '../../i18n/context';\nimport styles from './AiProposalCard.module.css';\n\ntype Props = {\n part: AiProposalPart;\n onConfirm: (proposalId: string, payload: unknown) => void;\n onCancel: (proposalId: string) => void;\n};\n\nexport function AiProposalCard({ part, onConfirm, onCancel }: Props) {\n const labels = useLabels();\n const { proposal } = part;\n\n const resolvedLabel =\n proposal.resolved === 'confirmed' ? labels.proposalConfirmed\n : proposal.resolved === 'cancelled' ? labels.proposalCancelled\n : proposal.resolved === 'expired' ? labels.proposalExpired\n : null;\n\n return (\n <div\n className={proposal.resolved ? `${styles.card} ${styles.cardResolved}` : styles.card}\n data-juneau=\"proposal-card\"\n >\n <div className={styles.header}>\n <svg className={styles.icon} viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M10 1a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 1zM5.05 3.05a.75.75 0 011.06 1.06l-1.06 1.06a.75.75 0 11-1.06-1.06l1.06-1.06zm9.9 0a.75.75 0 010 1.06l-1.06 1.06a.75.75 0 11-1.06-1.06l1.06-1.06a.75.75 0 011.06 0zM10 6a4 4 0 100 8 4 4 0 000-8zm-9 4a.75.75 0 01.75-.75h1.5a.75.75 0 010 1.5h-1.5A.75.75 0 011 10zm15.75-.75a.75.75 0 000 1.5h1.5a.75.75 0 000-1.5h-1.5zM4.11 14.89a.75.75 0 010 1.06l-1.06 1.06a.75.75 0 11-1.06-1.06l1.06-1.06a.75.75 0 011.06 0zm11.84 1.06a.75.75 0 10-1.06-1.06l-1.06 1.06a.75.75 0 101.06 1.06l1.06-1.06zM10 17.25a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5a.75.75 0 01.75-.75z\" />\n </svg>\n <span className={styles.title}>{proposal.title}</span>\n </div>\n {proposal.description && (\n <p className={styles.description}>{proposal.description}</p>\n )}\n {resolvedLabel ? (\n <span className={styles.resolvedBadge}>{resolvedLabel}</span>\n ) : (\n <div className={styles.actions}>\n <button\n className={styles.confirm}\n onClick={() => onConfirm(proposal.id, proposal.payload)}\n >\n {proposal.confirmLabel ?? labels.proposalConfirm}\n </button>\n <button\n className={styles.cancel}\n onClick={() => onCancel(proposal.id)}\n >\n {proposal.cancelLabel ?? labels.proposalCancel}\n </button>\n </div>\n )}\n </div>\n );\n}\n","import type { AiActivityPart as AiActivityPartType } from '../../core/types';\nimport styles from './AiActivityPart.module.css';\n\ntype Props = {\n part: AiActivityPartType;\n};\n\nexport function AiActivityPart({ part }: Props) {\n return (\n <div className={styles.activity} data-status={part.status} data-juneau=\"activity-part\">\n <span className={styles.indicator} aria-hidden=\"true\" />\n\n <div className={styles.content}>\n <div className={styles.title}>{part.title}</div>\n\n {part.description && (\n <div className={styles.description}>{part.description}</div>\n )}\n </div>\n </div>\n );\n}\n","import type { AiEntity, AiEntityBadgeTone, AiEntityPart } from '../../core/types';\nimport styles from './AiEntityCard.module.css';\n\ntype Props = {\n part: AiEntityPart;\n /** Optional click handler — the card becomes interactive when provided */\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\n};\n\nconst badgeClass: Record<AiEntityBadgeTone, string> = {\n success: styles.badgeSuccess,\n warning: styles.badgeWarning,\n danger: styles.badgeDanger,\n neutral: styles.badgeNeutral,\n};\n\nexport function AiEntityCard({ part, onEntityClick }: Props) {\n const { entity, entityType } = part;\n const clickable = onEntityClick !== undefined;\n\n const body = (\n <>\n <div className={styles.header}>\n <span className={styles.title}>{entity.title}</span>\n {entity.subtitle && <span className={styles.subtitle}>{entity.subtitle}</span>}\n </div>\n {entity.fields && entity.fields.length > 0 && (\n <dl className={styles.fields}>\n {entity.fields.map((field, i) => (\n <div key={i} className={styles.fieldRow}>\n <dt className={styles.fieldLabel}>{field.label}</dt>\n <dd className={styles.fieldValue}>\n {field.badge ? (\n <span className={`${styles.badge} ${badgeClass[field.badge]}`}>{field.value}</span>\n ) : (\n field.value\n )}\n </dd>\n </div>\n ))}\n </dl>\n )}\n </>\n );\n\n if (clickable) {\n return (\n <button\n type='button'\n className={`${styles.card} ${styles.cardClickable}`}\n onClick={() => onEntityClick(entity, entityType)}\n data-juneau=\"entity-card\"\n >\n {body}\n </button>\n );\n }\n\n return <div className={styles.card} data-juneau=\"entity-card\">{body}</div>;\n}\n","import type { AiEntity, AiEntityListPart as AiEntityListPartType } from '../../core/types';\nimport { AiEntityCard } from './AiEntityCard';\nimport styles from './AiEntityListPart.module.css';\n\ntype Props = {\n part: AiEntityListPartType;\n /** Optional click handler — cards become interactive when provided */\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\n};\n\nexport function AiEntityListPart({ part, onEntityClick }: Props) {\n return (\n <div className={styles.list} data-juneau=\"entity-list-part\">\n {part.title && <span className={styles.listTitle}>{part.title}</span>}\n {part.entities.map((entity, i) => (\n <AiEntityCard\n key={entity.id ?? i}\n part={{ type: 'entity', entity, entityType: part.entityType }}\n onEntityClick={onEntityClick}\n />\n ))}\n </div>\n );\n}\n","import type { ReactNode } from 'react';\nimport Markdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport type {\n AiEntity,\n AiMessagePart,\n AiTextPart,\n AiTablePart as AiTablePartType,\n AiProposalPart,\n AiActivityPart as AiActivityPartType,\n AiEntityPart as AiEntityPartType,\n AiEntityListPart as AiEntityListPartType,\n AiErrorPart,\n} from '../../core/types';\nimport { IconWarning } from '../icons';\nimport { AiTablePart } from './AiTablePart';\nimport { AiProposalCard } from './AiProposalCard';\nimport { AiActivityPart } from './AiActivityPart';\nimport { AiEntityCard } from './AiEntityCard';\nimport { AiEntityListPart } from './AiEntityListPart';\nimport styles from './AiMessagePartRenderer.module.css';\n\n/**\n * Consumer escape hatch for rendering custom part types (or overriding\n * built-in ones). Receives the raw part object with no narrowing or\n * validation applied — the consumer owns all type assertions.\n * Return null/undefined to fall through to the built-in renderers.\n */\nexport type RenderPartFn = (part: AiMessagePart) => ReactNode | null | undefined;\n\ntype Props = {\n part: AiMessagePart;\n onProposalConfirm: (proposalId: string, payload: unknown) => void;\n onProposalCancel: (proposalId: string) => void;\n /** Makes entity cards clickable — receives the entity and its optional entityType. */\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\n /** Called before the built-in switch — a non-nullish return value wins. */\n renderPart?: RenderPartFn;\n};\n\nexport function AiMessagePartRenderer({ part, onProposalConfirm, onProposalCancel, onEntityClick, renderPart }: Props) {\n // Consumer renderer takes priority — lets it override built-ins too\n if (renderPart) {\n const custom = renderPart(part);\n if (custom !== null && custom !== undefined) {\n return <>{custom}</>;\n }\n }\n\n // AiCustomPart's `type: string` absorbs literal narrowing, so the built-in\n // cases cast explicitly. The shapes are guaranteed by the wire protocol.\n switch (part.type) {\n case 'text':\n return (\n <div className={styles.markdown}>\n {/* react-markdown never uses dangerouslySetInnerHTML — safe against XSS by default */}\n <Markdown remarkPlugins={[remarkGfm]}>{(part as AiTextPart).text}</Markdown>\n </div>\n );\n case 'table':\n return <AiTablePart part={part as AiTablePartType} />;\n case 'activity':\n return <AiActivityPart part={part as AiActivityPartType} />;\n case 'proposal':\n return (\n <AiProposalCard\n part={part as AiProposalPart}\n onConfirm={onProposalConfirm}\n onCancel={onProposalCancel}\n />\n );\n case 'entity':\n return <AiEntityCard part={part as AiEntityPartType} onEntityClick={onEntityClick} />;\n case 'entity-list':\n return <AiEntityListPart part={part as AiEntityListPartType} onEntityClick={onEntityClick} />;\n case 'error':\n return (\n <span className={styles.errorText}>\n <IconWarning className={styles.errorIcon} />\n {(part as AiErrorPart).message}\n </span>\n );\n default:\n // Unknown custom part with no renderPart handler. Invisible in\n // production; a visible outline in dev so it's never a silent mystery.\n // Structural globalThis access: `process` may not exist in browsers and\n // the lib compiles without @types/node.\n const nodeEnv = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env?.NODE_ENV;\n if (nodeEnv !== 'production') {\n return (\n <div className={styles.unknownPart}>\n Unhandled part type: <code>{part.type}</code> — pass a{' '}\n <code>renderPart</code> prop to render it.\n </div>\n );\n }\n return null;\n }\n}\n","import type { ReactNode } from 'react';\nimport { IconWandMagicSparkles } from '../icons';\nimport type { AiEntity, AiMessage, AiMessagePart } from '../../core/types';\nimport { useLabels } from '../../i18n/context';\nimport { AiMessagePartRenderer } from '../parts/AiMessagePartRenderer';\nimport type { RenderPartFn } from '../parts/AiMessagePartRenderer';\nimport styles from './AiMessageBubble.module.css';\n\ntype Props = {\n message: AiMessage;\n onProposalConfirm: (proposalId: string, payload: unknown) => void;\n onProposalCancel: (proposalId: string) => void;\n /** Override the assistant avatar icon. Pass any ReactNode — an SVG, img, or component. Defaults to a brain icon. */\n assistantIcon?: ReactNode;\n /** Makes entity cards clickable — forwarded to every AiMessagePartRenderer. */\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\n /** Custom part renderer — forwarded to every AiMessagePartRenderer. */\n renderPart?: RenderPartFn;\n};\n\n/** Part types that read as prose and stay inside the padded chat bubble. */\nconst INLINE_PART_TYPES = new Set(['text', 'error', 'activity']);\n\n/** Cards (tables, entities, proposals, custom parts) render full-width outside the bubble. */\nfunction isCardPart(part: AiMessagePart): boolean {\n return !INLINE_PART_TYPES.has(part.type);\n}\n\ntype Segment = { card: boolean; parts: { part: AiMessagePart; index: number }[] };\n\n/** Groups consecutive parts so prose runs share one bubble and each card stands alone. */\nfunction toSegments(parts: AiMessagePart[]): Segment[] {\n const segments: Segment[] = [];\n parts.forEach((part, index) => {\n const card = isCardPart(part);\n const last = segments[segments.length - 1];\n // Each card is its own segment so it gets full width and its own spacing.\n if (last && !card && !last.card) {\n last.parts.push({ part, index });\n return;\n }\n segments.push({ card, parts: [{ part, index }] });\n });\n return segments;\n}\n\nexport function AiMessageBubble({ message, onProposalConfirm, onProposalCancel, onEntityClick, assistantIcon, renderPart }: Props) {\n const labels = useLabels();\n const isUser = message.role === 'user';\n\n const renderOne = (part: AiMessagePart, index: number) => (\n <AiMessagePartRenderer\n key={index}\n part={part}\n onProposalConfirm={onProposalConfirm}\n onProposalCancel={onProposalCancel}\n onEntityClick={onEntityClick}\n renderPart={renderPart}\n />\n );\n\n // Plain conversational messages keep the classic single-bubble layout untouched —\n // only messages carrying a card opt into the full-width column below.\n const hasCard = message.parts.some(isCardPart);\n\n return (\n <div\n className={`${styles.wrapper} ${isUser ? styles.user : styles.assistant}`}\n data-juneau=\"message\"\n data-juneau-role={message.role}\n >\n {!isUser && (\n <div className={styles.avatar} aria-hidden=\"true\" data-juneau=\"assistant-avatar\">\n {assistantIcon ?? <IconWandMagicSparkles />}\n </div>\n )}\n {hasCard ? (\n <div className={styles.content}>\n {toSegments(message.parts).map((segment, i) => (\n <div\n key={i}\n className={segment.card ? styles.card : styles.bubble}\n data-juneau-segment={segment.card ? 'card' : 'bubble'}\n >\n {segment.parts.map(({ part, index }) => renderOne(part, index))}\n </div>\n ))}\n </div>\n ) : (\n <div className={styles.bubble} data-juneau-segment=\"bubble\">\n {message.parts.map((part, i) => renderOne(part, i))}\n {message.parts.length === 0 && <span className={styles.empty} />}\n </div>\n )}\n {isUser && <div className={styles.avatar}>{labels.userLabel}</div>}\n </div>\n );\n}\n","import { useLabels } from '../../i18n/context';\nimport styles from './AiTypingIndicator.module.css';\n\ntype Props = {\n /** When true, shows a \"Connecting…\" label instead of just the dots. */\n connecting?: boolean;\n};\n\nexport function AiTypingIndicator({ connecting = false }: Props) {\n const labels = useLabels();\n\n return (\n <div\n className={styles.wrapper}\n aria-label={connecting ? labels.connectingMessage : labels.typingMessage}\n data-juneau=\"typing-indicator\"\n >\n <span className={styles.dot} />\n <span className={styles.dot} />\n <span className={styles.dot} />\n {connecting && (\n <span className={styles.connectingLabel}>{labels.connectingMessage}</span>\n )}\n </div>\n );\n}\n","import { useEffect, useRef } from 'react';\nimport type { ReactNode } from 'react';\nimport type { AiEntity, AiMessage } from '../../core/types';\nimport { useLabels } from '../../i18n/context';\nimport { AiMessageBubble } from '../AiMessageBubble/AiMessageBubble';\nimport { AiTypingIndicator } from '../AiTypingIndicator/AiTypingIndicator';\nimport type { RenderPartFn } from '../parts/AiMessagePartRenderer';\nimport styles from './AiMessageList.module.css';\n\ntype Props = {\n messages: AiMessage[];\n isLoading: boolean;\n /** True while waiting for the first token — shows a \"connecting\" label inside the typing indicator. */\n isConnecting: boolean;\n onProposalConfirm: (proposalId: string, payload: unknown) => void;\n onProposalCancel: (proposalId: string) => void;\n /** Override the assistant avatar icon. Forwarded to every AiMessageBubble. */\n assistantIcon?: ReactNode;\n /** Makes entity cards clickable — forwarded to every AiMessageBubble. */\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\n /** Custom part renderer — forwarded to every AiMessageBubble. */\n renderPart?: RenderPartFn;\n /**\n * Rendered instead of the default empty-state text when there are no messages.\n * Use it for a rich \"get started\" hero — headline, suggestion chips, anything.\n */\n emptyState?: ReactNode;\n};\n\nexport function AiMessageList({ messages, isLoading, isConnecting, onProposalConfirm, onProposalCancel, onEntityClick, assistantIcon, renderPart, emptyState }: Props) {\n const labels = useLabels();\n const bottomRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, [messages, isLoading]);\n\n return (\n <div className={styles.list} data-juneau=\"message-list\">\n {messages.length === 0 &&\n (emptyState ?? (\n <div className={styles.empty} data-juneau=\"empty-state\">\n <p>{labels.emptyStateText}</p>\n <p className={styles.hint}>\n <em>{labels.emptyStateHint}</em>\n </p>\n </div>\n ))}\n {messages.map(message => (\n <AiMessageBubble\n key={message.id}\n message={message}\n onProposalConfirm={onProposalConfirm}\n onProposalCancel={onProposalCancel}\n onEntityClick={onEntityClick}\n assistantIcon={assistantIcon}\n renderPart={renderPart}\n />\n ))}\n {isLoading && (\n <div className={styles.typing}>\n <AiTypingIndicator connecting={isConnecting} />\n </div>\n )}\n <div ref={bottomRef} />\n </div>\n );\n}\n","import type { KeyboardEvent, ReactNode } from 'react';\nimport { useEffect, useRef } from 'react';\nimport {\n IconPaperPlane,\n IconPaperclip,\n IconBolt,\n IconPlus,\n IconClockRotateLeft,\n IconScroll,\n} from '../icons';\nimport { useLabels } from '../../i18n/context';\nimport styles from './AiInput.module.css';\n\nexport type AiInputAction = {\n /** Icon rendered inside the button. */\n icon: ReactNode;\n /** Visible label and aria-label for the button. */\n label: string;\n onClick?: () => void;\n};\n\ntype Props = {\n value: string;\n onChange: (value: string) => void;\n onSend: () => void;\n /** When provided, the send button becomes a stop button while isLoading is true. */\n onStop?: () => void;\n isLoading: boolean;\n /** Overrides the `inputPlaceholder` label for this specific instance. */\n placeholder?: string;\n /**\n * Toolbar action buttons rendered left of the send button.\n * Pass an empty array to hide the toolbar entirely.\n * Defaults to five built-in actions (attach, quick actions, new, history, rules).\n */\n actions?: AiInputAction[];\n /** Override the send button icon. Defaults to a paper-plane icon. */\n sendIcon?: ReactNode;\n};\n\nexport function AiInput({ value, onChange, onSend, onStop, isLoading, placeholder, actions, sendIcon }: Props) {\n const labels = useLabels();\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const wasLoadingRef = useRef(false);\n\n // Restore focus when streaming finishes. The textarea stays enabled during\n // streaming so the user can keep typing, but if focus was lost anyway\n // (e.g. the user clicked the stop button), give it back.\n useEffect(() => {\n if (wasLoadingRef.current && !isLoading) {\n textareaRef.current?.focus();\n }\n wasLoadingRef.current = isLoading;\n }, [isLoading]);\n\n const defaultActions: AiInputAction[] = [\n { icon: <IconPaperclip />, label: labels.actionAddFile },\n { icon: <IconBolt />, label: labels.actionQuickActions },\n { icon: <IconPlus />, label: labels.actionNew },\n { icon: <IconClockRotateLeft />, label: labels.actionHistory },\n { icon: <IconScroll />, label: labels.actionRules },\n ];\n\n const resolvedActions = actions ?? defaultActions;\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n // Typing stays enabled during streaming, but Enter must not send —\n // useAiChat also guards this, this is just belt and braces.\n if (!isLoading) onSend();\n }\n };\n\n return (\n <div className={styles.wrapper} data-juneau=\"input\">\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n data-juneau=\"input-textarea\"\n value={value}\n onChange={e => onChange(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder ?? labels.inputPlaceholder}\n rows={3}\n aria-label={labels.sendMessage}\n />\n\n <div className={styles.toolbar}>\n {resolvedActions.length > 0 && (\n <div className={styles.actions}>\n {resolvedActions.map((action, i) => (\n <button\n key={i}\n className={styles.actionBtn}\n type=\"button\"\n disabled={isLoading}\n aria-label={action.label}\n onClick={action.onClick}\n >\n {action.icon}\n <span>{action.label}</span>\n </button>\n ))}\n </div>\n )}\n\n {isLoading && onStop ? (\n <button\n className={styles.stopBtn}\n onClick={onStop}\n aria-label={labels.stopMessage}\n type=\"button\"\n data-juneau=\"input-stop\"\n >\n <svg className={styles.stopIcon} viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <rect x=\"6\" y=\"6\" width=\"12\" height=\"12\" rx=\"2\" />\n </svg>\n <span>{labels.stopMessage}</span>\n </button>\n ) : (\n <button\n className={styles.sendBtn}\n onClick={onSend}\n disabled={isLoading || !value.trim()}\n aria-label={labels.sendMessage}\n type=\"button\"\n data-juneau=\"input-send\"\n >\n {isLoading ? (\n <svg className={styles.spinnerIcon} viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeDasharray=\"32\" strokeDashoffset=\"12\" />\n </svg>\n ) : (\n sendIcon ?? <IconPaperPlane />\n )}\n <span>{labels.sendMessage}</span>\n </button>\n )}\n </div>\n </div>\n );\n}\n","import { useLabels } from '../../i18n/context';\nimport styles from './AiError.module.css';\n\ntype Props = {\n message: string;\n onDismiss?: () => void;\n};\n\nexport function AiError({ message, onDismiss }: Props) {\n const labels = useLabels();\n\n return (\n <div className={styles.wrapper} role=\"alert\" data-juneau=\"error\">\n <svg className={styles.icon} viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fillRule=\"evenodd\" d=\"M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z\" clipRule=\"evenodd\" />\n </svg>\n <span className={styles.message}>{message}</span>\n {onDismiss && (\n <button className={styles.dismiss} onClick={onDismiss} aria-label={labels.errorDismiss}>\n <svg viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z\" />\n </svg>\n </button>\n )}\n </div>\n );\n}\n","import type { CSSProperties, ReactNode } from 'react';\nimport type { AiEntity, AiMessage } from '../../core/types';\nimport type { AiInputAction } from '../AiInput/AiInput';\nimport { AiMessageList } from '../AiMessageList/AiMessageList';\nimport { AiInput } from '../AiInput/AiInput';\nimport { AiError } from '../AiError/AiError';\nimport type { RenderPartFn } from '../parts/AiMessagePartRenderer';\nimport styles from './AiChat.module.css';\n\ntype Props = {\n messages: AiMessage[];\n input: string;\n isLoading: boolean;\n isConnecting: boolean;\n error: string | null;\n onInputChange: (value: string) => void;\n onSend: () => void;\n /** Called when the user cancels the in-flight stream. Shown as a stop button while isLoading. */\n onStop?: () => void;\n onProposalConfirm: (proposalId: string, payload: unknown) => void;\n onProposalCancel: (proposalId: string) => void;\n /** Makes entity cards clickable — receives the entity and its optional entityType. */\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\n placeholder?: string;\n /** Override the assistant avatar icon. Forwarded to every message bubble. */\n assistantIcon?: ReactNode;\n /**\n * Toolbar action buttons rendered left of the send button.\n * Pass an empty array to hide the toolbar entirely.\n * Defaults to five built-in actions (attach, quick actions, new, history, rules).\n */\n actions?: AiInputAction[];\n /** Override the send button icon. Defaults to a paper-plane icon. */\n sendIcon?: ReactNode;\n /**\n * Custom part renderer — called before the built-in renderers for every\n * message part. Return a ReactNode to render it, or null/undefined to fall\n * through to the built-ins. Enables custom part types like invoice cards.\n */\n renderPart?: RenderPartFn;\n /**\n * Rendered instead of the default empty-state text when there are no messages.\n * Use it for a rich \"get started\" hero — headline, suggestion chips, anything.\n */\n emptyState?: ReactNode;\n /**\n * Consumer content rendered between the message list / error banner and the\n * input, e.g. a feedback prompt. When omitted nothing renders — not even the\n * wrapper — so the default layout is unaffected.\n */\n aboveInput?: ReactNode;\n /**\n * While there are no messages, centre the empty state and the input in the\n * chat instead of pinning the input to the bottom. The first message restores\n * the default layout.\n */\n centerInputWhenEmpty?: boolean;\n /** Content below the input in the centred empty layout, e.g. suggestions. */\n belowInput?: ReactNode;\n className?: string;\n style?: CSSProperties;\n};\n\n/**\n * Presentational chat body — message list, input bar, and error banner.\n * Contains no state or hooks. The parent is responsible for calling useAiChat\n * and passing the results here.\n *\n * Used by AiSidebar (inside the sidebar chrome) and directly in dashboard\n * or any other layout where you want chat without the sidebar wrapper.\n */\nexport function AiChat({\n messages,\n input,\n isLoading,\n isConnecting,\n error,\n onInputChange,\n onSend,\n onStop,\n onProposalConfirm,\n onProposalCancel,\n onEntityClick,\n placeholder,\n assistantIcon,\n actions,\n sendIcon,\n renderPart,\n emptyState,\n aboveInput,\n centerInputWhenEmpty = false,\n belowInput,\n className,\n style,\n}: Props) {\n const errorBanner = error && <AiError message={error} />;\n const aboveInputSlot = aboveInput != null && (\n <div className={styles.aboveInput} data-juneau=\"above-input\" data-juneau-above-input=\"\">\n {aboveInput}\n </div>\n );\n const inputBar = (\n <AiInput\n value={input}\n onChange={onInputChange}\n onSend={onSend}\n onStop={onStop}\n isLoading={isLoading}\n placeholder={placeholder}\n actions={actions}\n sendIcon={sendIcon}\n />\n );\n\n if (centerInputWhenEmpty && messages.length === 0) {\n return (\n <div\n className={[styles.chat, className].filter(Boolean).join(' ')}\n style={style}\n data-juneau=\"chat\"\n >\n <div className={styles.start} data-juneau=\"chat-start\">\n <div className={styles.startColumn}>\n {emptyState ?? (\n <AiMessageList\n messages={messages}\n isLoading={isLoading}\n isConnecting={isConnecting}\n onProposalConfirm={onProposalConfirm}\n onProposalCancel={onProposalCancel}\n />\n )}\n {errorBanner}\n {aboveInputSlot}\n {inputBar}\n {belowInput != null && (\n <div className={styles.belowInput} data-juneau=\"below-input\">\n {belowInput}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n className={[styles.chat, className].filter(Boolean).join(' ')}\n style={style}\n data-juneau=\"chat\"\n >\n <AiMessageList\n messages={messages}\n isLoading={isLoading}\n isConnecting={isConnecting}\n onProposalConfirm={onProposalConfirm}\n onProposalCancel={onProposalCancel}\n onEntityClick={onEntityClick}\n assistantIcon={assistantIcon}\n renderPart={renderPart}\n emptyState={emptyState}\n />\n\n {errorBanner}\n\n {aboveInputSlot}\n\n {inputBar}\n </div>\n );\n}\n","import type { ReactNode } from 'react';\nimport {\n IconArrowRotateLeft,\n IconWandMagicSparkles,\n IconWindowMinimize,\n IconWindowRestore,\n} from '../icons';\nimport { useLabels } from '../../i18n/context';\nimport styles from './AiChatHeader.module.css';\n\ntype Props = {\n title?: string;\n onMinimize?: () => void;\n isMinimized?: boolean;\n /** Override the avatar icon. Pass any ReactNode — an SVG, img, or component. Defaults to a wand icon. */\n icon?: ReactNode;\n /** Called when the reset button is clicked. When provided, a reset button is shown. */\n onReset?: () => void;\n /**\n * Rendered right of the title. Use it for an unread/notification badge.\n * Juneau renders it as given and never interprets it.\n */\n badge?: ReactNode;\n /**\n * Extra controls rendered left of the built-in reset/minimize buttons.\n * Juneau renders them as given and never interprets them — the consumer owns their behaviour.\n */\n headerActions?: ReactNode;\n};\n\nexport function AiChatHeader({\n title,\n onMinimize,\n isMinimized,\n icon,\n onReset,\n badge,\n headerActions,\n}: Props) {\n const labels = useLabels();\n\n return (\n <div className={styles.header} data-juneau=\"header\">\n <div className={styles.left}>\n <span className={styles.icon} aria-hidden=\"true\" data-juneau=\"header-icon\">\n {icon ?? <IconWandMagicSparkles />}\n </span>\n <span className={styles.title}>{title ?? labels.sidebarTitle}</span>\n {badge && (\n <span className={styles.badge} data-juneau=\"header-badge\">\n {badge}\n </span>\n )}\n </div>\n {(onMinimize || onReset || headerActions) && (\n <div className={styles.actions}>\n {headerActions}\n {onReset && (\n <button\n className={styles.resetBtn}\n onClick={onReset}\n title={labels.resetConversation}\n aria-label={labels.resetConversation}\n data-juneau=\"header-reset\"\n >\n <IconArrowRotateLeft />\n </button>\n )}\n {onMinimize && (\n <button\n className={styles.resetBtn}\n onClick={onMinimize}\n title={isMinimized ? labels.expandSidebar : labels.minimizeSidebar}\n aria-label={isMinimized ? labels.expandSidebar : labels.minimizeSidebar}\n data-juneau=\"header-minimize\"\n >\n {isMinimized ? <IconWindowRestore /> : <IconWindowMinimize />}\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n","import type { CSSProperties, ReactNode } from 'react';\nimport { useState } from 'react';\nimport type { AiEntity } from '../../core/types';\nimport { useAiChatContext } from '../../context/AiChatContext';\nimport type { AiInputAction } from '../AiInput/AiInput';\nimport { AiChat } from '../AiChat/AiChat';\nimport { AiChatHeader } from '../AiChatHeader/AiChatHeader';\nimport type { RenderPartFn } from '../parts/AiMessagePartRenderer';\nimport styles from './AiSidebar.module.css';\n\ntype Props = {\n /** Overrides the `sidebarTitle` label for this instance only. */\n title?: string;\n /** Override the header and assistant avatar icon. Defaults to a wand icon. */\n icon?: ReactNode;\n /** Override only the message avatar. Falls back to `icon` when omitted. */\n assistantIcon?: ReactNode;\n /**\n * Toolbar action buttons rendered left of the send button.\n * Pass an empty array to hide the toolbar entirely.\n */\n actions?: AiInputAction[];\n /** Override the send button icon. Defaults to a paper-plane icon. */\n sendIcon?: ReactNode;\n /**\n * Height of the sidebar when open. Any valid CSS value.\n * Defaults to '60vh'.\n */\n height?: string;\n className?: string;\n style?: CSSProperties;\n /**\n * Called when the user resets the conversation. When provided, a reset\n * button is shown in the header. Internally calls `useAiChatContext().reset()`\n * and then invokes this callback — no wrapper component needed.\n */\n onReset?: () => void;\n /**\n * Gate asked before the conversation is cleared. Resolve false to abort —\n * nothing is reset and `onReset` never fires. Use it for a confirm dialog.\n */\n confirmReset?: () => boolean | Promise<boolean>;\n /**\n * Custom part renderer — called before the built-in renderers for every\n * message part. Return a ReactNode to render it, or null/undefined to fall\n * through to the built-ins. Enables custom part types like invoice cards.\n */\n renderPart?: RenderPartFn;\n /** Makes entity cards clickable — receives the entity and its optional entityType. */\n onEntityClick?: (entity: AiEntity, entityType?: string) => void;\n /**\n * Extra controls rendered in the header, left of the reset/minimize buttons.\n * Use it for consumer-owned chrome such as a settings button.\n */\n headerActions?: ReactNode;\n /**\n * Rendered right of the header title. Use it for an unread/notification badge.\n * Juneau renders it as given and never interprets it.\n */\n badge?: ReactNode;\n /**\n * Collapsed state. Omit to let the sidebar own it; pass a value to control it\n * (e.g. to persist the choice) and keep it in sync via `onMinimizedChange`.\n */\n minimized?: boolean;\n /** Fires whenever the user toggles the collapsed state, controlled or not. */\n onMinimizedChange?: (minimized: boolean) => void;\n /**\n * Rendered instead of the default empty-state text when there are no messages.\n * Use it for a rich \"get started\" hero — headline, suggestion chips, anything.\n */\n emptyState?: ReactNode;\n /**\n * Consumer content rendered directly above the input, e.g. a feedback prompt.\n * Forwarded to `AiChat`; hidden together with the chat body while minimized.\n */\n aboveInput?: ReactNode;\n};\n\nexport function AiSidebar({\n title,\n icon,\n assistantIcon,\n actions,\n sendIcon,\n height = '60vh',\n className,\n style,\n onReset,\n confirmReset,\n renderPart,\n onEntityClick,\n headerActions,\n badge,\n minimized,\n onMinimizedChange,\n emptyState,\n aboveInput,\n}: Props) {\n const [uncontrolledMinimized, setUncontrolledMinimized] = useState(false);\n // Controlled when `minimized` is supplied; otherwise the sidebar keeps owning the state.\n const isControlled = minimized !== undefined;\n const isMinimized = isControlled ? minimized : uncontrolledMinimized;\n\n const toggleMinimized = (): void => {\n const next = !isMinimized;\n if (!isControlled) setUncontrolledMinimized(next);\n onMinimizedChange?.(next);\n };\n\n const {\n messages,\n input,\n setInput,\n sendMessage,\n stop,\n isLoading,\n isConnecting,\n error,\n reset,\n confirmProposal,\n cancelProposal,\n } = useAiChatContext();\n\n // The gate runs before the wipe, so a declined confirm leaves the chat untouched.\n const handleReset = onReset\n ? async () => {\n if (confirmReset && !(await confirmReset())) return;\n reset();\n onReset();\n }\n : undefined;\n\n return (\n <aside\n className={[styles.sidebar, isMinimized ? styles.minimized : '', className].filter(Boolean).join(' ')}\n style={{ height: isMinimized ? undefined : height, ...style }}\n data-juneau=\"sidebar\"\n >\n <AiChatHeader\n title={title}\n icon={icon}\n onMinimize={toggleMinimized}\n isMinimized={isMinimized}\n onReset={handleReset}\n badge={badge}\n headerActions={headerActions}\n />\n\n {!isMinimized && (\n <AiChat\n messages={messages}\n input={input}\n isLoading={isLoading}\n isConnecting={isConnecting}\n error={error}\n onInputChange={setInput}\n onSend={sendMessage}\n onStop={stop}\n onProposalConfirm={confirmProposal}\n onProposalCancel={cancelProposal}\n assistantIcon={assistantIcon ?? icon}\n actions={actions}\n sendIcon={sendIcon}\n renderPart={renderPart}\n onEntityClick={onEntityClick}\n emptyState={emptyState}\n aboveInput={aboveInput}\n />\n )}\n </aside>\n );\n}\n","import type { AiChatSummary } from '../../core/types';\nimport { useLabels } from '../../i18n/context';\nimport styles from './AiChatHistoryList.module.css';\n\ntype Props = {\n /** Stored chats to display — most recently updated first is recommended (see `trimChats`) */\n chats: AiChatSummary[];\n /** Called with the chat id when the user picks a chat */\n onSelect: (chatId: string) => void;\n /** Highlights the currently open chat, if any */\n activeChatId?: string;\n /** If provided, shows a delete button on each row */\n onDelete?: (chatId: string) => void;\n};\n\nexport function AiChatHistoryList({ chats, onSelect, activeChatId, onDelete }: Props) {\n const labels = useLabels();\n\n if (chats.length === 0) {\n return <p className={styles.empty}>{labels.historyEmpty}</p>;\n }\n\n return (\n <ul className={styles.list} data-juneau=\"history-list\">\n {chats.map(chat => (\n <li key={chat.id} className={styles.item}>\n <button\n className={chat.id === activeChatId ? `${styles.chat} ${styles.chatActive}` : styles.chat}\n onClick={() => onSelect(chat.id)}\n >\n <span className={styles.title}>{chat.title}</span>\n <span className={styles.date}>\n {chat.updatedAt.toLocaleDateString(undefined, { day: 'numeric', month: 'short' })}\n </span>\n </button>\n {onDelete && (\n <button\n className={styles.delete}\n onClick={() => onDelete(chat.id)}\n aria-label={labels.historyDeleteChat}\n >\n <svg viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z\" />\n </svg>\n </button>\n )}\n </li>\n ))}\n </ul>\n );\n}\n"],"names":["serializeMessages","messages","msg","p","delay","ms","resolve","getMessageText","message","consumeStream","iterable","onEvent","signal","event","isProposalPart","part","isChartPart","STORAGE_FORMAT_VERSION","serializeForStorage","sanitizePart","deserializeMessages","stored","_v","trimHistory","limit","start","trimChats","chats","byUpdatedDesc","a","b","mockAdapter","input","lastUserMessage","m","query","scenarioActivity","scenarioTable","scenarioProposal","scenarioEntity","scenarioHelp","scenarioError","scenarioDefault","streamText","text","chunkDelayMs","i","parseJuneauWire","raw","wire","createSseAdapter","url","options","method","staticHeaders","getHeaders","getBody","getMessages","parseEvent","defaultOpenAiParser","credentials","dynamicHeaders","resolvedInput","body","response","readSseStream","reader","decoder","buffer","done","value","lines","line","trimmed","data","events","json","delta","createFetchStreamAdapter","parseChunk","defaultNdjsonParser","readChunkedStream","chunk","messageIdCounter","nextId","serializeHistory","useAiChat","adapter","context","onProposalConfirm","onProposalCancel","initialMessages","historyLimit","onMessagesChange","setMessages","useState","setInput","isLoading","setIsLoading","isConnecting","setIsConnecting","error","setError","abortRef","useRef","shouldNotifyRef","onMessagesChangeRef","useEffect","appendPartToLast","useCallback","prev","last","parts","existingIndex","appendTextToLast","lastPart","sendMessageCore","currentMessages","userMessage","assistantId","assistantAdded","ensureAssistantBubble","assistantMessage","abort","history","stream","err","sendMessage","sendMessageWithText","sendGreeting","contextHint","syntheticContext","stop","reset","nextMessages","resolveProposal","proposalId","resolved","confirmProposal","payload","cancelProposal","useMemo","juneauEn","JuneauLabelsContext","createContext","useLabels","useContext","JuneauProvider","children","theme","labels","defaultTitle","className","style","resolvedLabels","themeVars","buildThemeVars","jsx","styles","map","v","AiChatContext","useAiChatContext","ctx","useAiChatContextSafe","AiChatProvider","initialContext","setContextState","setContext","chat","juneauCs","IconWandMagicSparkles","ariaHidden","IconPaperPlane","IconPaperclip","IconBolt","IconPlus","IconClockRotateLeft","IconScroll","IconWindowMinimize","IconWindowRestore","IconArrowRotateLeft","IconWarning","AiTablePart","jsxs","col","row","AiProposalCard","onConfirm","onCancel","proposal","resolvedLabel","AiActivityPart","badgeClass","AiEntityCard","onEntityClick","entity","entityType","clickable","Fragment","field","AiEntityListPart","AiMessagePartRenderer","renderPart","custom","Markdown","remarkGfm","INLINE_PART_TYPES","isCardPart","toSegments","segments","index","card","AiMessageBubble","assistantIcon","isUser","renderOne","hasCard","segment","AiTypingIndicator","connecting","AiMessageList","emptyState","bottomRef","AiInput","onChange","onSend","onStop","placeholder","actions","sendIcon","textareaRef","wasLoadingRef","defaultActions","resolvedActions","handleKeyDown","e","action","AiError","onDismiss","AiChat","onInputChange","aboveInput","centerInputWhenEmpty","belowInput","errorBanner","aboveInputSlot","inputBar","AiChatHeader","title","onMinimize","isMinimized","icon","onReset","badge","headerActions","AiSidebar","height","confirmReset","minimized","onMinimizedChange","uncontrolledMinimized","setUncontrolledMinimized","isControlled","toggleMinimized","next","handleReset","AiChatHistoryList","onSelect","activeChatId","onDelete"],"mappings":"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"}
|