quassel 0.1.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/index.js.map ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/types.ts", "../src/texts.ts", "../src/useChat.ts", "../src/ChatMessages.tsx", "../src/options.ts", "../src/timestamps.ts", "../src/MessageActions.tsx", "../src/ChatSendContext.ts", "../src/Markdown.tsx", "../src/announce.ts", "../src/StepPopover.tsx", "../src/icons.tsx", "../src/QuestionCard.tsx", "../src/WorkingScenes.tsx", "../src/ChatPanel.tsx", "../src/TimestampSwitch.tsx", "../src/ChatInputToolbar.tsx", "../src/DetailModeSwitch.tsx"],
4
+ "sourcesContent": ["import type { Message } from \"./events\";\n\nexport type { Role, ToolInfo, Question, Message, ChatEvent } from \"./events\";\nexport { applyEvent, prettyJson, compactToolLine } from \"./events\";\n\n/**\n * off = nur Antworten, icons = Schritte als reine Symbole nebeneinander,\n * chips = Schritte als Symbol + Kurztext nebeneinander (mit Umbruch),\n * grouped = aufeinanderfolgende Schritte hinter einer aufklappbaren Kopfzeile, darin einzeilig,\n * compact = Denken und Werkzeuge einzeilig, full = alles ausgeklappt.\n */\nexport type DetailMode = \"off\" | \"icons\" | \"chips\" | \"grouped\" | \"compact\" | \"full\";\n\n/** running = call still open, thinking = thought block still open, done = finished, error = failed. */\nexport type StepState = \"running\" | \"thinking\" | \"done\" | \"error\";\n\n/** The single derivation of a step state, so chips, hosts and tests read the same signal. */\nexport function stepState(message: Message): StepState {\n if (message.tool?.isError) {\n return \"error\";\n }\n if (message.role === \"thinking\") {\n return message.closed ? \"done\" : \"thinking\";\n }\n return message.tool !== undefined && message.tool.result === undefined ? \"running\" : \"done\";\n}\n\n/** A moment worth one screen reader announcement: a finished reply or a new open question. */\nexport type ChatAnnouncement =\n | { kind: \"reply\"; message: Message }\n | { kind: \"question\"; message: Message };\n", "export interface ChatTexts {\n working: string;\n toolRunning: string;\n toolStillRunning: string;\n thinkingChip: string;\n stepGroupOne: string;\n stepGroupMany: string;\n stepGroupCollapse: string;\n thinkingTitle: string;\n toolTitle: string;\n argumentsLabel: string;\n resultLabel: string;\n close: string;\n jumpToEnd: string;\n send: string;\n sendIntoRun: string;\n stop: string;\n placeholder: string;\n steeringPlaceholder: string;\n timestamps: string;\n messageActions: string;\n questionSubmit: string;\n questionPlaceholder: string;\n questionAnswer: string;\n copyMessage: string;\n copyCode: string;\n copied: string;\n copyFailed: string;\n editMessage: string;\n retryMessage: string;\n detailModeTitle: string;\n detailModeOff: string;\n detailModeIcons: string;\n detailModeChips: string;\n detailModeGrouped: string;\n detailModeCompact: string;\n detailModeFull: string;\n}\n\nexport const defaultTexts: ChatTexts = {\n working: \"Arbeitet ...\",\n toolRunning: \"l\u00E4uft ...\",\n toolStillRunning: \"Werkzeug l\u00E4uft ...\",\n thinkingChip: \"Denken\",\n stepGroupOne: \"1 Schritt\",\n stepGroupMany: \"{count} Schritte\",\n stepGroupCollapse: \"Einklappen\",\n thinkingTitle: \"Thinking-Trace\",\n toolTitle: \"Tool-Call\",\n argumentsLabel: \"Argumente\",\n resultLabel: \"Ergebnis\",\n close: \"Schlie\u00DFen\",\n jumpToEnd: \"Zum Ende springen\",\n send: \"Senden\",\n sendIntoRun: \"In den laufenden Lauf schicken\",\n stop: \"Lauf abbrechen\",\n placeholder: \"Nachricht schreiben ...\",\n steeringPlaceholder: \"Dazwischenfunken ...\",\n timestamps: \"Zeitstempel\",\n messageActions: \"Nachrichtenaktionen\",\n questionSubmit: \"Auswahl \u00FCbernehmen\",\n questionPlaceholder: \"... oder frei antworten\",\n questionAnswer: \"Antworten\",\n copyMessage: \"Nachricht kopieren\",\n copyCode: \"Code kopieren\",\n copied: \"Kopiert\",\n copyFailed: \"Kopieren ist nicht verf\u00FCgbar.\",\n editMessage: \"Nachricht bearbeiten\",\n retryMessage: \"Erneut senden\",\n detailModeTitle: \"Detailgrad der Schritte\",\n detailModeOff: \"nur Antworten\",\n detailModeIcons: \"Symbole\",\n detailModeChips: \"kompakt\",\n detailModeGrouped: \"gruppiert\",\n detailModeCompact: \"einzeilig\",\n detailModeFull: \"alles\",\n};\n", "import { useCallback, useEffect, useReducer, useRef, useState } from \"react\";\nimport { applyEvent, ChatEvent, Message } from \"./events\";\n\n/**\n * Verbindet die Chat-Komponenten mit einem quassel/server-Endpunkt: ein dauerhafter\n * SSE-Strom liefert erst den Verlauf, dann live; Senden und Stoppen sind eigene Aufrufe\n * und erreichen so auch einen laufenden Turn. Bricht der Strom ab, verbindet der Hook\n * nach 3 Sekunden neu.\n */\nexport function useChat(baseUrl: string, headers: Record<string, string> = {}, onEvent?: (event: ChatEvent) => void): {\n messages: Message[];\n running: boolean;\n connected: boolean;\n send: (text: string) => Promise<void>;\n stop: () => Promise<void>;\n} {\n const [messages, dispatch] = useReducer(applyEvent, [] as Message[]);\n const [running, setRunning] = useState(false);\n const [connected, setConnected] = useState(false);\n const url = useRef(baseUrl);\n url.current = baseUrl;\n const zusatz = useRef(headers);\n zusatz.current = headers;\n const observer = useRef(onEvent);\n observer.current = onEvent;\n\n useEffect(() => {\n const controller = new AbortController();\n let active = true;\n\n async function verbinden() {\n while (active) {\n try {\n const response = await fetch(`${url.current}/stream`, {\n headers: { Accept: \"text/event-stream\", ...zusatz.current },\n signal: controller.signal,\n });\n if (!response.ok || !response.body) {\n throw new Error(`Stream fehlgeschlagen: ${response.status}`);\n }\n setConnected(true);\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let puffer = \"\";\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n puffer += decoder.decode(value, { stream: true });\n const teile = puffer.split(\"\\n\\n\");\n puffer = teile.pop() ?? \"\";\n for (const teil of teile) {\n const daten = teil\n .split(\"\\n\")\n .filter((zeile) => zeile.startsWith(\"data:\"))\n .map((zeile) => zeile.slice(5).trim())\n .join(\"\");\n if (!daten) {\n continue;\n }\n const event = JSON.parse(daten) as ChatEvent;\n if (event.kind === \"status\") {\n setRunning(event.running);\n }\n observer.current?.(event);\n dispatch(event);\n }\n }\n } catch {\n if (!active) {\n return;\n }\n }\n setConnected(false);\n await new Promise((resolve) => setTimeout(resolve, 3000));\n }\n }\n\n void verbinden();\n return () => {\n active = false;\n controller.abort();\n };\n }, []);\n\n const send = useCallback(async (text: string) => {\n await fetch(`${url.current}/send`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...zusatz.current },\n body: JSON.stringify({ text }),\n });\n }, []);\n\n const stop = useCallback(async () => {\n await fetch(`${url.current}/stop`, { method: \"POST\", headers: { ...zusatz.current } });\n }, []);\n\n return { messages, running, connected, send, stop };\n}\n", "import { ReactNode, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport { appearanceStyle, type ChatAppearance, type TimestampOptions, type CodeBlockOptions, type BubbleOptions, type MessageActionsOptions } from \"./options\";\nimport { timestampDate, formatTimestamp, timestampDay, formatDay } from \"./timestamps\";\nimport { MessageActions } from \"./MessageActions\";\nimport { ChatSendContext } from \"./ChatSendContext\";\nimport { ChatAnnouncement, compactToolLine, DetailMode, Message, prettyJson, stepState, ToolInfo } from \"./types\";\nimport { ChatTexts, defaultTexts } from \"./texts\";\nimport { Markdown, MarkdownLinks, MarkdownCodeBlocks, markdownPlainText, type LinkClickHandler } from \"./Markdown\";\nimport { announce as ansagen } from \"./announce\";\nimport { StepPopover } from \"./StepPopover\";\nimport { QuestionCard } from \"./QuestionCard\";\nimport { WorkingScenes } from \"./WorkingScenes\";\nimport { IconCheck, IconChevronDown, IconChevronRight, IconLayers, IconSpark, IconTool } from \"./icons\";\n\nconst collapseAtBottomFrom = 11;\nconst hoechstensAnsagenAufEinmal = 2;\n\nfunction istSchritt(message?: Message): boolean {\n return !!message && (message.role === \"thinking\" || message.role === \"tool\");\n}\n\nfunction defaultArgumentsText(tool: ToolInfo): string {\n return prettyJson(tool.arguments);\n}\n\n/**\n * Der Verlauf: eigener Scroll-Container mit Autoscroll, solange man unten ist,\n * und einem Zum-Ende-Knopf, sobald man liest. Ohne Eingabe read-only nutzbar.\n */\nexport function ChatMessages({\n messages,\n detailMode = \"compact\",\n running = false,\n working,\n workingTimeoutMs = 20000,\n stepsExpandable = true,\n texts,\n toolArgumentsText = defaultArgumentsText,\n renderTool,\n onAnswerQuestion,\n onLinkClick,\n announce,\n emptyState,\n className,\n showTimestamps = false,\n bottomThreshold = 120,\n scrollerRef,\n appearance,\n timestampOptions,\n codeBlockOptions,\n bubbleOptions,\n messageActions,\n}: {\n messages: Message[];\n appearance?: ChatAppearance;\n timestampOptions?: TimestampOptions;\n codeBlockOptions?: CodeBlockOptions;\n bubbleOptions?: BubbleOptions;\n messageActions?: MessageActionsOptions;\n detailMode?: DetailMode;\n running?: boolean;\n working?: ReactNode;\n /** Ohne neue Events verschwindet der Working-Indikator nach dieser Zeit, Default 20s. */\n workingTimeoutMs?: number;\n /** false = Denk- und Werkzeug-Schritte lassen sich nicht aufklappen (kein Popover). */\n stepsExpandable?: boolean;\n texts?: Partial<ChatTexts>;\n toolArgumentsText?: (tool: ToolInfo) => string;\n /** Eigene Darstellung fuer einzelne Werkzeuge; undefined = Standarddarstellung. */\n renderTool?: (tool: ToolInfo) => ReactNode | undefined;\n onAnswerQuestion?: (callId: string, text: string) => void;\n /** Faengt Klicks auf Markdown-Links ab; true = behandelt, der Browser folgt nicht. */\n onLinkClick?: LinkClickHandler;\n /** Screenreader-Ansage je fertiger Antwort und neuer R\u00FCckfrage: Default ist ihr Text, eine Funktion liefert eigenen Text (undefined = still), false schaltet ab. */\n announce?: false | ((announcement: ChatAnnouncement) => string | undefined);\n emptyState?: ReactNode;\n className?: string;\n /** true = dezente HH:MM-Spalte links an jedem Block (Message.at). */\n showTimestamps?: boolean;\n bottomThreshold?: number;\n /** Exposes the scroll container so hosts can scroll without querying the DOM. */\n scrollerRef?: (element: HTMLDivElement | null) => void;\n}) {\n const alleTexte = { ...defaultTexts, ...texts };\n const scrollBereich = useRef<HTMLDivElement>(null);\n const [amEnde, setAmEnde] = useState(true);\n const panel = useContext(ChatSendContext);\n useLayoutEffect(() => panel?.registerJump(() => {\n setAmEnde(true);\n const viewport = scrollBereich.current;\n if (viewport) viewport.scrollTop = viewport.scrollHeight;\n }), [panel]);\n const [now, setNow] = useState(Date.now);\n const relative = showTimestamps && timestampOptions?.format === \"relative\";\n useEffect(() => {\n if (!relative) return;\n setNow(Date.now());\n const timer = window.setInterval(() => setNow(Date.now()), 1000);\n return () => window.clearInterval(timer);\n }, [relative]);\n\n // Der Indikator laeuft nur, solange wirklich Events eintreffen: jede Aenderung am Verlauf\n // gilt als Lebenszeichen, danach zaehlt der Timeout. Stop beendet ihn ohnehin (running).\n const [stromAktiv, setStromAktiv] = useState(true);\n useEffect(() => {\n setStromAktiv(true);\n const timer = window.setTimeout(() => setStromAktiv(false), workingTimeoutMs);\n return () => window.clearTimeout(timer);\n }, [messages, workingTimeoutMs]);\n\n // Der Verlauf beim Einh\u00E4ngen und ganze Sch\u00FCbe (Reset mit Replay) gelten als bekannt, nicht als neu.\n const angesagt = useRef<ReadonlySet<string>>(new Set(messages.map((message) => message.key)));\n useEffect(() => {\n const faellig = messages.filter((message, index) => !angesagt.current.has(message.key) && (\n message.role === \"question\"\n ? message.question !== undefined && message.question.answer === undefined\n : message.role === \"assistant\" && message.text.trim() !== \"\" && (message.closed === true || (!running && index === messages.length - 1))\n ));\n if (faellig.length === 0) {\n return;\n }\n angesagt.current = new Set([...angesagt.current, ...faellig.map((message) => message.key)]);\n if (announce === false || faellig.length > hoechstensAnsagenAufEinmal) {\n return;\n }\n faellig\n .map((message) => announce\n ? announce({ kind: message.role === \"question\" ? \"question\" : \"reply\", message })\n : markdownPlainText(message.text))\n .forEach((text) => text && ansagen(text));\n }, [messages, running, announce]);\n\n // Include content that fits without scrolling in the bottom tolerance.\n const pruefeEnde = useCallback(() => {\n const bereich = scrollBereich.current;\n if (bereich) {\n const abstandZumEnde = bereich.scrollHeight - bereich.scrollTop - bereich.clientHeight;\n setAmEnde(abstandZumEnde <= bottomThreshold);\n }\n }, [bottomThreshold]);\n\n // Beim Streamen waechst der Inhalt, ohne dass jemand scrollt - ohne diesen Beobachter bliebe\n // die Antwort auf \"bin ich unten?\" stehen und der Knopf sichtbar, obwohl man unten ist.\n useEffect(() => {\n const bereich = scrollBereich.current;\n if (!bereich) {\n return;\n }\n const beobachter = new ResizeObserver(pruefeEnde);\n beobachter.observe(bereich);\n for (const kind of bereich.children) {\n beobachter.observe(kind);\n }\n return () => beobachter.disconnect();\n }, [pruefeEnde, messages.length]);\n\n useEffect(() => {\n if (!amEnde) {\n return;\n }\n scrollBereich.current?.scrollTo({ top: scrollBereich.current.scrollHeight, behavior: running ? \"auto\" : \"smooth\" });\n }, [messages, running, amEnde]);\n\n const visible = useMemo(\n () =>\n messages.filter((message) => {\n if ((message.role === \"thinking\" || message.role === \"assistant\") && message.text.trim() === \"\") {\n return false;\n }\n if (message.role === \"thinking\" || message.role === \"tool\") {\n return detailMode !== \"off\";\n }\n return true;\n }),\n [messages, detailMode],\n );\n\n // Dezente HH:MM-Spalte links; ohne Zeitstempel bleibt der Block unverpackt.\n const zeitVon = (at: string | undefined) => {\n const date = timestampDate(at);\n return date ? formatTimestamp(date, timestampOptions, now) : \"\";\n };\n const mitZeit = (inhalt: ReactNode, key: string, at: string | undefined): ReactNode =>\n showTimestamps\n ? (\n <div className=\"qsl-line\" key={`zeit-${key}`}>\n <time className=\"qsl-time\" dateTime={timestampDate(at) ? at : undefined} style={timestampOptions?.format && timestampOptions.format !== \"time\" ? { width: \"auto\", maxWidth: \"35%\" } : undefined}>{zeitVon(at)}</time>\n <div className=\"qsl-line-body\">{inhalt}</div>\n </div>\n )\n : inhalt;\n\n // In den Chip-Modi ruecken aufeinanderfolgende Schritte in eine umbrechende Zeile zusammen, gruppiert hinter eine aufklappbare Zeile.\n const chipModus = detailMode === \"chips\" || detailMode === \"icons\";\n const gruppenModus = detailMode === \"grouped\";\n const bloecke: ReactNode[] = [];\n let gruppe: Message[] = [];\n const schliesseGruppe = () => {\n if (gruppe.length > 0) {\n const letzterZustand = stepState(gruppe[gruppe.length - 1]);\n bloecke.push(mitZeit(\n gruppenModus ? (\n <StepGroup\n aktiv={running && (letzterZustand === \"running\" || letzterZustand === \"thinking\")}\n expandierbar={stepsExpandable}\n key={gruppe[0].key}\n messages={gruppe}\n texts={alleTexte}\n toolArgumentsText={toolArgumentsText}\n />\n ) : (\n <StepRow\n expandierbar={stepsExpandable}\n key={gruppe[0].key}\n messages={gruppe}\n mitText={detailMode === \"chips\"}\n texts={alleTexte}\n toolArgumentsText={toolArgumentsText}\n />\n ),\n gruppe[0].key,\n gruppe[0].at,\n ));\n gruppe = [];\n }\n };\n let currentDay: string | undefined;\n visible.forEach((message, index) => {\n const date = timestampOptions?.showDaySeparators ? timestampDate(message.at) : undefined;\n if (date) {\n const day = timestampDay(date, timestampOptions?.timeZone);\n if (day !== currentDay) {\n schliesseGruppe();\n bloecke.push(<div className=\"qsl-day-separator\" role=\"separator\" key={`day-${message.key}`} aria-label={formatDay(date, timestampOptions)}>{formatDay(date, timestampOptions)}</div>);\n currentDay = day;\n }\n }\n const eigeneDarstellung = message.role === \"tool\" && message.tool ? renderTool?.(message.tool) : undefined;\n if (eigeneDarstellung !== undefined) {\n schliesseGruppe();\n bloecke.push(mitZeit(\n <div className=\"qsl-step\" key={message.key}>\n {eigeneDarstellung}\n </div>,\n message.key,\n message.at,\n ));\n return;\n }\n if ((chipModus || gruppenModus) && istSchritt(message)) {\n gruppe = [...gruppe, message];\n return;\n }\n schliesseGruppe();\n bloecke.push(mitZeit(\n <Bubble\n detailMode={detailMode}\n dicht={istSchritt(message) && istSchritt(visible[index - 1])}\n expandierbar={stepsExpandable}\n key={message.key}\n message={message}\n bubbleOptions={bubbleOptions}\n messageActions={messageActions}\n texts={alleTexte}\n toolArgumentsText={toolArgumentsText}\n onAnswerQuestion={onAnswerQuestion}\n />,\n message.key,\n message.at,\n ));\n });\n schliesseGruppe();\n\n const verlauf = (\n <div className={className ? `qsl-chat-wrap ${className}` : \"qsl-chat-wrap\"} style={appearanceStyle(appearance)}>\n <div\n className=\"qsl-chat\"\n onScroll={pruefeEnde}\n ref={(element) => {\n scrollBereich.current = element;\n scrollerRef?.(element);\n }}\n >\n {visible.length === 0 && !running ? (\n emptyState ?? null\n ) : (\n <div aria-busy={running || undefined} className=\"qsl-thread\">\n {bloecke}\n {running && stromAktiv && (working ?? <WorkingScenes label={alleTexte.working} />)}\n </div>\n )}\n </div>\n {!amEnde && (\n <div className=\"qsl-jump\">\n <button aria-label={alleTexte.jumpToEnd} onClick={() => scrollBereich.current?.scrollTo({ top: scrollBereich.current.scrollHeight, behavior: \"smooth\" })} type=\"button\">\n <IconChevronDown />\n </button>\n </div>\n )}\n </div>\n );\n\n return <MarkdownLinks onLinkClick={onLinkClick}><MarkdownCodeBlocks options={codeBlockOptions} texts={texts}>{verlauf}</MarkdownCodeBlocks></MarkdownLinks>;\n}\n\n/** Aufeinanderfolgende Schritte als Chips nebeneinander; bei Platzmangel bricht die Zeile um. */\nfunction StepRow({\n messages,\n mitText,\n expandierbar,\n texts,\n toolArgumentsText,\n}: {\n messages: Message[];\n mitText: boolean;\n expandierbar: boolean;\n texts: ChatTexts;\n toolArgumentsText: (tool: ToolInfo) => string;\n}) {\n const [detail, setDetail] = useState<{ key: string; position: { x: number; y: number } }>();\n const offen = expandierbar && detail && messages.find((message) => message.key === detail.key);\n\n return (\n <div className=\"qsl-step qsl-steprow\">\n {messages.map((message) => {\n const thinking = message.role === \"thinking\";\n const tool = message.tool;\n const state = stepState(message);\n const running = state === \"running\" || state === \"thinking\";\n const label = thinking ? texts.thinkingChip : tool?.name ?? message.text;\n const content = (\n <>\n {thinking ? (\n <IconSpark size={11} />\n ) : (\n <IconTool className={tool?.isError ? \"qsl-chip__icon--error\" : undefined} size={11} />\n )}\n {mitText && <span className=\"qsl-chip__label\">{label}</span>}\n {mitText && <span className=\"qsl-chip__state\">{state === \"done\" && <IconCheck size={10} />}</span>}\n </>\n );\n const classes = `${mitText ? \"\" : \" qsl-chip--icon\"} qsl-chip--${state}${running ? \" qsl-pulse\" : \"\"}`;\n if (!expandierbar) {\n return (\n <span className={`qsl-chip qsl-chip--still${classes}`} key={message.key} title={label}>\n {content}\n </span>\n );\n }\n return (\n <button\n aria-haspopup=\"dialog\"\n className={`qsl-chip${classes}`}\n key={message.key}\n onClick={(event) => setDetail({ key: message.key, position: { x: event.clientX, y: event.clientY } })}\n title={label}\n type=\"button\"\n >\n {content}\n </button>\n );\n })}\n {offen && detail && (\n <StepPopover\n message={offen}\n position={detail.position}\n texts={texts}\n toolArgumentsText={toolArgumentsText}\n onClose={() => setDetail(undefined)}\n />\n )}\n </div>\n );\n}\n\n/** Aufeinanderfolgende Schritte hinter einer Kopfzeile; aufgeklappt stehen sie einzeilig darunter. */\nfunction StepGroup({\n messages,\n aktiv,\n expandierbar,\n texts,\n toolArgumentsText,\n}: {\n messages: Message[];\n aktiv: boolean;\n expandierbar: boolean;\n texts: ChatTexts;\n toolArgumentsText: (tool: ToolInfo) => string;\n}) {\n const [offen, setOffen] = useState(false);\n const kopf = useRef<HTMLButtonElement>(null);\n const vonUntenEingeklappt = useRef(false);\n useLayoutEffect(() => {\n if (!offen && vonUntenEingeklappt.current) {\n vonUntenEingeklappt.current = false;\n kopf.current?.scrollIntoView({ block: \"nearest\" });\n }\n }, [offen]);\n const letzte = messages[messages.length - 1];\n const fehler = messages.some((message) => message.tool?.isError);\n const anzahl = messages.length === 1 ? texts.stepGroupOne : texts.stepGroupMany.replace(\"{count}\", String(messages.length));\n const laufend = aktiv ? (letzte.role === \"thinking\" ? texts.thinkingChip : letzte.tool?.name ?? letzte.text) : undefined;\n\n return (\n <div className=\"qsl-step qsl-stepgroup\">\n <button\n aria-expanded={offen}\n className={`qsl-trace qsl-trace--compact qsl-stepgroup__toggle${aktiv ? \" qsl-pulse\" : \"\"}`}\n onClick={() => setOffen((wert) => !wert)}\n ref={kopf}\n type=\"button\"\n >\n <IconChevronRight className=\"qsl-stepgroup__chevron\" size={12} />\n <IconLayers className={fehler ? \"qsl-trace__icon qsl-trace__icon--error\" : \"qsl-trace__icon\"} size={12} />\n <span className=\"qsl-trace__line\">\n {anzahl}\n {laufend && <span className=\"qsl-trace__running\">{laufend} {texts.toolRunning}</span>}\n </span>\n </button>\n {offen && (\n <div className=\"qsl-stepgroup__lines\">\n {messages.map((message) => (\n <TraceLine expandierbar={expandierbar} key={message.key} message={message} texts={texts} toolArgumentsText={toolArgumentsText} />\n ))}\n {messages.length >= collapseAtBottomFrom && (\n <button\n className=\"qsl-trace qsl-trace--compact qsl-stepgroup__toggle qsl-stepgroup__collapse\"\n onClick={() => {\n vonUntenEingeklappt.current = true;\n setOffen(false);\n }}\n type=\"button\"\n >\n <IconChevronRight className=\"qsl-stepgroup__chevron\" size={12} />\n <span className=\"qsl-trace__line\">{texts.stepGroupCollapse}</span>\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n\n/** Ein Schritt als eine Zeile; mit Freigabe oeffnet ein Klick die Details im Popover. */\nfunction TraceLine({\n message,\n className,\n expandierbar,\n texts,\n toolArgumentsText,\n}: {\n message: Message;\n className?: string;\n expandierbar: boolean;\n texts: ChatTexts;\n toolArgumentsText: (tool: ToolInfo) => string;\n}) {\n const [detailPosition, setDetailPosition] = useState<{ x: number; y: number }>();\n const classes = `${className ? `${className} ` : \"\"}qsl-trace qsl-trace--compact${message.role === \"thinking\" ? \" qsl-trace--thinking\" : \"\"}`;\n const inhalt = (\n <>\n <TraceIcon message={message} />\n <span className=\"qsl-trace__line\"><TraceText message={message} texts={texts} /></span>\n </>\n );\n if (!expandierbar) {\n return <div className={classes}>{inhalt}</div>;\n }\n return (\n <>\n <button\n aria-expanded={detailPosition !== undefined}\n aria-haspopup=\"dialog\"\n className={classes}\n onClick={(event) => setDetailPosition({ x: event.clientX, y: event.clientY })}\n type=\"button\"\n >\n {inhalt}\n </button>\n {detailPosition && (\n <StepPopover\n message={message}\n position={detailPosition}\n texts={texts}\n toolArgumentsText={toolArgumentsText}\n onClose={() => setDetailPosition(undefined)}\n />\n )}\n </>\n );\n}\n\nfunction TraceIcon({ message }: { message: Message }) {\n return message.role === \"thinking\"\n ? <IconSpark className=\"qsl-trace__icon\" size={12} />\n : <IconTool className={message.tool?.isError ? \"qsl-trace__icon qsl-trace__icon--error\" : \"qsl-trace__icon\"} size={12} />;\n}\n\nfunction TraceText({ message, texts }: { message: Message; texts: ChatTexts }) {\n return (\n <>\n {message.text}\n {message.tool && message.tool.result === undefined && <span className=\"qsl-trace__running\">{texts.toolRunning}</span>}\n </>\n );\n}\n\nfunction Bubble({\n message,\n bubbleOptions,\n messageActions,\n detailMode,\n dicht,\n expandierbar,\n texts,\n toolArgumentsText,\n onAnswerQuestion,\n}: {\n message: Message;\n bubbleOptions?: BubbleOptions;\n messageActions?: MessageActionsOptions;\n detailMode: DetailMode;\n dicht: boolean;\n expandierbar: boolean;\n texts: ChatTexts;\n toolArgumentsText: (tool: ToolInfo) => string;\n onAnswerQuestion?: (callId: string, text: string) => void;\n}) {\n const schritt = dicht ? \"qsl-step qsl-step--dense\" : \"qsl-step\";\n\n if (message.role === \"thinking\" || (message.role === \"tool\" && message.tool)) {\n if (detailMode === \"compact\") {\n return <TraceLine className={schritt} expandierbar={expandierbar} message={message} texts={texts} toolArgumentsText={toolArgumentsText} />;\n }\n const tool = message.tool;\n return (\n <div className={`${schritt} qsl-trace${message.role === \"thinking\" ? \" qsl-trace--thinking\" : \"\"}`}>\n <TraceIcon message={message} />\n <div className=\"qsl-trace__body\">\n <div className=\"qsl-trace__line\"><TraceText message={message} texts={texts} /></div>\n {tool && (\n <div className=\"qsl-details\">\n <pre>{toolArgumentsText(tool)}</pre>\n {tool.result !== undefined && (\n <pre className={tool.isError ? \"qsl-details__pre--error\" : undefined}>{prettyJson(tool.result)}</pre>\n )}\n </div>\n )}\n </div>\n </div>\n );\n }\n\n if (message.role === \"question\" && message.question) {\n return (\n <div className={schritt}>\n <QuestionCard\n question={message.question}\n text={message.text}\n texts={texts}\n onAnswer={(text) => onAnswerQuestion?.(message.question!.callId, text)}\n />\n </div>\n );\n }\n\n if (message.role === \"system\") {\n return (\n <div className={`${schritt} qsl-system`}>\n <Markdown text={message.text} />\n </div>\n );\n }\n\n const content = message.text.trim();\n if (!content && message.role !== \"user\") return null;\n const plain = bubbleOptions?.variant === \"plain\";\n const isBubble = !plain && (message.role === \"user\" || message.bubble || bubbleOptions?.variant === \"bubbles\");\n const side = (message.role === \"user\" ? bubbleOptions?.userSide : bubbleOptions?.assistantSide)\n ?? message.bubble?.side ?? (message.role === \"user\" ? \"end\" : \"start\");\n const label = bubbleOptions?.showSender === false ? undefined\n : bubbleOptions?.senderLabel?.(message) ?? message.bubble?.label ?? (bubbleOptions?.showSender ? message.role : undefined);\n const body = <>\n {label && <span className=\"qsl-bubble__label\">{label}</span>}\n <Markdown text={message.role === \"user\" ? message.text : content} />\n <MessageActions message={message} options={messageActions} texts={texts} />\n </>;\n if (isBubble) {\n const user = message.role === \"user\" && !message.bubble;\n return <div className={`${schritt} ${user ? \"qsl-user\" : \"qsl-bubble\"}`} style={{ justifyContent: side === \"end\" ? \"flex-end\" : \"flex-start\" }}>\n <div style={{ background: message.bubble?.color ?? (user ? undefined : \"var(--qsl-accent)\"), maxWidth: bubbleOptions?.maxWidth }}>\n {body}\n </div>\n </div>;\n }\n return <div className={`${schritt} qsl-answer`}>{body}</div>;\n}\n", "import type { CSSProperties, ReactNode } from \"react\";\nimport type { Message } from \"./types\";\n\nexport interface ChatAppearance {\n fontSize?: CSSProperties[\"fontSize\"];\n lineHeight?: CSSProperties[\"lineHeight\"];\n messageGap?: CSSProperties[\"marginTop\"];\n denseMessageGap?: CSSProperties[\"marginTop\"];\n}\n\nexport interface TimestampOptions {\n format?: \"time\" | \"date-time\" | \"relative\";\n locale?: string;\n timeZone?: string;\n showDaySeparators?: boolean;\n}\n\nexport interface CodeBlockOptions {\n wrap?: boolean;\n maxHeight?: CSSProperties[\"maxHeight\"];\n showCopyButton?: boolean;\n}\n\nexport interface BubbleOptions {\n variant?: \"default\" | \"plain\" | \"bubbles\";\n maxWidth?: CSSProperties[\"maxWidth\"];\n userSide?: \"start\" | \"end\";\n assistantSide?: \"start\" | \"end\";\n showSender?: boolean;\n senderLabel?: (message: Message) => string | undefined;\n}\n\nexport interface MessageAction {\n id: string;\n label: string;\n icon?: ReactNode;\n disabled?: boolean;\n onClick: (message: Message) => void | Promise<void>;\n}\n\nexport interface MessageActionsOptions {\n copy?: boolean | ((message: Message) => boolean);\n edit?: (message: Message) => void | Promise<void>;\n retry?: (message: Message) => void | Promise<void>;\n custom?: (message: Message) => readonly MessageAction[];\n}\n\nexport type SendShortcut = \"enter\" | \"mod-enter\";\n\nconst length = (value: string | number | undefined) => typeof value === \"number\" ? `${value}px` : value;\n\nexport function appearanceStyle(appearance?: ChatAppearance): CSSProperties {\n return {\n \"--qsl-chat-font-size\": length(appearance?.fontSize),\n \"--qsl-chat-line-height\": appearance?.lineHeight,\n \"--qsl-message-gap\": length(appearance?.messageGap),\n \"--qsl-dense-message-gap\": length(appearance?.denseMessageGap),\n } as CSSProperties;\n}\n", "import type { TimestampOptions } from \"./options\";\n\nexport function timestampDate(at?: string): Date | undefined {\n if (!at) return undefined;\n const date = new Date(at);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\n\nexport function formatTimestamp(date: Date, options: TimestampOptions = {}, now = Date.now()): string {\n if (options.format === \"relative\") {\n const seconds = (date.getTime() - now) / 1000;\n const [unit, divisor]: [Intl.RelativeTimeFormatUnit, number] = Math.abs(seconds) < 60 ? [\"second\", 1]\n : Math.abs(seconds) < 3600 ? [\"minute\", 60] : Math.abs(seconds) < 86400 ? [\"hour\", 3600] : [\"day\", 86400];\n return new Intl.RelativeTimeFormat(options.locale ?? \"de\", { numeric: \"auto\" }).format(Math.round(seconds / divisor), unit);\n }\n if (options.format === \"date-time\") {\n return new Intl.DateTimeFormat(options.locale ?? \"de\", {\n dateStyle: \"short\", timeStyle: \"short\", timeZone: options.timeZone,\n }).format(date);\n }\n if (!options.locale && !options.timeZone) {\n return `${String(date.getHours()).padStart(2, \"0\")}:${String(date.getMinutes()).padStart(2, \"0\")}`;\n }\n return new Intl.DateTimeFormat(options.locale ?? \"de\", {\n hour: \"2-digit\", minute: \"2-digit\", hourCycle: \"h23\", timeZone: options.timeZone,\n }).format(date);\n}\n\nexport function timestampDay(date: Date, timeZone?: string): string {\n return new Intl.DateTimeFormat(\"en-CA\", {\n year: \"numeric\", month: \"2-digit\", day: \"2-digit\", calendar: \"gregory\", numberingSystem: \"latn\", timeZone,\n }).format(date);\n}\n\nexport function formatDay(date: Date, options?: TimestampOptions): string {\n return new Intl.DateTimeFormat(options?.locale ?? \"de\", {\n dateStyle: \"long\", timeZone: options?.timeZone,\n }).format(date);\n}\n", "import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport type { MessageActionsOptions } from \"./options\";\nimport type { ChatTexts } from \"./texts\";\nimport type { Message } from \"./types\";\n\nexport function ActionButton({ label, icon, disabled, onClick, successLabel }: {\n label: string;\n icon?: ReactNode;\n disabled?: boolean;\n onClick: () => void | Promise<void>;\n successLabel?: string;\n}) {\n const pending = useRef(false);\n const [status, setStatus] = useState<\"idle\" | \"pending\" | \"done\">(\"idle\");\n const [error, setError] = useState<string>();\n useEffect(() => {\n if (status !== \"done\") return;\n const timer = window.setTimeout(() => setStatus(\"idle\"), 1800);\n return () => window.clearTimeout(timer);\n }, [status]);\n const run = async () => {\n if (pending.current) return;\n pending.current = true;\n setStatus(\"pending\");\n setError(undefined);\n try {\n await onClick();\n setStatus(\"done\");\n } catch (failure) {\n setStatus(\"idle\");\n setError(failure instanceof Error ? failure.message : String(failure));\n } finally {\n pending.current = false;\n }\n };\n return <>\n <button className=\"qsl-icon-button\" type=\"button\" disabled={disabled || status === \"pending\"} onClick={() => void run()}>\n {icon}{status === \"done\" && successLabel ? successLabel : label}\n </button>\n {error && <span className=\"qsl-action-error\" role=\"alert\">{error}</span>}\n </>;\n}\n\nexport async function copyText(text: string, error: string) {\n if (!navigator.clipboard) throw new Error(error);\n await navigator.clipboard.writeText(text);\n}\n\nexport function MessageActions({ message, options, texts }: { message: Message; options?: MessageActionsOptions; texts: ChatTexts }) {\n if (!options) return null;\n const copy = typeof options.copy === \"function\" ? options.copy(message) : options.copy;\n const edit = message.role === \"user\" ? options.edit : undefined;\n const retry = message.role === \"assistant\" ? options.retry : undefined;\n const custom = options.custom?.(message) ?? [];\n if (!copy && !edit && !retry && custom.length === 0) return null;\n return <div className=\"qsl-message-actions\" role=\"group\" aria-label={texts.messageActions}>\n {copy && <ActionButton label={texts.copyMessage} successLabel={texts.copied} onClick={() => copyText(message.text, texts.copyFailed)} />}\n {edit && <ActionButton label={texts.editMessage} onClick={() => edit(message)} />}\n {retry && <ActionButton label={texts.retryMessage} onClick={() => retry(message)} />}\n {custom.map(action => <ActionButton key={action.id} label={action.label} icon={action.icon} disabled={action.disabled} onClick={() => action.onClick(message)} />)}\n </div>;\n}\n", "import { createContext, useContext, useLayoutEffect, useRef, useState } from \"react\";\nimport type { KeyboardEvent } from \"react\";\nimport type { SendShortcut } from \"./options\";\n\nexport const ChatSendContext = createContext<{\n onSent: () => void;\n registerJump: (jump: () => void) => () => void;\n} | undefined>(undefined);\n\nexport function isSendKey(event: KeyboardEvent<HTMLTextAreaElement>, shortcut: SendShortcut): boolean {\n return event.key === \"Enter\" && !event.shiftKey && !event.altKey\n && !event.nativeEvent.isComposing && event.nativeEvent.keyCode !== 229\n && (shortcut === \"enter\" || event.ctrlKey || event.metaKey);\n}\n\nexport function useChatSubmit(onSend: (text: string) => void | Promise<void>) {\n const panel = useContext(ChatSendContext);\n const pending = useRef(false);\n const mounted = useRef(true);\n useLayoutEffect(() => {\n mounted.current = true;\n return () => { mounted.current = false; };\n }, []);\n const [sending, setSending] = useState(false);\n const [error, setError] = useState<string>();\n const submit = async (text: string): Promise<boolean> => {\n if (pending.current) return false;\n pending.current = true;\n setSending(true);\n setError(undefined);\n try {\n await onSend(text);\n if (!mounted.current) return false;\n panel?.onSent();\n return true;\n } catch (failure) {\n if (mounted.current) setError(failure instanceof Error ? failure.message : String(failure));\n return false;\n } finally {\n pending.current = false;\n if (mounted.current) setSending(false);\n }\n };\n return { submit, sending, error };\n}\n", "import { createContext, ReactNode, useContext } from \"react\";\nimport type { CodeBlockOptions } from \"./options\";\nimport { defaultTexts, type ChatTexts } from \"./texts\";\nimport { ActionButton, copyText } from \"./MessageActions\";\n\nconst CodeBlockContext = createContext<{ options?: CodeBlockOptions; texts?: Partial<ChatTexts> }>({});\n\nexport function MarkdownCodeBlocks({ children, options, texts }: {\n children: ReactNode;\n options?: CodeBlockOptions;\n texts?: Partial<ChatTexts>;\n}) {\n return <CodeBlockContext.Provider value={{ options, texts }}>{children}</CodeBlockContext.Provider>;\n}\n\nfunction CodeBlock({ text }: { text: string }) {\n const { options, texts } = useContext(CodeBlockContext);\n const labels = { ...defaultTexts, ...texts };\n const content = <pre style={{\n whiteSpace: options?.wrap ? \"pre-wrap\" : undefined,\n overflowWrap: options?.wrap ? \"anywhere\" : undefined,\n maxHeight: options?.maxHeight,\n overflowY: options?.maxHeight === undefined ? undefined : \"auto\",\n }}><code>{text}</code></pre>;\n return options?.showCopyButton ? <div className=\"qsl-code-block\">\n <ActionButton label={labels.copyCode} successLabel={labels.copied} onClick={() => copyText(text, labels.copyFailed)} />\n {content}\n </div> : content;\n}\n\n/**\n * Schlanker Markdown-Renderer ohne Abh\u00E4ngigkeit: \u00DCberschriften, **fett**, *kursiv*,\n * `code`, Links, Listen, Blockquotes, Code-Bl\u00F6cke und Tabellen. Bewusst sicher (reines\n * React, kein dangerouslySetInnerHTML) und streaming-robust: zeilenbasiert, unvollst\u00E4ndige\n * Bl\u00F6cke werden so weit gerendert wie vorhanden.\n */\n/** true = der Host hat den Link behandelt, der Browser folgt ihm nicht. */\nexport type LinkClickHandler = (href: string, label: string) => boolean;\n\nconst LinkClickContext = createContext<LinkClickHandler | undefined>(undefined);\n\n/** Faengt Klicks auf Markdown-Links im Teilbaum ab, z.B. fuer eigene Ziele der Gastseite. */\nexport function MarkdownLinks({ children, onLinkClick }: { children: ReactNode; onLinkClick?: LinkClickHandler }) {\n return <LinkClickContext.Provider value={onLinkClick}>{children}</LinkClickContext.Provider>;\n}\n\nfunction MarkdownLink({ href, label }: { href: string; label: string }) {\n const onLinkClick = useContext(LinkClickContext);\n return (\n <a\n href={href}\n onClick={(event) => {\n if (onLinkClick?.(href, label)) {\n event.preventDefault();\n }\n }}\n rel=\"noreferrer\"\n target=\"_blank\"\n >\n {label}\n </a>\n );\n}\n\nexport function Markdown({ text }: { text: string }) {\n const lines = text.split(\"\\n\");\n const blocks: ReactNode[] = [];\n let i = 0;\n let key = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n const fence = line.match(/^\\s*```(\\w*)\\s*$/);\n if (fence) {\n const body: string[] = [];\n i++;\n while (i < lines.length && !/^\\s*```\\s*$/.test(lines[i])) {\n body.push(lines[i]);\n i++;\n }\n if (i < lines.length) {\n i++;\n }\n blocks.push(\n <CodeBlock key={key++} text={body.join(\"\\n\")} />,\n );\n continue;\n }\n\n if (line.includes(\"|\") && i + 1 < lines.length && isTableDivider(lines[i + 1])) {\n const header = splitTableRow(line);\n i += 2;\n const rows: string[][] = [];\n while (i < lines.length && lines[i].includes(\"|\") && lines[i].trim() !== \"\") {\n rows.push(splitTableRow(lines[i]));\n i++;\n }\n blocks.push(\n <div className=\"qsl-md-scroll\" key={key++}>\n <table>\n <thead>\n <tr>\n {header.map((cell, ci) => (\n <th key={ci}>{renderInline(cell, `th${key}_${ci}`)}</th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.map((row, ri) => (\n <tr key={ri}>\n {header.map((_, ci) => (\n <td key={ci}>{renderInline(row[ci] ?? \"\", `td${key}_${ri}_${ci}`)}</td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>,\n );\n continue;\n }\n\n const heading = line.match(/^(#{1,4})\\s+(.*)$/);\n if (heading) {\n const level = heading[1].length;\n blocks.push(\n level === 1 ? (\n <h3 key={key++}>{renderInline(heading[2], `h${key}`)}</h3>\n ) : (\n <h4 key={key++}>{renderInline(heading[2], `h${key}`)}</h4>\n ),\n );\n i++;\n continue;\n }\n\n const quote = line.match(/^\\s*>\\s?(.*)$/);\n if (quote) {\n blocks.push(<blockquote key={key++}>{renderInline(quote[1], `q${key}`)}</blockquote>);\n i++;\n continue;\n }\n\n const bullet = line.match(/^\\s*[-*]\\s+(.*)$/);\n if (bullet) {\n blocks.push(\n <div className=\"qsl-md-bullet\" key={key++}>\n <span>&bull;</span>\n <span>{renderInline(bullet[1], `l${key}`)}</span>\n </div>,\n );\n i++;\n continue;\n }\n\n const numbered = line.match(/^\\s*(\\d+)\\.\\s+(.*)$/);\n if (numbered) {\n blocks.push(\n <div className=\"qsl-md-bullet\" key={key++}>\n <span>{numbered[1]}.</span>\n <span>{renderInline(numbered[2], `l${key}`)}</span>\n </div>,\n );\n i++;\n continue;\n }\n\n if (line.trim() === \"\") {\n blocks.push(<div className=\"qsl-md-gap\" key={key++} />);\n i++;\n continue;\n }\n\n blocks.push(<p key={key++}>{renderInline(line, `l${key}`)}</p>);\n i++;\n }\n\n return <div className=\"qsl-md\">{blocks}</div>;\n}\n\nfunction renderInline(text: string, keyPrefix: string): ReactNode[] {\n const out: ReactNode[] = [];\n const pattern = /\\[([^\\]]+)\\]\\(([^)]+)\\)|\\*\\*([^*]+)\\*\\*|\\*([^*]+)\\*|`([^`]+)`/g;\n let last = 0;\n let match: RegExpExecArray | null;\n let i = 0;\n\n while ((match = pattern.exec(text)) !== null) {\n if (match.index > last) {\n out.push(text.slice(last, match.index));\n }\n if (match[1] !== undefined) {\n out.push(<MarkdownLink href={match[2]} key={`${keyPrefix}a${i}`} label={match[1]} />);\n } else if (match[3] !== undefined) {\n out.push(<strong key={`${keyPrefix}b${i}`}>{match[3]}</strong>);\n } else if (match[4] !== undefined) {\n out.push(<em key={`${keyPrefix}i${i}`}>{match[4]}</em>);\n } else if (match[5] !== undefined) {\n out.push(<code key={`${keyPrefix}c${i}`}>{match[5]}</code>);\n }\n last = match.index + match[0].length;\n i++;\n }\n if (last < text.length) {\n out.push(text.slice(last));\n }\n return out;\n}\n\n/** Dieselbe Syntax wie der Renderer, als Klartext ohne Markup, etwa f\u00FCr Screenreader-Ansagen. */\nexport function markdownPlainText(text: string): string {\n return text\n .split(\"\\n\")\n .filter((line) => !/^\\s*```\\w*\\s*$/.test(line) && !isTableDivider(line))\n .map((line) => (line.trim().startsWith(\"|\") ? splitTableRow(line).join(\", \") : line)\n .replace(/^(#{1,4})\\s+/, \"\")\n .replace(/^\\s*>\\s?/, \"\")\n .replace(/^\\s*[-*]\\s+/, \"\")\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)|\\*\\*([^*]+)\\*\\*|\\*([^*]+)\\*|`([^`]+)`/g, (_, link, _href, fett, kursiv, code) => link ?? fett ?? kursiv ?? code)\n .trim())\n .filter((line) => line !== \"\")\n .join(\"\\n\");\n}\n\nfunction splitTableRow(line: string): string[] {\n let row = line.trim();\n if (row.startsWith(\"|\")) {\n row = row.slice(1);\n }\n if (row.endsWith(\"|\")) {\n row = row.slice(0, -1);\n }\n return row.split(\"|\").map((cell) => cell.trim());\n}\n\nfunction isTableDivider(line: string): boolean {\n return /^\\s*\\|?\\s*:?-{1,}:?\\s*(\\|\\s*:?-{1,}:?\\s*)*\\|?\\s*$/.test(line) && line.includes(\"-\");\n}\n", "const abstandMs = 400;\nconst hoechstensWartend = 5;\n\nlet region: HTMLElement | undefined;\nlet wartend: readonly string[] = [];\nlet laeuft = false;\n\nfunction ansageRegion(): HTMLElement {\n if (region?.isConnected) {\n return region;\n }\n const element = document.createElement(\"div\");\n element.setAttribute(\"role\", \"status\");\n element.setAttribute(\"aria-live\", \"polite\");\n element.setAttribute(\"aria-atomic\", \"true\");\n Object.assign(element.style, {\n position: \"absolute\",\n width: \"1px\",\n height: \"1px\",\n margin: \"-1px\",\n padding: \"0\",\n border: \"0\",\n overflow: \"hidden\",\n clipPath: \"inset(50%)\",\n whiteSpace: \"nowrap\",\n });\n document.body.append(element);\n region = element;\n return element;\n}\n\nfunction naechste(): void {\n if (wartend.length === 0) {\n laeuft = false;\n return;\n }\n if (document.visibilityState === \"hidden\") {\n document.addEventListener(\"visibilitychange\", naechste, { once: true });\n return;\n }\n const [text, ...rest] = wartend;\n wartend = rest;\n const ziel = ansageRegion();\n ziel.textContent = ziel.textContent === text ? `${text}\u00A0` : text;\n window.setTimeout(naechste, abstandMs);\n}\n\n/** Sagt Text \u00FCber eine gemeinsame, versteckte Live-Region an: gedrosselt, und bei verstecktem Tab angehalten. */\nexport function announce(text: string): void {\n const inhalt = text.trim();\n if (!inhalt || typeof document === \"undefined\") {\n return;\n }\n wartend = [...wartend, inhalt].slice(-hoechstensWartend);\n if (laeuft) {\n return;\n }\n laeuft = true;\n ansageRegion();\n window.setTimeout(naechste, abstandMs);\n}\n", "import { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Message, prettyJson } from \"./types\";\nimport { IconSpark, IconTool, IconX } from \"./icons\";\nimport { ChatTexts } from \"./texts\";\n\nexport function StepPopover({\n message,\n position,\n texts,\n toolArgumentsText,\n onClose,\n}: {\n message: Message;\n position: { x: number; y: number };\n texts: ChatTexts;\n toolArgumentsText: (tool: NonNullable<Message[\"tool\"]>) => string;\n onClose: () => void;\n}) {\n const popover = useRef<HTMLDivElement>(null);\n const [placement, setPlacement] = useState<{ left: number; top: number }>();\n\n useLayoutEffect(() => {\n const element = popover.current;\n if (!element) {\n return;\n }\n const margin = 16;\n const gap = 10;\n const bounds = element.getBoundingClientRect();\n const preferredLeft = position.x + gap;\n const preferredTop = position.y + gap;\n const left =\n preferredLeft + bounds.width <= window.innerWidth - margin\n ? preferredLeft\n : position.x - bounds.width - gap;\n const top =\n preferredTop + bounds.height <= window.innerHeight - margin\n ? preferredTop\n : position.y - bounds.height - gap;\n setPlacement({\n left: Math.max(margin, Math.min(left, window.innerWidth - bounds.width - margin)),\n top: Math.max(margin, Math.min(top, window.innerHeight - bounds.height - margin)),\n });\n }, [message.text, message.tool?.result, position]);\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onClose();\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [onClose]);\n\n // Klick daneben schliesst - auch wenn der Host etwas ueber den Backdrop legt.\n useEffect(() => {\n const handlePointerDown = (event: PointerEvent) => {\n if (!popover.current?.contains(event.target as Node)) {\n onClose();\n }\n };\n document.addEventListener(\"pointerdown\", handlePointerDown, true);\n return () => document.removeEventListener(\"pointerdown\", handlePointerDown, true);\n }, [onClose]);\n\n const tool = message.tool;\n const title = message.role === \"thinking\" ? texts.thinkingTitle : texts.toolTitle;\n\n return createPortal(\n <>\n <div className=\"qsl-popover-backdrop\" onClick={onClose} />\n <div\n aria-label={title}\n className=\"qsl-popover\"\n ref={popover}\n role=\"dialog\"\n style={{\n left: placement?.left ?? position.x,\n top: placement?.top ?? position.y,\n visibility: placement ? \"visible\" : \"hidden\",\n }}\n >\n <div className=\"qsl-popover__head\">\n {message.role === \"thinking\" ? (\n <IconSpark className=\"qsl-popover__icon\" />\n ) : (\n <IconTool className={tool?.isError ? \"qsl-popover__icon qsl-popover__icon--error\" : \"qsl-popover__icon\"} />\n )}\n <span className=\"qsl-popover__title\">{title}</span>\n <button aria-label={texts.close} className=\"qsl-popover__close\" onClick={onClose} title={texts.close} type=\"button\">\n <IconX />\n </button>\n </div>\n <div className=\"qsl-popover__body\">\n {message.role === \"thinking\" ? (\n <div className=\"qsl-popover__thinking\">{message.text}</div>\n ) : tool ? (\n <div className=\"qsl-popover__sections\">\n <div className=\"qsl-popover__toolname\">{message.text}</div>\n <PopoverSection label={texts.argumentsLabel} value={toolArgumentsText(tool)} />\n {tool.result === undefined ? (\n <div className=\"qsl-popover__running\">{texts.toolStillRunning}</div>\n ) : (\n <PopoverSection error={tool.isError} label={texts.resultLabel} value={prettyJson(tool.result)} />\n )}\n </div>\n ) : null}\n </div>\n </div>\n </>,\n document.body,\n );\n}\n\nfunction PopoverSection({ label, value, error = false }: { label: string; value: string; error?: boolean }) {\n return (\n <section>\n <h3>{label}</h3>\n <pre className={error ? \"qsl-popover__pre qsl-popover__pre--error\" : \"qsl-popover__pre\"}>{value}</pre>\n </section>\n );\n}\n", "import { ReactNode } from \"react\";\n\ninterface IconProps {\n size?: number;\n className?: string;\n}\n\nfunction Svg({ size = 14, className, children }: IconProps & { children: ReactNode }) {\n return (\n <svg\n aria-hidden=\"true\"\n className={className}\n fill=\"none\"\n height={size}\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n viewBox=\"0 0 24 24\"\n width={size}\n >\n {children}\n </svg>\n );\n}\n\nexport function IconSend(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M22 2 11 13\" />\n <path d=\"M22 2 15 22 11 13 2 9Z\" />\n </Svg>\n );\n}\n\nexport function IconStop(props: IconProps) {\n return (\n <Svg {...props}>\n <rect fill=\"currentColor\" height={12} rx={2} stroke=\"none\" width={12} x={6} y={6} />\n </Svg>\n );\n}\n\nexport function IconX(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </Svg>\n );\n}\n\nexport function IconChevronDown(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"m6 9 6 6 6-6\" />\n </Svg>\n );\n}\n\nexport function IconChevronRight(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"m9 18 6-6-6-6\" />\n </Svg>\n );\n}\n\nexport function IconLayers(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"m12 2 10 5-10 5L2 7Z\" />\n <path d=\"m2 17 10 5 10-5\" />\n <path d=\"m2 12 10 5 10-5\" />\n </Svg>\n );\n}\n\nexport function IconCheck(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M20 6 9 17l-5-5\" />\n </Svg>\n );\n}\n\nexport function IconSpark(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M12 3l1.9 6.1L20 11l-6.1 1.9L12 19l-1.9-6.1L4 11l6.1-1.9Z\" />\n </Svg>\n );\n}\n\nexport function IconClock(props: IconProps) {\n return (\n <Svg {...props}>\n <circle cx={12} cy={12} r={9} />\n <path d=\"M12 7v5l3 2\" />\n </Svg>\n );\n}\n\nexport function IconTool(props: IconProps) {\n return (\n <Svg {...props}>\n <path d=\"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z\" />\n </Svg>\n );\n}\n", "import { useState } from \"react\";\nimport { Question } from \"./types\";\nimport { IconCheck } from \"./icons\";\nimport type { ChatTexts } from \"./texts\";\n\n/**\n * R\u00FCckfrage-Karte: Optionen untereinander, wahlweise Einzel- oder Mehrfachauswahl\n * (question.multi), dazu immer eine freie Antwortzeile. Nach der Antwort nur noch Beleg.\n */\nexport function QuestionCard({\n text,\n question,\n texts,\n onAnswer,\n}: {\n text: string;\n question: Question;\n texts: ChatTexts;\n onAnswer: (text: string) => void;\n}) {\n const [gewaehlt, setGewaehlt] = useState<string[]>([]);\n const [frei, setFrei] = useState(\"\");\n\n if (question.answer !== undefined) {\n return (\n <div className=\"qsl-question\">\n <div className=\"qsl-question__text\">{text}</div>\n <div className=\"qsl-question__answered\">\n <IconCheck className=\"qsl-question__check\" size={12} />\n {question.answer}\n </div>\n </div>\n );\n }\n\n const umschalten = (option: string) =>\n setGewaehlt((bisher) =>\n bisher.includes(option) ? bisher.filter((o) => o !== option) : [...bisher, option]);\n\n const freiSenden = () => {\n const wert = frei.trim();\n if (wert) onAnswer(wert);\n };\n\n return (\n <div className=\"qsl-question\">\n <div className=\"qsl-question__text\">{text}</div>\n <div className=\"qsl-question__options\">\n {question.options.map((option) =>\n question.multi ? (\n <button\n aria-pressed={gewaehlt.includes(option)}\n className={\n gewaehlt.includes(option)\n ? \"qsl-question__option qsl-question__option--gewaehlt\"\n : \"qsl-question__option\"\n }\n key={option}\n onClick={() => umschalten(option)}\n type=\"button\"\n >\n <span className=\"qsl-question__kasten\">\n {gewaehlt.includes(option) && <IconCheck size={10} />}\n </span>\n {option}\n </button>\n ) : (\n <button className=\"qsl-question__option\" key={option} onClick={() => onAnswer(option)} type=\"button\">\n {option}\n </button>\n ),\n )}\n </div>\n {question.multi && (\n <button\n className=\"qsl-question__uebernehmen\"\n disabled={gewaehlt.length === 0}\n onClick={() => onAnswer(gewaehlt.join(\"; \"))}\n type=\"button\"\n >\n {texts.questionSubmit}\n </button>\n )}\n <div className=\"qsl-question__frei\">\n <input\n className=\"qsl-field qsl-question__frei-feld\"\n onChange={(event) => setFrei(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" && !event.nativeEvent.isComposing) freiSenden();\n }}\n placeholder={texts.questionPlaceholder}\n value={frei}\n />\n <button\n className=\"qsl-question__frei-senden\"\n disabled={frei.trim() === \"\"}\n onClick={freiSenden}\n type=\"button\"\n >\n {texts.questionAnswer}\n </button>\n </div>\n </div>\n );\n}\n", "import { useEffect, useState } from \"react\";\n\nconst SPUR = 13;\nconst GRUNDTAKT_MS = 90;\nconst SZENENWECHSEL_MS = 2600;\n\n/** Eine Zelle je Figur: Emoji und Satzzeichen teilen sich kein Raster, geschobener Text ruckelt. */\nfunction bahn(figuren: Record<number, string>, breite = SPUR): string[] {\n return Array.from({ length: breite }, (_, x) => figuren[x] ?? \" \");\n}\n\ninterface Szene {\n id: string;\n takt: number;\n laufend?: true;\n zeichne: (schritt: number) => string | string[];\n}\n\n/**\n * Kleine Szenen, in denen etwas Erkennbares passiert - der Zustand aendert sich sichtbar,\n * statt dass nur eine Figur vorbeilaeuft. Szenen mit Bewegung geben ihre Bahn als Zellen\n * zurueck, alle anderen als schlichten Text.\n */\nconst SZENEN: Szene[] = [\n {\n id: \"denken\",\n takt: 2,\n zeichne: (schritt) => {\n const takt = schritt % 10;\n if (takt >= 8) return \"\\u{1F929}\\u{1F4A1}\";\n return \"\\u{1F914}\" + \"\\u{1F4AD}\".repeat(Math.min(takt, 3));\n },\n },\n {\n // Fliegt nach rechts und zieht ihren Schweif hinterher.\n id: \"rakete\",\n takt: 2,\n laufend: true,\n zeichne: (schritt) => {\n const x = schritt % SPUR;\n return bahn({ [x - 2]: \"\u00B7\", [x - 1]: \"\\u{1F4A8}\", [x]: \"\\u{1F680}\" });\n },\n },\n {\n // Die Punkte bleiben stehen und werden einzeln gefressen.\n id: \"pacman\",\n takt: 2,\n laufend: true,\n zeichne: (schritt) => {\n const x = schritt % SPUR;\n const figuren: Record<number, string> = {};\n for (let i = x + 1; i < SPUR; i++) {\n figuren[i] = \"\u00B7\";\n }\n figuren[x] = schritt % 2 === 0 ? \"\\u{1F7E1}\" : \"\\u{1F315}\";\n return bahn(figuren);\n },\n },\n {\n // Aus einem Samen wird ein Baum, dann von vorn.\n id: \"wachsen\",\n takt: 2,\n zeichne: (schritt) => {\n const stufen = [\"\\u{1F331}\", \"\\u{1F331}\", \"\\u{1F33F}\", \"\\u{1F33F}\", \"\\u{1F343}\", \"\\u{1F333}\", \"\\u{1F333}\", \"\\u{1F333}\"];\n return stufen[schritt % stufen.length];\n },\n },\n {\n // Das Ei bekommt Risse, das Kueken schluepft.\n id: \"schluepfen\",\n takt: 2,\n zeichne: (schritt) => {\n const takt = schritt % 12;\n if (takt < 4) return \"\\u{1F95A}\";\n if (takt < 6) return \"\\u{1F95A}\u2728\";\n if (takt < 9) return \"\\u{1F423}\";\n return \"\\u{1F425}\";\n },\n },\n {\n // Morse-artiges Signal, das sich zu einem OK aufloest.\n id: \"signal\",\n takt: 2,\n zeichne: (schritt) => {\n const takt = schritt % 14;\n if (takt >= 11) return \"\\u{1F4E1} OK\";\n const muster = [\"\u00B7\", \"\u00B7\u00B7\", \"\u00B7-\", \"-\u00B7\", \"\u00B7\u00B7-\", \"-\u00B7\u00B7\"];\n return \"\\u{1F4E1} \" + muster[takt % muster.length];\n },\n },\n {\n // Sanduhr: der Sand laeuft durch, dann wird gedreht.\n id: \"sanduhr\",\n takt: 2,\n zeichne: (schritt) => {\n const takt = schritt % 12;\n const koerner = \"\u00B7\".repeat(Math.max(0, 5 - Math.floor(takt / 2)));\n return (takt < 10 ? \"\u23F3\" : \"\u231B\") + \" \" + koerner;\n },\n },\n {\n // Ei, Kueken, Henne - und die legt das naechste Ei.\n id: \"huhn-kreislauf\",\n takt: 3,\n zeichne: (schritt) => {\n const takt = schritt % 16;\n if (takt < 3) return \"\\u{1F95A}\";\n if (takt < 5) return \"\\u{1F95A}\u2728\";\n if (takt < 8) return \"\\u{1F423}\";\n if (takt < 11) return \"\\u{1F424}\";\n if (takt < 14) return \"\\u{1F414}\";\n return \"\\u{1F414}\\u{1F95A}\";\n },\n },\n {\n // Hut, Funken - und das Kaninchen tuermt.\n id: \"zauberhut\",\n takt: 3,\n zeichne: (schritt) => {\n const takt = schritt % 14;\n if (takt < 4) return \"\\u{1F3A9}\";\n if (takt < 7) return \"\\u{1F3A9}\u2728\";\n if (takt < 11) return \"\\u{1F3A9}\\u{1F407}\";\n return \"\\u{1F407}\\u{1F4A8}\";\n },\n },\n {\n // Rot, Gelb, Gruen - und ab.\n id: \"ampel\",\n takt: 3,\n zeichne: (schritt) => {\n const takt = schritt % 12;\n if (takt < 4) return \"\\u{1F534}\";\n if (takt < 6) return \"\\u{1F7E1}\";\n if (takt < 8) return \"\\u{1F7E2}\";\n return \"\\u{1F697}\\u{1F4A8}\";\n },\n },\n {\n // Klingeln, verschlafen, losrennen.\n id: \"wecker\",\n takt: 2,\n zeichne: (schritt) => {\n const takt = schritt % 14;\n if (takt < 5) return takt % 2 === 0 ? \"\u23F0\" : \"\\u{1F514}\";\n if (takt < 8) return \"\\u{1F634}\";\n if (takt < 10) return \"\\u{1F633}\";\n return \"\\u{1F3C3}\\u{1F4A8}\";\n },\n },\n {\n // Schnecke kriecht zur Flagge - und feiert.\n id: \"schnecke\",\n takt: 4,\n zeichne: (schritt) => {\n const takt = schritt % 8;\n if (takt < 5) return bahn({ [takt]: \"\\u{1F40C}\", 4: \"\\u{1F3C1}\" }, 5);\n return bahn({ 4: \"\\u{1F389}\" }, 5);\n },\n },\n];\n\nexport interface WorkingScenesProps {\n /** Text fuer Screenreader, Default \"Arbeitet ...\". */\n label?: string;\n}\n\n/**\n * Der Default-Working-Indikator: zufaellig rotierende Mini-Szenen. Zufaellige Reihenfolge\n * und Startphase, damit dieselben Szenen nie wie eine Schleife wirken. Ueber die\n * working-Prop von ChatMessages laesst er sich komplett ersetzen.\n */\nexport function WorkingScenes({ label = \"Arbeitet ...\" }: WorkingScenesProps) {\n const [szene, setSzene] = useState(() => SZENEN[Math.floor(Math.random() * SZENEN.length)]);\n const [versatz, setVersatz] = useState(() => Math.floor(Math.random() * 20));\n const [frameTick, setFrameTick] = useState(0);\n\n useEffect(() => {\n const timer = window.setInterval(() => {\n setSzene((bisher) => {\n const andere = SZENEN.filter((s) => s.id !== bisher.id);\n return andere[Math.floor(Math.random() * andere.length)];\n });\n setVersatz(Math.floor(Math.random() * 20));\n setFrameTick(0);\n }, SZENENWECHSEL_MS);\n return () => window.clearInterval(timer);\n }, []);\n\n useEffect(() => {\n const timer = window.setInterval(() => setFrameTick((value) => value + 1), GRUNDTAKT_MS);\n return () => window.clearInterval(timer);\n }, []);\n\n const bild = szene.zeichne(Math.floor(frameTick / szene.takt) + (szene.laufend ? versatz : 0));\n return (\n <div aria-label={label} className=\"qsl-working\" role=\"img\">\n <span aria-hidden=\"true\" className=\"qsl-working__stage\" key={szene.id}>\n <span className=\"qsl-working__character\">\n {typeof bild === \"string\"\n ? bild\n : bild.map((zelle, i) => (\n <span className=\"qsl-working__cell\" key={i}>\n {zelle}\n </span>\n ))}\n </span>\n </span>\n </div>\n );\n}\n", "import { useEffect, useLayoutEffect, useMemo, useRef, type ReactNode, type Ref } from \"react\";\nimport { ChatSendContext } from \"./ChatSendContext\";\nimport { appearanceStyle, type ChatAppearance } from \"./options\";\n\n/**\n * Verlauf mit ueberlagerter Eingabe. Der Rahmen misst die Eingabe selbst und\n * gibt dem Verlauf den noetigen Fussraum, damit kein Host Innenmasse setzen muss.\n */\nexport function ChatPanel({\n children,\n composer,\n className,\n nodeRef,\n appearance,\n scrollOnSend = false,\n}: {\n children: ReactNode;\n /** Die Eingabe; sie liegt ueber dem Verlauf, nicht darunter. */\n composer?: ReactNode;\n className?: string;\n nodeRef?: Ref<HTMLDivElement>;\n appearance?: ChatAppearance;\n scrollOnSend?: boolean;\n}) {\n const jump = useRef<(() => void) | undefined>(undefined);\n const scrollOnSendRef = useRef(scrollOnSend);\n useLayoutEffect(() => { scrollOnSendRef.current = scrollOnSend; }, [scrollOnSend]);\n const sendContext = useMemo(() => ({\n onSent: () => { if (scrollOnSendRef.current) jump.current?.(); },\n registerJump: (callback: () => void) => {\n jump.current = callback;\n return () => { if (jump.current === callback) jump.current = undefined; };\n },\n }), []);\n const wurzel = useRef<HTMLDivElement>(null);\n const eingabe = useRef<HTMLDivElement>(null);\n const mitEingabe = composer !== undefined;\n\n useEffect(() => {\n const element = eingabe.current;\n const rahmen = wurzel.current;\n if (!rahmen) {\n return;\n }\n if (!element) {\n rahmen.style.removeProperty(\"--qsl-composer-height\");\n return;\n }\n const messen = () => rahmen.style.setProperty(\"--qsl-composer-height\", `${element.offsetHeight}px`);\n const beobachter = new ResizeObserver(messen);\n beobachter.observe(element);\n messen();\n return () => beobachter.disconnect();\n }, [mitEingabe]);\n\n return (\n <ChatSendContext.Provider value={sendContext}>\n <div\n className={className ? `qsl-chat-panel ${className}` : \"qsl-chat-panel\"}\n style={appearanceStyle(appearance)}\n ref={(element) => {\n wurzel.current = element;\n if (typeof nodeRef === \"function\") {\n nodeRef(element);\n } else if (nodeRef) {\n nodeRef.current = element;\n }\n }}\n >\n {children}\n {composer !== undefined && (\n <div className=\"qsl-chat-panel__composer\" ref={eingabe}>\n {composer}\n </div>\n )}\n </div>\n </ChatSendContext.Provider>\n );\n}\n", "import { ChatTexts, defaultTexts } from \"./texts\";\nimport { IconClock } from \"./icons\";\n\nexport function TimestampSwitch({\n showTimestamps,\n onChange,\n collapsible = true,\n texts,\n className,\n}: {\n showTimestamps: boolean;\n onChange: (showTimestamps: boolean) => void;\n collapsible?: boolean;\n texts?: Partial<ChatTexts>;\n className?: string;\n}) {\n const label = texts?.timestamps ?? defaultTexts.timestamps;\n const classes = showTimestamps ? \"qsl-icon-button qsl-icon-button--active\" : \"qsl-icon-button\";\n return (\n <button\n aria-label={label}\n aria-pressed={showTimestamps}\n className={className ? `${classes} ${className}` : classes}\n onClick={() => onChange(!showTimestamps)}\n title={label}\n type=\"button\"\n >\n <IconClock />\n <span className={collapsible ? \"qsl-collapsible\" : undefined}>{label}</span>\n </button>\n );\n}\n", "import { KeyboardEvent, ReactNode, useCallback, useEffect, useRef, useState } from \"react\";\nimport { ChatTexts, defaultTexts } from \"./texts\";\nimport { isSendKey, useChatSubmit } from \"./ChatSendContext\";\nimport type { SendShortcut } from \"./options\";\nimport { IconSend, IconStop } from \"./icons\";\n\n// Unter dieser Panel-Breite klappen Beschriftungen mit .qsl-collapsible zu ihren Symbolen.\nconst COMPACT_WIDTH_PX = 480;\n\n/** Ein Toolbar-Knopf, deklarativ: Symbol, Text oder beides - plus Klick-Handler. */\nexport interface ToolbarAction {\n icon?: ReactNode;\n label?: string;\n title?: string;\n disabled?: boolean;\n active?: boolean;\n onClick: () => void;\n}\n\n/**\n * Die Eingabe-Karte: rahmenlose Textarea oben, Toolbar unter einer Haarlinie. Eigene\n * Kn\u00F6pfe kommen deklarativ \u00FCber `actions` oder frei \u00FCber die Slots links/rechts; im Lauf\n * bleibt der Stop-Knopf sichtbar, und Tippen zeigt daneben den Senden-Knopf, der zum\n * Dazwischenfunken wird. `rows` bestimmt die Starth\u00F6he; mit `maxRows` w\u00E4chst die Textarea\n * mit dem Inhalt bis zu dieser Zeilenzahl und scrollt danach.\n */\nexport function ChatInputToolbar({\n onSend,\n onStop,\n running = false,\n disabled = false,\n rows = 3,\n maxRows,\n actions,\n toolbarLeft,\n toolbarRight,\n texts,\n sendShortcut = \"enter\",\n}: {\n onSend: (text: string) => void | Promise<void>;\n onStop?: () => void;\n running?: boolean;\n disabled?: boolean;\n rows?: number;\n maxRows?: number;\n actions?: ToolbarAction[];\n toolbarLeft?: ReactNode;\n toolbarRight?: ReactNode;\n texts?: Partial<ChatTexts>;\n sendShortcut?: SendShortcut;\n}) {\n const alleTexte = { ...defaultTexts, ...texts };\n const [draft, setDraft] = useState(\"\");\n const { submit, sending, error } = useChatSubmit(onSend);\n const rootRef = useRef<HTMLDivElement>(null);\n const eingabeRef = useRef<HTMLTextAreaElement>(null);\n const [compact, setCompact] = useState(false);\n\n // Auto-Wachstum: Hoehe folgt dem Inhalt zwischen rows und maxRows, danach scrollt die Textarea.\n const applyAutoGrow = useCallback(() => {\n const element = eingabeRef.current;\n if (!element || maxRows === undefined) {\n return;\n }\n const stil = getComputedStyle(element);\n const zeilenhoehe = Number.parseFloat(stil.lineHeight) || Number.parseFloat(stil.fontSize) * 1.4;\n const polster = Number.parseFloat(stil.paddingTop) + Number.parseFloat(stil.paddingBottom);\n const maximum = zeilenhoehe * Math.max(maxRows, rows) + polster;\n element.style.height = \"auto\";\n const inhalt = element.scrollHeight;\n element.style.height = `${Math.min(inhalt, maximum)}px`;\n element.style.overflowY = inhalt > maximum ? \"auto\" : \"hidden\";\n }, [maxRows, rows]);\n\n useEffect(() => {\n applyAutoGrow();\n }, [draft, applyAutoGrow]);\n\n // Hosts may lay the composer out a frame later; re-measure once the width settles.\n useEffect(() => {\n const element = eingabeRef.current;\n if (!element || maxRows === undefined) {\n return;\n }\n let lastWidth = element.clientWidth;\n const observer = new ResizeObserver(() => {\n if (element.clientWidth !== lastWidth) {\n lastWidth = element.clientWidth;\n applyAutoGrow();\n }\n });\n observer.observe(element);\n return () => observer.disconnect();\n }, [maxRows, applyAutoGrow]);\n\n // Panel-Breite statt Viewport-Breite: die Chat-Spalte kann im Host beliebig schmal sein.\n useEffect(() => {\n const element = rootRef.current;\n if (!element) {\n return;\n }\n const update = () => setCompact(element.clientWidth < COMPACT_WIDTH_PX);\n update();\n const beobachter = new ResizeObserver(update);\n beobachter.observe(element);\n return () => beobachter.disconnect();\n }, []);\n\n const hatText = draft.trim().length > 0;\n\n const send = async () => {\n const text = draft.trim();\n if (!text || disabled || sending) {\n return;\n }\n if (await submit(text)) setDraft(current => current === draft ? \"\" : current);\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n if (isSendKey(event, sendShortcut)) {\n event.preventDefault();\n if (!event.repeat) void send();\n }\n };\n\n return (\n <div className={compact ? \"qsl-input-card qsl-input-card--compact\" : \"qsl-input-card\"} ref={rootRef}>\n {error && <p className=\"qsl-action-error\" role=\"alert\">{error}</p>}\n <textarea\n aria-label={alleTexte.placeholder}\n disabled={disabled}\n onChange={(event) => setDraft(event.target.value)}\n onKeyDown={onKeyDown}\n placeholder={running ? alleTexte.steeringPlaceholder : alleTexte.placeholder}\n ref={eingabeRef}\n rows={rows}\n value={draft}\n />\n <div className=\"qsl-input-card__toolbar\">\n <div className=\"qsl-input-card__left\">\n {actions?.map((action, index) => (\n <button\n className={action.active ? \"qsl-icon-button qsl-icon-button--active\" : \"qsl-icon-button\"}\n disabled={action.disabled}\n key={index}\n onClick={action.onClick}\n title={action.title ?? action.label}\n type=\"button\"\n >\n {action.icon}\n {action.label && <span className={action.icon ? \"qsl-collapsible\" : undefined}>{action.label}</span>}\n </button>\n ))}\n {toolbarLeft}\n </div>\n <div className=\"qsl-input-card__right\">\n {toolbarRight}\n {running && onStop && (\n <button aria-label={alleTexte.stop} className=\"qsl-send qsl-send--stop\" onClick={onStop} title={alleTexte.stop} type=\"button\">\n <IconStop />\n </button>\n )}\n {(!running || !onStop || hatText) && (\n <button\n aria-label={alleTexte.send}\n className=\"qsl-send\"\n disabled={disabled || sending || !hatText}\n onClick={() => void send()}\n title={running ? alleTexte.sendIntoRun : alleTexte.send}\n type=\"button\"\n >\n <IconSend />\n </button>\n )}\n </div>\n </div>\n </div>\n );\n}\n", "import { DetailMode } from \"./types\";\nimport { ChatTexts, defaultTexts } from \"./texts\";\nimport { IconSpark } from \"./icons\";\n\nexport const DETAIL_MODES: readonly DetailMode[] = [\"off\", \"icons\", \"chips\", \"grouped\", \"compact\", \"full\"];\n\nconst TEXT_KEYS: Record<DetailMode, keyof ChatTexts> = {\n off: \"detailModeOff\",\n icons: \"detailModeIcons\",\n chips: \"detailModeChips\",\n grouped: \"detailModeGrouped\",\n compact: \"detailModeCompact\",\n full: \"detailModeFull\",\n};\n\nexport const detailModeLabel = (mode: DetailMode, texts?: Partial<ChatTexts>): string =>\n ({ ...defaultTexts, ...texts })[TEXT_KEYS[mode]];\n\n/**\n * Ein Knopf, der den Detailgrad der Denk- und Werkzeug-Schritte weiterschaltet. Die\n * Reihenfolge kommt aus `modes`, der aktuelle Wert steht als Beschriftung daneben.\n */\nexport function DetailModeSwitch({\n mode,\n onChange,\n modes = DETAIL_MODES,\n collapsible = true,\n texts,\n className,\n}: {\n mode: DetailMode;\n onChange: (mode: DetailMode) => void;\n /** Auswahl und Reihenfolge des Weiterschaltens; Default sind alle sechs Modi. */\n modes?: readonly DetailMode[];\n /** false = die Beschriftung bleibt auch in einer schmalen Eingabe-Karte stehen. */\n collapsible?: boolean;\n texts?: Partial<ChatTexts>;\n className?: string;\n}) {\n const alleTexte = { ...defaultTexts, ...texts };\n const aktuell = modes.indexOf(mode);\n const naechster = modes[(aktuell < 0 ? 0 : aktuell + 1) % modes.length];\n return (\n <button\n aria-label={`${alleTexte.detailModeTitle}: ${detailModeLabel(mode, texts)}`}\n className={className ? `qsl-icon-button ${className}` : \"qsl-icon-button\"}\n onClick={() => onChange(naechster)}\n title={`${alleTexte.detailModeTitle}: ${detailModeLabel(mode, texts)}`}\n type=\"button\"\n >\n <IconSpark size={14} />\n <span className={collapsible ? \"qsl-collapsible\" : undefined}>{detailModeLabel(mode, texts)}</span>\n </button>\n );\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["useCallback", "useContext", "useEffect", "useLayoutEffect", "useRef", "useState", "useEffect", "useRef", "useState", "useRef", "useState", "createContext", "useContext", "jsx", "jsxs", "createContext", "useContext", "useEffect", "useLayoutEffect", "useRef", "useState", "jsx", "jsxs", "Fragment", "jsx", "jsxs", "useRef", "useState", "useLayoutEffect", "useEffect", "useState", "jsx", "jsxs", "useState", "useEffect", "useState", "jsx", "Fragment", "jsx", "jsxs", "announce", "useRef", "useState", "useContext", "useLayoutEffect", "useEffect", "useCallback", "useEffect", "useLayoutEffect", "useMemo", "useRef", "jsx", "jsxs", "useRef", "useLayoutEffect", "useMemo", "useEffect", "jsx", "jsxs", "useCallback", "useEffect", "useRef", "useState", "jsx", "jsxs", "useState", "useRef", "useCallback", "useEffect", "jsx", "jsxs"]
7
+ }
package/options.d.ts ADDED
@@ -0,0 +1,42 @@
1
+ import type { CSSProperties, ReactNode } from "react";
2
+ import type { Message } from "./types";
3
+ export interface ChatAppearance {
4
+ fontSize?: CSSProperties["fontSize"];
5
+ lineHeight?: CSSProperties["lineHeight"];
6
+ messageGap?: CSSProperties["marginTop"];
7
+ denseMessageGap?: CSSProperties["marginTop"];
8
+ }
9
+ export interface TimestampOptions {
10
+ format?: "time" | "date-time" | "relative";
11
+ locale?: string;
12
+ timeZone?: string;
13
+ showDaySeparators?: boolean;
14
+ }
15
+ export interface CodeBlockOptions {
16
+ wrap?: boolean;
17
+ maxHeight?: CSSProperties["maxHeight"];
18
+ showCopyButton?: boolean;
19
+ }
20
+ export interface BubbleOptions {
21
+ variant?: "default" | "plain" | "bubbles";
22
+ maxWidth?: CSSProperties["maxWidth"];
23
+ userSide?: "start" | "end";
24
+ assistantSide?: "start" | "end";
25
+ showSender?: boolean;
26
+ senderLabel?: (message: Message) => string | undefined;
27
+ }
28
+ export interface MessageAction {
29
+ id: string;
30
+ label: string;
31
+ icon?: ReactNode;
32
+ disabled?: boolean;
33
+ onClick: (message: Message) => void | Promise<void>;
34
+ }
35
+ export interface MessageActionsOptions {
36
+ copy?: boolean | ((message: Message) => boolean);
37
+ edit?: (message: Message) => void | Promise<void>;
38
+ retry?: (message: Message) => void | Promise<void>;
39
+ custom?: (message: Message) => readonly MessageAction[];
40
+ }
41
+ export type SendShortcut = "enter" | "mod-enter";
42
+ export declare function appearanceStyle(appearance?: ChatAppearance): CSSProperties;
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "quassel",
3
+ "version": "0.1.0",
4
+ "description": "Composable chat building blocks for React: streaming transcript, steps, questions, inputs, CSS foundation and event contract",
5
+ "license": "MIT",
6
+ "author": "Ronald Schlenker",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/SchlenkR/quassel.git"
10
+ },
11
+ "homepage": "https://github.com/SchlenkR/quassel#readme",
12
+ "keywords": [
13
+ "chat",
14
+ "react",
15
+ "llm",
16
+ "agent",
17
+ "streaming",
18
+ "ui"
19
+ ],
20
+ "type": "module",
21
+ "sideEffects": [
22
+ "*.css"
23
+ ],
24
+ "exports": {
25
+ ".": {
26
+ "types": "./index.d.ts",
27
+ "default": "./index.js"
28
+ },
29
+ "./events": {
30
+ "types": "./events.d.ts",
31
+ "default": "./events.js"
32
+ },
33
+ "./server": {
34
+ "types": "./server/index.d.ts",
35
+ "default": "./server/index.js"
36
+ },
37
+ "./chat.css": "./css/chat.css",
38
+ "./foundation.css": "./css/foundation/index.css",
39
+ "./base.css": "./css/foundation/base.css"
40
+ },
41
+ "peerDependencies": {
42
+ "react": "^18 || ^19",
43
+ "react-dom": "^18 || ^19"
44
+ },
45
+ "peerDependenciesMeta": {
46
+ "react": {
47
+ "optional": true
48
+ },
49
+ "react-dom": {
50
+ "optional": true
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,17 @@
1
+ import { IncomingMessage, ServerResponse } from "node:http";
2
+ import { ChatSessionProvider } from "./types";
3
+ export interface ChatHandlerOptions {
4
+ manager: ChatSessionProvider;
5
+ prefix?: string;
6
+ cors?: boolean;
7
+ }
8
+ /**
9
+ * Framework-freier HTTP-Adapter. Routen unter dem Prefix (default /chat):
10
+ * GET /:id/stream SSE - erst Verlauf, dann live, mit Keepalive-Pings
11
+ * POST /:id/send { text } - startet einen Lauf oder funkt dazwischen
12
+ * POST /:id/stop bricht den laufenden Turn ab
13
+ * GET /sessions persistierte Unterhaltungen
14
+ * DELETE /:id loescht eine Unterhaltung
15
+ * Rueckgabe true heisst: Anfrage wurde behandelt.
16
+ */
17
+ export declare function createChatHandler({ manager, prefix, cors }: ChatHandlerOptions): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
@@ -0,0 +1,6 @@
1
+ export type { AgentConfig, AgentTool, ChatSessionLike, ChatSessionProvider, OpenAiMessage, OpenAiToolCall, SessionState, SessionInfo, SessionStore, } from "./types";
2
+ export { AgentSession } from "./session";
3
+ export { SessionManager } from "./manager";
4
+ export { MemorySessionStore, FileSessionStore } from "./store";
5
+ export { createChatHandler } from "./http";
6
+ export { streamChatCompletion } from "./openai";