@noodleseed/assistant 1.1.0 → 1.1.1

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.
@@ -399,10 +399,18 @@ var NoodleAssistantElement = class extends HTMLElementBase {
399
399
  throw new Error(`Assistant confirmation failed (${response.status})`);
400
400
  }
401
401
  let completed;
402
+ let narrationBody;
402
403
  await consumeAssistantEvents(response, (event) => {
403
404
  if (event.event === "tool_completed") completed = event.data;
405
+ if (event.event === "content") {
406
+ const body = narrationBody ?? this.#appendMessage("assistant", "");
407
+ narrationBody = body;
408
+ if (body) body.textContent += String(event.data.delta ?? "");
409
+ }
404
410
  });
405
- if (completed) this.#appendMessage("assistant", JSON.stringify(completed.result ?? {}));
411
+ if (completed && !narrationBody) {
412
+ this.#appendMessage("assistant", JSON.stringify(completed.result ?? {}));
413
+ }
406
414
  this.dispatchEvent(new CustomEvent("assistant-tool-completed", { detail: { id } }));
407
415
  }
408
416
  #handleSystemTheme = () => this.#applyTheme();
@@ -695,4 +703,4 @@ export {
695
703
  NoodleAssistantElement,
696
704
  registerNoodleAssistant
697
705
  };
698
- //# sourceMappingURL=chunk-OXFV6KZ2.js.map
706
+ //# sourceMappingURL=chunk-IM7SAHNE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/appearance.ts","../src/transport.ts","../src/element.ts"],"sourcesContent":["export type AssistantThemeMode = 'auto' | 'light' | 'dark';\nexport type AssistantLayoutMode = 'floating' | 'inline' | 'drawer';\nexport type AssistantPosition = 'bottom-left' | 'bottom-right';\n\nexport interface AssistantThemeTokens {\n readonly page: string;\n readonly panel: string;\n readonly elevated: string;\n readonly input: string;\n readonly hover: string;\n readonly selected: string;\n readonly text: string;\n readonly mutedText: string;\n readonly accent: string;\n readonly accentText: string;\n readonly link: string;\n readonly divider: string;\n readonly focus: string;\n readonly success: string;\n readonly warning: string;\n readonly danger: string;\n readonly overlay: string;\n readonly code: string;\n readonly widgetFrame: string;\n readonly fontFamily: string;\n readonly monoFontFamily: string;\n readonly baseFontSize: number;\n readonly messageFontSize: number;\n readonly lineHeight: number;\n readonly panelRadius: number;\n readonly cardRadius: number;\n readonly inputRadius: number;\n readonly buttonRadius: number;\n readonly launcherRadius: number;\n readonly spacing: number;\n readonly shadow: string;\n readonly backdropBlur: number;\n readonly motionScale: number;\n}\n\nexport interface AssistantConfiguration {\n readonly branding?: {\n readonly name?: string;\n readonly accent?: string;\n readonly surface?: string;\n readonly surfaceDark?: string;\n readonly logo?: AssistantBrandAsset;\n readonly mark?: AssistantBrandAsset;\n readonly avatar?: AssistantBrandAsset;\n readonly theme?: {\n readonly light?: BrandThemeOverrides;\n readonly dark?: BrandThemeOverrides;\n };\n readonly radius?: 'none' | 'sm' | 'md' | 'lg';\n readonly density?: 'compact' | 'comfortable';\n readonly typography?: 'system' | 'serif' | 'mono';\n readonly colorScheme?: AssistantThemeMode;\n };\n readonly assistant?: AssistantUiConfiguration;\n}\n\ninterface AssistantBrandAsset {\n readonly uri: string;\n readonly darkUri?: string;\n readonly alt: string;\n}\n\ninterface BrandThemeOverrides {\n readonly surface?: string;\n readonly surfaceRaised?: string;\n readonly surfaceMuted?: string;\n readonly text?: string;\n readonly textMuted?: string;\n readonly accent?: string;\n readonly accentText?: string;\n readonly link?: string;\n readonly border?: string;\n readonly borderStrong?: string;\n readonly focus?: string;\n readonly success?: string;\n readonly warning?: string;\n readonly danger?: string;\n readonly code?: string;\n}\n\ninterface AssistantUiConfiguration {\n readonly layout?: {\n readonly mode?: AssistantLayoutMode;\n readonly position?: AssistantPosition;\n readonly panelWidth?: number;\n readonly panelMinHeight?: number;\n readonly panelMaxHeight?: number;\n readonly zIndex?: number;\n readonly density?: 'compact' | 'comfortable';\n readonly mobileFullscreen?: boolean;\n };\n readonly behavior?: {\n readonly startOpen?: boolean;\n readonly closeOnEscape?: boolean;\n readonly closeOnOutsideClick?: boolean;\n readonly showLauncher?: boolean;\n readonly showHeader?: boolean;\n readonly showAvatars?: boolean;\n readonly showTimestamps?: boolean;\n };\n readonly labels?: Partial<AssistantLabels>;\n readonly suggestedPrompts?: readonly string[];\n readonly privacyUrl?: string;\n readonly termsUrl?: string;\n readonly locale?: string;\n readonly direction?: 'ltr' | 'rtl' | 'auto';\n}\n\nexport interface AssistantLabels {\n readonly welcomeHeading: string;\n readonly welcomeMessage: string;\n readonly composerPlaceholder: string;\n readonly send: string;\n readonly stop: string;\n readonly close: string;\n readonly open: string;\n readonly confirm: string;\n readonly cancel: string;\n readonly retry: string;\n readonly unavailable: string;\n readonly sessionExpired: string;\n}\n\nexport interface ResolvedAssistantAppearance {\n readonly brand: {\n readonly name: string;\n readonly logo: { readonly light?: string; readonly dark?: string };\n readonly avatar: { readonly light?: string; readonly dark?: string };\n readonly mark: { readonly light?: string; readonly dark?: string };\n };\n readonly theme: {\n readonly defaultMode: AssistantThemeMode;\n readonly light: AssistantThemeTokens;\n readonly dark: AssistantThemeTokens;\n };\n readonly layout: {\n readonly mode: AssistantLayoutMode;\n readonly position: AssistantPosition;\n readonly panelWidth: number;\n readonly panelMinHeight: number;\n readonly panelMaxHeight: number;\n readonly zIndex: number;\n readonly density: 'compact' | 'comfortable';\n readonly mobileFullscreen: boolean;\n };\n readonly behavior: {\n readonly startOpen: boolean;\n readonly closeOnEscape: boolean;\n readonly closeOnOutsideClick: boolean;\n readonly showLauncher: boolean;\n readonly showHeader: boolean;\n readonly showAvatars: boolean;\n readonly showTimestamps: boolean;\n };\n readonly labels: AssistantLabels;\n readonly suggestedPrompts: readonly string[];\n readonly privacyUrl?: string;\n readonly termsUrl?: string;\n readonly locale: string;\n readonly direction: 'ltr' | 'rtl' | 'auto';\n}\n\nconst common = {\n fontFamily: 'inherit',\n monoFontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n baseFontSize: 15,\n messageFontSize: 15,\n lineHeight: 1.5,\n panelRadius: 20,\n cardRadius: 14,\n inputRadius: 14,\n buttonRadius: 12,\n launcherRadius: 999,\n spacing: 12,\n backdropBlur: 18,\n motionScale: 1,\n} as const;\n\nexport const DEFAULT_APPEARANCE: ResolvedAssistantAppearance = {\n brand: { name: 'Assistant', logo: {}, avatar: {}, mark: {} },\n theme: {\n defaultMode: 'auto',\n light: {\n ...common,\n page: '#F7F7F8',\n panel: '#FFFFFF',\n elevated: '#FFFFFF',\n input: '#F1F1F3',\n hover: '#ECECEF',\n selected: '#E4E2FF',\n text: '#18181B',\n mutedText: '#71717A',\n accent: '#5B4CF0',\n accentText: '#FFFFFF',\n link: '#4A3BD5',\n divider: '#E4E4E7',\n focus: '#5B4CF0',\n success: '#16835D',\n warning: '#A45B00',\n danger: '#C92A45',\n overlay: '#18181B66',\n code: '#F1F1F3',\n widgetFrame: '#E4E4E7',\n shadow: '0 24px 80px rgba(24, 24, 27, 0.18)',\n },\n dark: {\n ...common,\n page: '#111113',\n panel: '#19191D',\n elevated: '#222228',\n input: '#26262C',\n hover: '#303038',\n selected: '#37315F',\n text: '#FAFAFA',\n mutedText: '#A1A1AA',\n accent: '#A99FFF',\n accentText: '#17131F',\n link: '#B9B1FF',\n divider: '#34343B',\n focus: '#B9B1FF',\n success: '#58C69A',\n warning: '#F2B45F',\n danger: '#FF8094',\n overlay: '#00000099',\n code: '#26262C',\n widgetFrame: '#34343B',\n shadow: '0 24px 90px rgba(0, 0, 0, 0.55)',\n },\n },\n layout: {\n mode: 'floating',\n position: 'bottom-right',\n panelWidth: 400,\n panelMinHeight: 420,\n panelMaxHeight: 720,\n zIndex: 2147483000,\n density: 'comfortable',\n mobileFullscreen: true,\n },\n behavior: {\n startOpen: false,\n closeOnEscape: true,\n closeOnOutsideClick: false,\n showLauncher: true,\n showHeader: true,\n showAvatars: true,\n showTimestamps: false,\n },\n labels: {\n welcomeHeading: 'How can I help?',\n welcomeMessage: '',\n composerPlaceholder: 'Ask a question…',\n send: 'Send',\n stop: 'Stop',\n close: 'Close assistant',\n open: 'Open assistant',\n confirm: 'Confirm',\n cancel: 'Cancel',\n retry: 'Try again',\n unavailable: 'The assistant is temporarily unavailable.',\n sessionExpired: 'Your assistant session expired. Reopen it to continue.',\n },\n suggestedPrompts: [],\n locale: 'en',\n direction: 'auto',\n};\n\nexport function resolveAppearance(input: AssistantConfiguration = {}): ResolvedAssistantAppearance {\n const branding = input.branding;\n const assistant = input.assistant;\n return {\n brand: {\n ...DEFAULT_APPEARANCE.brand,\n ...(branding?.name ? { name: branding.name } : {}),\n logo: themedAsset(branding?.logo),\n avatar: themedAsset(branding?.avatar),\n mark: themedAsset(branding?.mark),\n },\n theme: {\n defaultMode: branding?.colorScheme ?? DEFAULT_APPEARANCE.theme.defaultMode,\n light: resolveTheme('light', branding),\n dark: resolveTheme('dark', branding),\n },\n layout: {\n ...DEFAULT_APPEARANCE.layout,\n ...(branding?.density ? { density: branding.density } : {}),\n ...assistant?.layout,\n },\n behavior: { ...DEFAULT_APPEARANCE.behavior, ...assistant?.behavior },\n labels: { ...DEFAULT_APPEARANCE.labels, ...assistant?.labels },\n suggestedPrompts: assistant?.suggestedPrompts ?? DEFAULT_APPEARANCE.suggestedPrompts,\n ...(assistant?.privacyUrl ? { privacyUrl: assistant.privacyUrl } : {}),\n ...(assistant?.termsUrl ? { termsUrl: assistant.termsUrl } : {}),\n locale: assistant?.locale ?? DEFAULT_APPEARANCE.locale,\n direction: assistant?.direction ?? DEFAULT_APPEARANCE.direction,\n };\n}\n\nfunction themedAsset(asset: AssistantBrandAsset | undefined): {\n readonly light?: string;\n readonly dark?: string;\n} {\n return asset ? { light: asset.uri, dark: asset.darkUri ?? asset.uri } : {};\n}\n\nfunction resolveTheme(\n mode: 'light' | 'dark',\n branding: AssistantConfiguration['branding'],\n): AssistantThemeTokens {\n const defaults = DEFAULT_APPEARANCE.theme[mode];\n const surface = mode === 'light' ? branding?.surface : branding?.surfaceDark;\n const portable = branding?.theme?.[mode];\n const radius = branding?.radius ? radiusValue(branding.radius) : undefined;\n return {\n ...defaults,\n ...(branding?.accent ? { accent: branding.accent } : {}),\n ...(surface ? { page: surface, panel: surface } : {}),\n ...mapPortableTheme(portable),\n ...(radius === undefined\n ? {}\n : {\n panelRadius: radius,\n cardRadius: radius,\n inputRadius: Math.max(0, radius - 2),\n buttonRadius: Math.max(0, radius - 2),\n }),\n ...(branding?.typography === 'serif'\n ? { fontFamily: 'ui-serif, Georgia, serif' }\n : branding?.typography === 'mono'\n ? { fontFamily: defaults.monoFontFamily }\n : {}),\n };\n}\n\nfunction mapPortableTheme(input: BrandThemeOverrides | undefined): Partial<AssistantThemeTokens> {\n if (!input) return {};\n return {\n ...(input.surface ? { page: input.surface, panel: input.surface } : {}),\n ...(input.surfaceRaised ? { elevated: input.surfaceRaised } : {}),\n ...(input.surfaceMuted\n ? { input: input.surfaceMuted, hover: input.surfaceMuted, selected: input.surfaceMuted }\n : {}),\n ...(input.text ? { text: input.text } : {}),\n ...(input.textMuted ? { mutedText: input.textMuted } : {}),\n ...(input.accent ? { accent: input.accent } : {}),\n ...(input.accentText ? { accentText: input.accentText } : {}),\n ...(input.link ? { link: input.link } : {}),\n ...(input.border ? { divider: input.border, widgetFrame: input.border } : {}),\n ...(input.focus ? { focus: input.focus } : {}),\n ...(input.success ? { success: input.success } : {}),\n ...(input.warning ? { warning: input.warning } : {}),\n ...(input.danger ? { danger: input.danger } : {}),\n ...(input.code ? { code: input.code } : {}),\n };\n}\n\nfunction radiusValue(radius: 'none' | 'sm' | 'md' | 'lg'): number {\n if (radius === 'none') return 0;\n if (radius === 'sm') return 8;\n if (radius === 'lg') return 18;\n return 14;\n}\n","export interface AssistantEvent {\n readonly event: string;\n readonly data: Readonly<Record<string, unknown>>;\n}\n\nexport interface AssistantErrorDetail {\n readonly code: string;\n readonly status?: number;\n readonly retryable: boolean;\n}\n\n/**\n * A 2xx response whose body carried no assistant events at all — typically an auth redirect or\n * proxy page returning HTML with a 200. Silently rendering nothing strands the end user, so the\n * transport fails loudly instead (ADR 0151 hardening).\n */\nexport class AssistantTransportError extends Error {\n readonly code = 'invalid_response' as const;\n\n constructor(contentType: string) {\n super(`assistant response was not an event stream (content-type: ${contentType || 'unknown'})`);\n this.name = 'AssistantTransportError';\n }\n}\n\n/** Consume JSON-bearing server-sent events without buffering the whole assistant turn. */\nexport async function consumeAssistantEvents(\n response: Response,\n onEvent: (event: AssistantEvent) => void,\n): Promise<void> {\n let delivered = 0;\n let sawText = false;\n const deliver = (event: AssistantEvent): void => {\n delivered += 1;\n onEvent(event);\n };\n if (!response.body) {\n const text = await response.text();\n sawText = text.trim().length > 0;\n emitFrames(text, deliver, true);\n } else {\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let pending = '';\n while (true) {\n const { done, value } = await reader.read();\n const chunk = decoder.decode(value, { stream: !done });\n if (!sawText && chunk.trim().length > 0) sawText = true;\n pending += chunk;\n pending = emitFrames(pending, deliver, done);\n if (done) break;\n }\n }\n if (delivered === 0 && sawText) {\n throw new AssistantTransportError(response.headers.get('content-type') ?? '');\n }\n}\n\nfunction emitFrames(\n input: string,\n onEvent: (event: AssistantEvent) => void,\n flush: boolean,\n): string {\n const normalized = input.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n');\n const frames = normalized.split('\\n\\n');\n const pending = flush ? '' : (frames.pop() ?? '');\n for (const frame of frames) {\n const event = parseFrame(frame);\n if (event) onEvent(event);\n }\n if (flush && frames.length === 0 && normalized.trim()) {\n const event = parseFrame(normalized);\n if (event) onEvent(event);\n }\n return pending;\n}\n\nfunction parseFrame(frame: string): AssistantEvent | undefined {\n let event = 'message';\n const data: string[] = [];\n for (const line of frame.split('\\n')) {\n if (line.startsWith(':')) continue;\n const separator = line.indexOf(':');\n const field = separator < 0 ? line : line.slice(0, separator);\n const value = separator < 0 ? '' : line.slice(separator + 1).replace(/^ /, '');\n if (field === 'event') event = value;\n if (field === 'data') data.push(value);\n }\n if (data.length === 0) return undefined;\n try {\n return { event, data: JSON.parse(data.join('\\n')) as Readonly<Record<string, unknown>> };\n } catch {\n return undefined;\n }\n}\n","import {\n type AssistantConfiguration,\n type AssistantThemeMode,\n type AssistantThemeTokens,\n resolveAppearance,\n} from './appearance.js';\nimport {\n type AssistantErrorDetail,\n AssistantTransportError,\n consumeAssistantEvents,\n} from './transport.js';\n\nexport const ASSISTANT_TAG_NAME = 'noodle-assistant';\nconst HTMLElementBase: typeof HTMLElement =\n globalThis.HTMLElement ?? (class {} as unknown as typeof HTMLElement);\n\ninterface SessionResponse {\n readonly token: string;\n readonly expiresAt: string;\n readonly endpoints: {\n readonly turns: string;\n readonly toolConfirmations: string;\n };\n readonly configuration?: AssistantConfiguration;\n}\n\nexport class NoodleAssistantElement extends HTMLElementBase {\n static readonly observedAttributes = ['open', 'theme'];\n #appearance = resolveAppearance();\n #session: SessionResponse | undefined;\n #messages: HTMLElement | undefined;\n #media: MediaQueryList | undefined;\n #context: Readonly<Record<string, string | number | boolean | null>> | undefined;\n sessionEndpoint = '';\n\n connectedCallback(): void {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n if (!this.sessionEndpoint) this.sessionEndpoint = this.getAttribute('session-endpoint') ?? '';\n this.#media = globalThis.matchMedia?.('(prefers-color-scheme: dark)');\n this.#media?.addEventListener('change', this.#handleSystemTheme);\n document.addEventListener('keydown', this.#handleDocumentKeydown);\n document.addEventListener('pointerdown', this.#handleDocumentPointerDown);\n if (this.#appearance.behavior.startOpen) this.setAttribute('open', '');\n this.#render();\n this.dispatchEvent(new CustomEvent('assistant-ready'));\n }\n\n disconnectedCallback(): void {\n this.#media?.removeEventListener('change', this.#handleSystemTheme);\n document.removeEventListener('keydown', this.#handleDocumentKeydown);\n document.removeEventListener('pointerdown', this.#handleDocumentPointerDown);\n }\n\n attributeChangedCallback(name: string): void {\n if (name === 'theme') this.#applyTheme();\n }\n\n open(): void {\n this.setAttribute('open', '');\n this.dispatchEvent(new CustomEvent('assistant-open'));\n }\n\n close(): void {\n this.removeAttribute('open');\n this.dispatchEvent(new CustomEvent('assistant-close'));\n }\n\n toggle(): void {\n this.hasAttribute('open') ? this.close() : this.open();\n }\n\n focusComposer(): void {\n this.shadowRoot?.querySelector<HTMLTextAreaElement>('textarea')?.focus();\n }\n\n resetSession(): void {\n this.#session = undefined;\n this.#messages?.replaceChildren();\n this.dispatchEvent(new CustomEvent('assistant-session-reset'));\n }\n\n updateContext(context: Readonly<Record<string, string | number | boolean | null>>): void {\n this.#context = { ...context };\n this.dispatchEvent(new CustomEvent('assistant-context-changed', { detail: { context } }));\n }\n\n async sendMessage(text: string): Promise<void> {\n const message = text.trim();\n if (!message) return;\n if (!this.#session) this.#session = await this.#createSession();\n this.#appendMessage('user', message);\n this.dispatchEvent(new CustomEvent('assistant-message-started'));\n await this.#sendTurn(message, true);\n }\n\n async #sendTurn(message: string, mayRetry: boolean): Promise<void> {\n if (!this.#session) this.#session = await this.#createSession();\n const response = await fetch(this.#session.endpoints.turns, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.#session.token}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({ message }),\n });\n if (response.status === 401 && mayRetry) {\n this.#session = undefined;\n this.dispatchEvent(new CustomEvent('assistant-session-expired'));\n await this.#sendTurn(message, false);\n return;\n }\n if (!response.ok) {\n this.#dispatchError({ code: 'turn_failed', status: response.status, retryable: false });\n throw new Error(`Assistant turn failed (${response.status})`);\n }\n let assistantBody: HTMLElement | undefined;\n try {\n await consumeAssistantEvents(response, (event) => {\n if (event.event === 'content') {\n const body = assistantBody ?? this.#appendMessage('assistant', '');\n assistantBody = body;\n if (body) body.textContent += String(event.data.delta ?? '');\n }\n if (event.event === 'tool_proposed') {\n this.#appendToolProposal(\n String(event.data.id ?? ''),\n String(event.data.tool ?? 'Action'),\n );\n }\n if (event.event === 'error') {\n this.#dispatchError({\n code: String(event.data.code ?? 'stream_failed'),\n retryable: event.data.retryable === true,\n });\n }\n });\n } catch (error) {\n if (error instanceof AssistantTransportError) {\n this.#dispatchError({ code: error.code, retryable: false });\n }\n throw error;\n }\n this.dispatchEvent(new CustomEvent('assistant-message-completed'));\n }\n\n /**\n * Every listener the element attaches to its own DOM must go through this guard: internal UI\n * failures surface as `assistant-error` events (already dispatched by the failing path) and must\n * never escape as unhandled rejections into the embedding page. Programmatic callers use\n * `sendMessage`/`confirmTool` directly and keep the rejection.\n */\n #sendGuarded(text: string): void {\n void this.sendMessage(text).catch(() => {});\n }\n\n async confirmTool(id: string): Promise<void> {\n if (!this.#session) {\n this.#dispatchError({ code: 'confirmation_expired', retryable: false });\n throw new Error('assistant session is not active');\n }\n const response = await fetch(this.#session.endpoints.toolConfirmations, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.#session.token}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({ id }),\n });\n if (!response.ok) {\n const expired = response.status === 401 || response.status === 409;\n if (response.status === 401) {\n this.#session = undefined;\n this.dispatchEvent(new CustomEvent('assistant-session-expired'));\n }\n this.#dispatchError({\n code: expired ? 'confirmation_expired' : 'confirmation_failed',\n status: response.status,\n retryable: false,\n });\n throw new Error(`Assistant confirmation failed (${response.status})`);\n }\n let completed: Readonly<Record<string, unknown>> | undefined;\n let narrationBody: HTMLElement | undefined;\n await consumeAssistantEvents(response, (event) => {\n if (event.event === 'tool_completed') completed = event.data;\n if (event.event === 'content') {\n const body = narrationBody ?? this.#appendMessage('assistant', '');\n narrationBody = body;\n if (body) body.textContent += String(event.data.delta ?? '');\n }\n });\n // The narrated reply supersedes the raw result; older services send only tool_completed,\n // so the JSON rendering remains as the fallback.\n if (completed && !narrationBody) {\n this.#appendMessage('assistant', JSON.stringify(completed.result ?? {}));\n }\n this.dispatchEvent(new CustomEvent('assistant-tool-completed', { detail: { id } }));\n }\n\n #handleSystemTheme = (): void => this.#applyTheme();\n\n #handleDocumentKeydown = (event: KeyboardEvent): void => {\n if (\n event.key === 'Escape' &&\n this.hasAttribute('open') &&\n this.#appearance.behavior.closeOnEscape\n ) {\n this.close();\n }\n };\n\n #handleDocumentPointerDown = (event: PointerEvent): void => {\n if (\n this.hasAttribute('open') &&\n this.#appearance.behavior.closeOnOutsideClick &&\n !event.composedPath().includes(this)\n ) {\n this.close();\n }\n };\n\n async #createSession(): Promise<SessionResponse> {\n if (!this.sessionEndpoint) throw new Error('sessionEndpoint is required');\n let response: Response;\n try {\n response = await fetch(this.sessionEndpoint, {\n method: 'POST',\n headers: { Accept: 'application/json', 'Content-Type': 'application/json' },\n body: JSON.stringify(this.#context ? { context: this.#context } : {}),\n credentials: 'same-origin',\n });\n } catch (error) {\n this.#dispatchError({ code: 'session_failed', retryable: true });\n throw error;\n }\n if (!response.ok) {\n this.#dispatchError({ code: 'session_failed', status: response.status, retryable: true });\n throw new Error(`Assistant session failed (${response.status})`);\n }\n let session: SessionResponse;\n try {\n session = (await response.json()) as SessionResponse;\n } catch (error) {\n this.#dispatchError({ code: 'session_failed', retryable: true });\n throw error;\n }\n if (session.configuration) {\n this.#appearance = resolveAppearance(session.configuration);\n this.#render();\n }\n this.dispatchEvent(\n new CustomEvent('assistant-session-started', { detail: { expiresAt: session.expiresAt } }),\n );\n return session;\n }\n\n #appendMessage(role: 'user' | 'assistant', text: string): HTMLElement | undefined {\n if (!this.#messages) return undefined;\n const message = document.createElement('div');\n message.className = `message ${role}`;\n if (\n role === 'assistant' &&\n this.#appearance.behavior.showAvatars &&\n this.#appearance.brand.avatar[this.#resolvedMode()]\n ) {\n const avatar = document.createElement('img');\n avatar.className = 'avatar';\n avatar.src = this.#appearance.brand.avatar[this.#resolvedMode()] ?? '';\n avatar.alt = '';\n message.append(avatar);\n }\n const body = document.createElement('span');\n body.textContent = text;\n message.append(body);\n if (this.#appearance.behavior.showTimestamps) {\n const timestamp = document.createElement('time');\n timestamp.dateTime = new Date().toISOString();\n timestamp.textContent = new Intl.DateTimeFormat(this.#appearance.locale, {\n hour: 'numeric',\n minute: '2-digit',\n }).format(new Date());\n message.append(timestamp);\n }\n this.#messages.append(message);\n return body;\n }\n\n #dispatchError(detail: AssistantErrorDetail): void {\n this.dispatchEvent(new CustomEvent('assistant-error', { detail }));\n }\n\n #appendToolProposal(id: string, tool: string): void {\n if (!this.#messages || !id) return;\n const card = document.createElement('section');\n card.className = 'tool-proposal';\n const label = document.createElement('strong');\n label.textContent = tool;\n const confirm = document.createElement('button');\n confirm.type = 'button';\n confirm.textContent = this.#appearance.labels.confirm;\n confirm.addEventListener('click', () => {\n confirm.disabled = true;\n void this.confirmTool(id).catch(() => {\n confirm.disabled = false;\n this.dispatchEvent(\n new CustomEvent('assistant-error', { detail: { code: 'confirmation_failed' } }),\n );\n });\n });\n const cancel = document.createElement('button');\n cancel.type = 'button';\n cancel.textContent = this.#appearance.labels.cancel;\n cancel.addEventListener('click', () => card.remove());\n card.append(label, confirm, cancel);\n this.#messages.append(card);\n this.dispatchEvent(new CustomEvent('assistant-tool-proposed', { detail: { id, tool } }));\n }\n\n #resolvedMode(): Exclude<AssistantThemeMode, 'auto'> {\n const configured =\n (this.getAttribute('theme') as AssistantThemeMode | null) ??\n this.#appearance.theme.defaultMode;\n return configured === 'auto' ? (this.#media?.matches ? 'dark' : 'light') : configured;\n }\n\n #applyTheme(): void {\n const mode = this.#resolvedMode();\n this.setAttribute('data-theme', mode);\n const tokens = this.#appearance.theme[mode];\n for (const [name, value] of Object.entries(tokens)) {\n this.style.setProperty(\n `--ns-assistant-default-${camelToKebab(name)}`,\n tokenValue(name, value),\n );\n }\n this.style.setProperty(\n '--ns-assistant-default-panel-width',\n `${this.#appearance.layout.panelWidth}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-min-height',\n `${this.#appearance.layout.panelMinHeight}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-max-height',\n `${this.#appearance.layout.panelMaxHeight}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-z-index',\n String(this.#appearance.layout.zIndex),\n );\n const logo = this.shadowRoot?.querySelector<HTMLImageElement>('.brand-logo');\n const logoUrl = this.#appearance.brand.logo[mode];\n if (logo) {\n logo.hidden = !logoUrl;\n if (logoUrl) logo.src = logoUrl;\n }\n }\n\n #render(): void {\n if (!this.shadowRoot) return;\n const appearance = this.#appearance;\n this.setAttribute('role', 'complementary');\n this.setAttribute('aria-label', appearance.brand.name);\n this.setAttribute('lang', appearance.locale);\n this.setAttribute('dir', appearance.direction);\n this.dataset.mode = appearance.layout.mode;\n this.dataset.position = appearance.layout.position;\n this.dataset.density = appearance.layout.density;\n this.toggleAttribute('mobile-fullscreen', appearance.layout.mobileFullscreen);\n this.shadowRoot.innerHTML = `${styles}\n <button class=\"launcher\" type=\"button\" aria-label=\"${escapeAttribute(appearance.labels.open)}\"><slot name=\"launcher-icon\">✦</slot></button>\n <section class=\"panel\" aria-label=\"${escapeAttribute(appearance.brand.name)}\">\n <header><slot name=\"header-leading\"></slot><img class=\"brand-logo\" alt=\"\"><strong></strong><slot name=\"header-actions\"></slot><button class=\"close\" type=\"button\" aria-label=\"${escapeAttribute(appearance.labels.close)}\">×</button></header>\n <div class=\"welcome\"><slot name=\"empty-state\"><h2></h2><p></p></slot></div>\n <div class=\"suggested-prompts\"></div>\n <div class=\"messages\" aria-live=\"polite\"></div>\n <form><slot name=\"composer-leading\"></slot><textarea rows=\"1\"></textarea><button class=\"send\" type=\"submit\"></button><slot name=\"composer-trailing\"></slot></form>\n <nav class=\"legal\" aria-label=\"Legal\"></nav>\n <slot name=\"conversation-footer\"></slot>\n </section>`;\n queryRequired<HTMLElement>(this.shadowRoot, 'strong').textContent = appearance.brand.name;\n const launcherIcon = appearance.brand.mark[this.#resolvedMode()];\n if (launcherIcon) {\n const launcherSlot = queryRequired<HTMLSlotElement>(\n this.shadowRoot,\n 'slot[name=\"launcher-icon\"]',\n );\n const icon = document.createElement('img');\n icon.src = launcherIcon;\n icon.alt = '';\n launcherSlot.replaceChildren(icon);\n }\n const logo = queryRequired<HTMLImageElement>(this.shadowRoot, '.brand-logo');\n const logoUrl = appearance.brand.logo[this.#resolvedMode()];\n if (logoUrl) {\n logo.src = logoUrl;\n logo.alt = appearance.brand.name;\n } else {\n logo.hidden = true;\n }\n queryRequired<HTMLElement>(this.shadowRoot, 'h2').textContent =\n appearance.labels.welcomeHeading;\n queryRequired<HTMLElement>(this.shadowRoot, 'p').textContent = appearance.labels.welcomeMessage;\n const textarea = queryRequired<HTMLTextAreaElement>(this.shadowRoot, 'textarea');\n textarea.placeholder = appearance.labels.composerPlaceholder;\n textarea.setAttribute('aria-label', appearance.labels.composerPlaceholder);\n queryRequired<HTMLElement>(this.shadowRoot, '.send').textContent = appearance.labels.send;\n const prompts = queryRequired<HTMLElement>(this.shadowRoot, '.suggested-prompts');\n for (const prompt of appearance.suggestedPrompts) {\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = prompt;\n button.addEventListener('click', () => this.#sendGuarded(prompt));\n prompts.append(button);\n }\n if (!appearance.behavior.showLauncher)\n queryRequired<HTMLElement>(this.shadowRoot, '.launcher').hidden = true;\n if (!appearance.behavior.showHeader)\n queryRequired<HTMLElement>(this.shadowRoot, 'header').hidden = true;\n const legal = queryRequired<HTMLElement>(this.shadowRoot, '.legal');\n for (const [label, href] of [\n ['Privacy', appearance.privacyUrl],\n ['Terms', appearance.termsUrl],\n ] as const) {\n if (!href) continue;\n const link = document.createElement('a');\n link.href = href;\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.textContent = label;\n legal.append(link);\n }\n this.#messages = this.shadowRoot.querySelector('.messages') ?? undefined;\n this.shadowRoot.querySelector('.launcher')?.addEventListener('click', () => this.open());\n this.shadowRoot.querySelector('.close')?.addEventListener('click', () => this.close());\n this.shadowRoot.querySelector('form')?.addEventListener('submit', (event) => {\n event.preventDefault();\n const value = textarea.value;\n textarea.value = '';\n this.#sendGuarded(value);\n });\n this.#applyTheme();\n }\n}\n\nexport function registerNoodleAssistant(): void {\n if (globalThis.customElements && !customElements.get(ASSISTANT_TAG_NAME)) {\n customElements.define(ASSISTANT_TAG_NAME, NoodleAssistantElement);\n }\n}\n\nfunction camelToKebab(value: string): string {\n return value.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n}\n\nfunction tokenValue(name: string, value: AssistantThemeTokens[keyof AssistantThemeTokens]): string {\n if (typeof value !== 'number') return value;\n if (name === 'lineHeight' || name === 'motionScale') return String(value);\n return `${value}px`;\n}\n\nfunction escapeAttribute(value: string): string {\n return value.replaceAll('&', '&amp;').replaceAll('\"', '&quot;').replaceAll('<', '&lt;');\n}\n\nfunction queryRequired<T extends Element>(root: ShadowRoot, selector: string): T {\n const element = root.querySelector<T>(selector);\n if (!element) throw new Error(`assistant renderer is missing ${selector}`);\n return element;\n}\n\nconst styles = `<style>\n :host { color-scheme: light dark; font-family: var(--ns-assistant-font-family, var(--ns-assistant-default-font-family)); font-size: var(--ns-assistant-base-font-size, var(--ns-assistant-default-base-font-size)); line-height: var(--ns-assistant-line-height, var(--ns-assistant-default-line-height)); z-index: var(--ns-assistant-z-index, var(--ns-assistant-default-z-index)); }\n :host([data-mode=\"floating\"]) { position: fixed; bottom: 24px; right: 24px; }\n :host([data-mode=\"floating\"][data-position=\"bottom-left\"]) { right: auto; left: 24px; }\n .launcher { width: 54px; height: 54px; border: 0; border-radius: var(--ns-assistant-launcher-radius, var(--ns-assistant-default-launcher-radius)); color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); cursor: pointer; }\n .launcher img { width: 24px; height: 24px; object-fit: contain; }\n .panel { display: none; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 32px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 32px)); overflow: hidden; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); }\n :host([open]) .panel { display: grid; grid-template-rows: auto auto 1fr auto; }\n :host([open]) .launcher { display: none; }\n header { display: flex; gap: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); align-items: center; padding: calc(var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)) * 1.2); border-bottom: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); }\n header strong { flex: 1; }\n .brand-logo { display: block; max-width: 120px; max-height: 28px; object-fit: contain; }\n button { font: inherit; }\n .close, .send { border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); cursor: pointer; }\n .close { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; font-size: 24px; }\n .welcome { padding: calc(var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)) * 1.5); }\n .welcome h2 { margin: 0; font-size: 1.25em; }\n .welcome p { margin: 6px 0 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }\n .suggested-prompts { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); }\n .suggested-prompts:empty { display: none; }\n .suggested-prompts button { padding: 7px 10px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: transparent; border: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: 999px; cursor: pointer; }\n .messages { min-height: 120px; padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); overflow: auto; }\n .message { width: fit-content; max-width: 84%; margin: 8px 0; padding: 10px 12px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); white-space: pre-wrap; }\n .message .avatar { float: left; width: 24px; height: 24px; margin-right: 8px; border-radius: 50%; object-fit: cover; }\n .message time { display: block; margin-top: 4px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .75em; }\n .message.user { margin-left: auto; color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n .tool-proposal { display: grid; grid-template-columns: 1fr auto auto; gap: 8px; align-items: center; margin: 10px 0; padding: 12px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); }\n .tool-proposal button { padding: 8px 10px; border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); cursor: pointer; }\n .tool-proposal button:first-of-type { color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n form { display: flex; gap: 8px; align-items: end; padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); border-top: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); }\n textarea { flex: 1; resize: none; padding: 10px 12px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); border: 0; border-radius: var(--ns-assistant-input-radius, var(--ns-assistant-default-input-radius)); font: inherit; }\n textarea:focus-visible, button:focus-visible { outline: 3px solid var(--ns-assistant-focus, var(--ns-assistant-default-focus)); outline-offset: 2px; }\n .send { padding: 10px 14px; color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n .legal { display: flex; gap: 12px; justify-content: center; padding: 0 12px 10px; font-size: .8em; }\n .legal:empty { display: none; }\n .legal a { color: var(--ns-assistant-link, var(--ns-assistant-default-link)); }\n :host([data-density=\"compact\"]) .welcome { padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); }\n @media (max-width: 640px) { :host([mobile-fullscreen][open]) { inset: 0; } :host([mobile-fullscreen][open]) .panel { width: 100vw; min-height: 100vh; max-height: 100vh; border-radius: 0; } }\n @media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; } }\n @media (max-width: 560px) { :host([data-mode=\"floating\"]) { inset: auto 12px 12px; } :host([open]) .panel { width: calc(100vw - 24px); max-height: calc(100vh - 24px); } }\n</style>`;\n"],"mappings":"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","names":[]}
package/dist/index.cjs CHANGED
@@ -427,10 +427,18 @@ var NoodleAssistantElement = class extends HTMLElementBase {
427
427
  throw new Error(`Assistant confirmation failed (${response.status})`);
428
428
  }
429
429
  let completed;
430
+ let narrationBody;
430
431
  await consumeAssistantEvents(response, (event) => {
431
432
  if (event.event === "tool_completed") completed = event.data;
433
+ if (event.event === "content") {
434
+ const body = narrationBody ?? this.#appendMessage("assistant", "");
435
+ narrationBody = body;
436
+ if (body) body.textContent += String(event.data.delta ?? "");
437
+ }
432
438
  });
433
- if (completed) this.#appendMessage("assistant", JSON.stringify(completed.result ?? {}));
439
+ if (completed && !narrationBody) {
440
+ this.#appendMessage("assistant", JSON.stringify(completed.result ?? {}));
441
+ }
434
442
  this.dispatchEvent(new CustomEvent("assistant-tool-completed", { detail: { id } }));
435
443
  }
436
444
  #handleSystemTheme = () => this.#applyTheme();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/appearance.ts","../src/transport.ts","../src/element.ts"],"sourcesContent":["export {\n ASSISTANT_TAG_NAME,\n NoodleAssistantElement,\n registerNoodleAssistant,\n} from './element.js';\nexport type { AssistantErrorDetail, AssistantEvent } from './transport.js';\n\nimport { registerNoodleAssistant } from './element.js';\n\nregisterNoodleAssistant();\n","export type AssistantThemeMode = 'auto' | 'light' | 'dark';\nexport type AssistantLayoutMode = 'floating' | 'inline' | 'drawer';\nexport type AssistantPosition = 'bottom-left' | 'bottom-right';\n\nexport interface AssistantThemeTokens {\n readonly page: string;\n readonly panel: string;\n readonly elevated: string;\n readonly input: string;\n readonly hover: string;\n readonly selected: string;\n readonly text: string;\n readonly mutedText: string;\n readonly accent: string;\n readonly accentText: string;\n readonly link: string;\n readonly divider: string;\n readonly focus: string;\n readonly success: string;\n readonly warning: string;\n readonly danger: string;\n readonly overlay: string;\n readonly code: string;\n readonly widgetFrame: string;\n readonly fontFamily: string;\n readonly monoFontFamily: string;\n readonly baseFontSize: number;\n readonly messageFontSize: number;\n readonly lineHeight: number;\n readonly panelRadius: number;\n readonly cardRadius: number;\n readonly inputRadius: number;\n readonly buttonRadius: number;\n readonly launcherRadius: number;\n readonly spacing: number;\n readonly shadow: string;\n readonly backdropBlur: number;\n readonly motionScale: number;\n}\n\nexport interface AssistantConfiguration {\n readonly branding?: {\n readonly name?: string;\n readonly accent?: string;\n readonly surface?: string;\n readonly surfaceDark?: string;\n readonly logo?: AssistantBrandAsset;\n readonly mark?: AssistantBrandAsset;\n readonly avatar?: AssistantBrandAsset;\n readonly theme?: {\n readonly light?: BrandThemeOverrides;\n readonly dark?: BrandThemeOverrides;\n };\n readonly radius?: 'none' | 'sm' | 'md' | 'lg';\n readonly density?: 'compact' | 'comfortable';\n readonly typography?: 'system' | 'serif' | 'mono';\n readonly colorScheme?: AssistantThemeMode;\n };\n readonly assistant?: AssistantUiConfiguration;\n}\n\ninterface AssistantBrandAsset {\n readonly uri: string;\n readonly darkUri?: string;\n readonly alt: string;\n}\n\ninterface BrandThemeOverrides {\n readonly surface?: string;\n readonly surfaceRaised?: string;\n readonly surfaceMuted?: string;\n readonly text?: string;\n readonly textMuted?: string;\n readonly accent?: string;\n readonly accentText?: string;\n readonly link?: string;\n readonly border?: string;\n readonly borderStrong?: string;\n readonly focus?: string;\n readonly success?: string;\n readonly warning?: string;\n readonly danger?: string;\n readonly code?: string;\n}\n\ninterface AssistantUiConfiguration {\n readonly layout?: {\n readonly mode?: AssistantLayoutMode;\n readonly position?: AssistantPosition;\n readonly panelWidth?: number;\n readonly panelMinHeight?: number;\n readonly panelMaxHeight?: number;\n readonly zIndex?: number;\n readonly density?: 'compact' | 'comfortable';\n readonly mobileFullscreen?: boolean;\n };\n readonly behavior?: {\n readonly startOpen?: boolean;\n readonly closeOnEscape?: boolean;\n readonly closeOnOutsideClick?: boolean;\n readonly showLauncher?: boolean;\n readonly showHeader?: boolean;\n readonly showAvatars?: boolean;\n readonly showTimestamps?: boolean;\n };\n readonly labels?: Partial<AssistantLabels>;\n readonly suggestedPrompts?: readonly string[];\n readonly privacyUrl?: string;\n readonly termsUrl?: string;\n readonly locale?: string;\n readonly direction?: 'ltr' | 'rtl' | 'auto';\n}\n\nexport interface AssistantLabels {\n readonly welcomeHeading: string;\n readonly welcomeMessage: string;\n readonly composerPlaceholder: string;\n readonly send: string;\n readonly stop: string;\n readonly close: string;\n readonly open: string;\n readonly confirm: string;\n readonly cancel: string;\n readonly retry: string;\n readonly unavailable: string;\n readonly sessionExpired: string;\n}\n\nexport interface ResolvedAssistantAppearance {\n readonly brand: {\n readonly name: string;\n readonly logo: { readonly light?: string; readonly dark?: string };\n readonly avatar: { readonly light?: string; readonly dark?: string };\n readonly mark: { readonly light?: string; readonly dark?: string };\n };\n readonly theme: {\n readonly defaultMode: AssistantThemeMode;\n readonly light: AssistantThemeTokens;\n readonly dark: AssistantThemeTokens;\n };\n readonly layout: {\n readonly mode: AssistantLayoutMode;\n readonly position: AssistantPosition;\n readonly panelWidth: number;\n readonly panelMinHeight: number;\n readonly panelMaxHeight: number;\n readonly zIndex: number;\n readonly density: 'compact' | 'comfortable';\n readonly mobileFullscreen: boolean;\n };\n readonly behavior: {\n readonly startOpen: boolean;\n readonly closeOnEscape: boolean;\n readonly closeOnOutsideClick: boolean;\n readonly showLauncher: boolean;\n readonly showHeader: boolean;\n readonly showAvatars: boolean;\n readonly showTimestamps: boolean;\n };\n readonly labels: AssistantLabels;\n readonly suggestedPrompts: readonly string[];\n readonly privacyUrl?: string;\n readonly termsUrl?: string;\n readonly locale: string;\n readonly direction: 'ltr' | 'rtl' | 'auto';\n}\n\nconst common = {\n fontFamily: 'inherit',\n monoFontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n baseFontSize: 15,\n messageFontSize: 15,\n lineHeight: 1.5,\n panelRadius: 20,\n cardRadius: 14,\n inputRadius: 14,\n buttonRadius: 12,\n launcherRadius: 999,\n spacing: 12,\n backdropBlur: 18,\n motionScale: 1,\n} as const;\n\nexport const DEFAULT_APPEARANCE: ResolvedAssistantAppearance = {\n brand: { name: 'Assistant', logo: {}, avatar: {}, mark: {} },\n theme: {\n defaultMode: 'auto',\n light: {\n ...common,\n page: '#F7F7F8',\n panel: '#FFFFFF',\n elevated: '#FFFFFF',\n input: '#F1F1F3',\n hover: '#ECECEF',\n selected: '#E4E2FF',\n text: '#18181B',\n mutedText: '#71717A',\n accent: '#5B4CF0',\n accentText: '#FFFFFF',\n link: '#4A3BD5',\n divider: '#E4E4E7',\n focus: '#5B4CF0',\n success: '#16835D',\n warning: '#A45B00',\n danger: '#C92A45',\n overlay: '#18181B66',\n code: '#F1F1F3',\n widgetFrame: '#E4E4E7',\n shadow: '0 24px 80px rgba(24, 24, 27, 0.18)',\n },\n dark: {\n ...common,\n page: '#111113',\n panel: '#19191D',\n elevated: '#222228',\n input: '#26262C',\n hover: '#303038',\n selected: '#37315F',\n text: '#FAFAFA',\n mutedText: '#A1A1AA',\n accent: '#A99FFF',\n accentText: '#17131F',\n link: '#B9B1FF',\n divider: '#34343B',\n focus: '#B9B1FF',\n success: '#58C69A',\n warning: '#F2B45F',\n danger: '#FF8094',\n overlay: '#00000099',\n code: '#26262C',\n widgetFrame: '#34343B',\n shadow: '0 24px 90px rgba(0, 0, 0, 0.55)',\n },\n },\n layout: {\n mode: 'floating',\n position: 'bottom-right',\n panelWidth: 400,\n panelMinHeight: 420,\n panelMaxHeight: 720,\n zIndex: 2147483000,\n density: 'comfortable',\n mobileFullscreen: true,\n },\n behavior: {\n startOpen: false,\n closeOnEscape: true,\n closeOnOutsideClick: false,\n showLauncher: true,\n showHeader: true,\n showAvatars: true,\n showTimestamps: false,\n },\n labels: {\n welcomeHeading: 'How can I help?',\n welcomeMessage: '',\n composerPlaceholder: 'Ask a question…',\n send: 'Send',\n stop: 'Stop',\n close: 'Close assistant',\n open: 'Open assistant',\n confirm: 'Confirm',\n cancel: 'Cancel',\n retry: 'Try again',\n unavailable: 'The assistant is temporarily unavailable.',\n sessionExpired: 'Your assistant session expired. Reopen it to continue.',\n },\n suggestedPrompts: [],\n locale: 'en',\n direction: 'auto',\n};\n\nexport function resolveAppearance(input: AssistantConfiguration = {}): ResolvedAssistantAppearance {\n const branding = input.branding;\n const assistant = input.assistant;\n return {\n brand: {\n ...DEFAULT_APPEARANCE.brand,\n ...(branding?.name ? { name: branding.name } : {}),\n logo: themedAsset(branding?.logo),\n avatar: themedAsset(branding?.avatar),\n mark: themedAsset(branding?.mark),\n },\n theme: {\n defaultMode: branding?.colorScheme ?? DEFAULT_APPEARANCE.theme.defaultMode,\n light: resolveTheme('light', branding),\n dark: resolveTheme('dark', branding),\n },\n layout: {\n ...DEFAULT_APPEARANCE.layout,\n ...(branding?.density ? { density: branding.density } : {}),\n ...assistant?.layout,\n },\n behavior: { ...DEFAULT_APPEARANCE.behavior, ...assistant?.behavior },\n labels: { ...DEFAULT_APPEARANCE.labels, ...assistant?.labels },\n suggestedPrompts: assistant?.suggestedPrompts ?? DEFAULT_APPEARANCE.suggestedPrompts,\n ...(assistant?.privacyUrl ? { privacyUrl: assistant.privacyUrl } : {}),\n ...(assistant?.termsUrl ? { termsUrl: assistant.termsUrl } : {}),\n locale: assistant?.locale ?? DEFAULT_APPEARANCE.locale,\n direction: assistant?.direction ?? DEFAULT_APPEARANCE.direction,\n };\n}\n\nfunction themedAsset(asset: AssistantBrandAsset | undefined): {\n readonly light?: string;\n readonly dark?: string;\n} {\n return asset ? { light: asset.uri, dark: asset.darkUri ?? asset.uri } : {};\n}\n\nfunction resolveTheme(\n mode: 'light' | 'dark',\n branding: AssistantConfiguration['branding'],\n): AssistantThemeTokens {\n const defaults = DEFAULT_APPEARANCE.theme[mode];\n const surface = mode === 'light' ? branding?.surface : branding?.surfaceDark;\n const portable = branding?.theme?.[mode];\n const radius = branding?.radius ? radiusValue(branding.radius) : undefined;\n return {\n ...defaults,\n ...(branding?.accent ? { accent: branding.accent } : {}),\n ...(surface ? { page: surface, panel: surface } : {}),\n ...mapPortableTheme(portable),\n ...(radius === undefined\n ? {}\n : {\n panelRadius: radius,\n cardRadius: radius,\n inputRadius: Math.max(0, radius - 2),\n buttonRadius: Math.max(0, radius - 2),\n }),\n ...(branding?.typography === 'serif'\n ? { fontFamily: 'ui-serif, Georgia, serif' }\n : branding?.typography === 'mono'\n ? { fontFamily: defaults.monoFontFamily }\n : {}),\n };\n}\n\nfunction mapPortableTheme(input: BrandThemeOverrides | undefined): Partial<AssistantThemeTokens> {\n if (!input) return {};\n return {\n ...(input.surface ? { page: input.surface, panel: input.surface } : {}),\n ...(input.surfaceRaised ? { elevated: input.surfaceRaised } : {}),\n ...(input.surfaceMuted\n ? { input: input.surfaceMuted, hover: input.surfaceMuted, selected: input.surfaceMuted }\n : {}),\n ...(input.text ? { text: input.text } : {}),\n ...(input.textMuted ? { mutedText: input.textMuted } : {}),\n ...(input.accent ? { accent: input.accent } : {}),\n ...(input.accentText ? { accentText: input.accentText } : {}),\n ...(input.link ? { link: input.link } : {}),\n ...(input.border ? { divider: input.border, widgetFrame: input.border } : {}),\n ...(input.focus ? { focus: input.focus } : {}),\n ...(input.success ? { success: input.success } : {}),\n ...(input.warning ? { warning: input.warning } : {}),\n ...(input.danger ? { danger: input.danger } : {}),\n ...(input.code ? { code: input.code } : {}),\n };\n}\n\nfunction radiusValue(radius: 'none' | 'sm' | 'md' | 'lg'): number {\n if (radius === 'none') return 0;\n if (radius === 'sm') return 8;\n if (radius === 'lg') return 18;\n return 14;\n}\n","export interface AssistantEvent {\n readonly event: string;\n readonly data: Readonly<Record<string, unknown>>;\n}\n\nexport interface AssistantErrorDetail {\n readonly code: string;\n readonly status?: number;\n readonly retryable: boolean;\n}\n\n/**\n * A 2xx response whose body carried no assistant events at all — typically an auth redirect or\n * proxy page returning HTML with a 200. Silently rendering nothing strands the end user, so the\n * transport fails loudly instead (ADR 0151 hardening).\n */\nexport class AssistantTransportError extends Error {\n readonly code = 'invalid_response' as const;\n\n constructor(contentType: string) {\n super(`assistant response was not an event stream (content-type: ${contentType || 'unknown'})`);\n this.name = 'AssistantTransportError';\n }\n}\n\n/** Consume JSON-bearing server-sent events without buffering the whole assistant turn. */\nexport async function consumeAssistantEvents(\n response: Response,\n onEvent: (event: AssistantEvent) => void,\n): Promise<void> {\n let delivered = 0;\n let sawText = false;\n const deliver = (event: AssistantEvent): void => {\n delivered += 1;\n onEvent(event);\n };\n if (!response.body) {\n const text = await response.text();\n sawText = text.trim().length > 0;\n emitFrames(text, deliver, true);\n } else {\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let pending = '';\n while (true) {\n const { done, value } = await reader.read();\n const chunk = decoder.decode(value, { stream: !done });\n if (!sawText && chunk.trim().length > 0) sawText = true;\n pending += chunk;\n pending = emitFrames(pending, deliver, done);\n if (done) break;\n }\n }\n if (delivered === 0 && sawText) {\n throw new AssistantTransportError(response.headers.get('content-type') ?? '');\n }\n}\n\nfunction emitFrames(\n input: string,\n onEvent: (event: AssistantEvent) => void,\n flush: boolean,\n): string {\n const normalized = input.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n');\n const frames = normalized.split('\\n\\n');\n const pending = flush ? '' : (frames.pop() ?? '');\n for (const frame of frames) {\n const event = parseFrame(frame);\n if (event) onEvent(event);\n }\n if (flush && frames.length === 0 && normalized.trim()) {\n const event = parseFrame(normalized);\n if (event) onEvent(event);\n }\n return pending;\n}\n\nfunction parseFrame(frame: string): AssistantEvent | undefined {\n let event = 'message';\n const data: string[] = [];\n for (const line of frame.split('\\n')) {\n if (line.startsWith(':')) continue;\n const separator = line.indexOf(':');\n const field = separator < 0 ? line : line.slice(0, separator);\n const value = separator < 0 ? '' : line.slice(separator + 1).replace(/^ /, '');\n if (field === 'event') event = value;\n if (field === 'data') data.push(value);\n }\n if (data.length === 0) return undefined;\n try {\n return { event, data: JSON.parse(data.join('\\n')) as Readonly<Record<string, unknown>> };\n } catch {\n return undefined;\n }\n}\n","import {\n type AssistantConfiguration,\n type AssistantThemeMode,\n type AssistantThemeTokens,\n resolveAppearance,\n} from './appearance.js';\nimport {\n type AssistantErrorDetail,\n AssistantTransportError,\n consumeAssistantEvents,\n} from './transport.js';\n\nexport const ASSISTANT_TAG_NAME = 'noodle-assistant';\nconst HTMLElementBase: typeof HTMLElement =\n globalThis.HTMLElement ?? (class {} as unknown as typeof HTMLElement);\n\ninterface SessionResponse {\n readonly token: string;\n readonly expiresAt: string;\n readonly endpoints: {\n readonly turns: string;\n readonly toolConfirmations: string;\n };\n readonly configuration?: AssistantConfiguration;\n}\n\nexport class NoodleAssistantElement extends HTMLElementBase {\n static readonly observedAttributes = ['open', 'theme'];\n #appearance = resolveAppearance();\n #session: SessionResponse | undefined;\n #messages: HTMLElement | undefined;\n #media: MediaQueryList | undefined;\n #context: Readonly<Record<string, string | number | boolean | null>> | undefined;\n sessionEndpoint = '';\n\n connectedCallback(): void {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n if (!this.sessionEndpoint) this.sessionEndpoint = this.getAttribute('session-endpoint') ?? '';\n this.#media = globalThis.matchMedia?.('(prefers-color-scheme: dark)');\n this.#media?.addEventListener('change', this.#handleSystemTheme);\n document.addEventListener('keydown', this.#handleDocumentKeydown);\n document.addEventListener('pointerdown', this.#handleDocumentPointerDown);\n if (this.#appearance.behavior.startOpen) this.setAttribute('open', '');\n this.#render();\n this.dispatchEvent(new CustomEvent('assistant-ready'));\n }\n\n disconnectedCallback(): void {\n this.#media?.removeEventListener('change', this.#handleSystemTheme);\n document.removeEventListener('keydown', this.#handleDocumentKeydown);\n document.removeEventListener('pointerdown', this.#handleDocumentPointerDown);\n }\n\n attributeChangedCallback(name: string): void {\n if (name === 'theme') this.#applyTheme();\n }\n\n open(): void {\n this.setAttribute('open', '');\n this.dispatchEvent(new CustomEvent('assistant-open'));\n }\n\n close(): void {\n this.removeAttribute('open');\n this.dispatchEvent(new CustomEvent('assistant-close'));\n }\n\n toggle(): void {\n this.hasAttribute('open') ? this.close() : this.open();\n }\n\n focusComposer(): void {\n this.shadowRoot?.querySelector<HTMLTextAreaElement>('textarea')?.focus();\n }\n\n resetSession(): void {\n this.#session = undefined;\n this.#messages?.replaceChildren();\n this.dispatchEvent(new CustomEvent('assistant-session-reset'));\n }\n\n updateContext(context: Readonly<Record<string, string | number | boolean | null>>): void {\n this.#context = { ...context };\n this.dispatchEvent(new CustomEvent('assistant-context-changed', { detail: { context } }));\n }\n\n async sendMessage(text: string): Promise<void> {\n const message = text.trim();\n if (!message) return;\n if (!this.#session) this.#session = await this.#createSession();\n this.#appendMessage('user', message);\n this.dispatchEvent(new CustomEvent('assistant-message-started'));\n await this.#sendTurn(message, true);\n }\n\n async #sendTurn(message: string, mayRetry: boolean): Promise<void> {\n if (!this.#session) this.#session = await this.#createSession();\n const response = await fetch(this.#session.endpoints.turns, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.#session.token}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({ message }),\n });\n if (response.status === 401 && mayRetry) {\n this.#session = undefined;\n this.dispatchEvent(new CustomEvent('assistant-session-expired'));\n await this.#sendTurn(message, false);\n return;\n }\n if (!response.ok) {\n this.#dispatchError({ code: 'turn_failed', status: response.status, retryable: false });\n throw new Error(`Assistant turn failed (${response.status})`);\n }\n let assistantBody: HTMLElement | undefined;\n try {\n await consumeAssistantEvents(response, (event) => {\n if (event.event === 'content') {\n const body = assistantBody ?? this.#appendMessage('assistant', '');\n assistantBody = body;\n if (body) body.textContent += String(event.data.delta ?? '');\n }\n if (event.event === 'tool_proposed') {\n this.#appendToolProposal(\n String(event.data.id ?? ''),\n String(event.data.tool ?? 'Action'),\n );\n }\n if (event.event === 'error') {\n this.#dispatchError({\n code: String(event.data.code ?? 'stream_failed'),\n retryable: event.data.retryable === true,\n });\n }\n });\n } catch (error) {\n if (error instanceof AssistantTransportError) {\n this.#dispatchError({ code: error.code, retryable: false });\n }\n throw error;\n }\n this.dispatchEvent(new CustomEvent('assistant-message-completed'));\n }\n\n /**\n * Every listener the element attaches to its own DOM must go through this guard: internal UI\n * failures surface as `assistant-error` events (already dispatched by the failing path) and must\n * never escape as unhandled rejections into the embedding page. Programmatic callers use\n * `sendMessage`/`confirmTool` directly and keep the rejection.\n */\n #sendGuarded(text: string): void {\n void this.sendMessage(text).catch(() => {});\n }\n\n async confirmTool(id: string): Promise<void> {\n if (!this.#session) {\n this.#dispatchError({ code: 'confirmation_expired', retryable: false });\n throw new Error('assistant session is not active');\n }\n const response = await fetch(this.#session.endpoints.toolConfirmations, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.#session.token}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({ id }),\n });\n if (!response.ok) {\n const expired = response.status === 401 || response.status === 409;\n if (response.status === 401) {\n this.#session = undefined;\n this.dispatchEvent(new CustomEvent('assistant-session-expired'));\n }\n this.#dispatchError({\n code: expired ? 'confirmation_expired' : 'confirmation_failed',\n status: response.status,\n retryable: false,\n });\n throw new Error(`Assistant confirmation failed (${response.status})`);\n }\n let completed: Readonly<Record<string, unknown>> | undefined;\n await consumeAssistantEvents(response, (event) => {\n if (event.event === 'tool_completed') completed = event.data;\n });\n if (completed) this.#appendMessage('assistant', JSON.stringify(completed.result ?? {}));\n this.dispatchEvent(new CustomEvent('assistant-tool-completed', { detail: { id } }));\n }\n\n #handleSystemTheme = (): void => this.#applyTheme();\n\n #handleDocumentKeydown = (event: KeyboardEvent): void => {\n if (\n event.key === 'Escape' &&\n this.hasAttribute('open') &&\n this.#appearance.behavior.closeOnEscape\n ) {\n this.close();\n }\n };\n\n #handleDocumentPointerDown = (event: PointerEvent): void => {\n if (\n this.hasAttribute('open') &&\n this.#appearance.behavior.closeOnOutsideClick &&\n !event.composedPath().includes(this)\n ) {\n this.close();\n }\n };\n\n async #createSession(): Promise<SessionResponse> {\n if (!this.sessionEndpoint) throw new Error('sessionEndpoint is required');\n let response: Response;\n try {\n response = await fetch(this.sessionEndpoint, {\n method: 'POST',\n headers: { Accept: 'application/json', 'Content-Type': 'application/json' },\n body: JSON.stringify(this.#context ? { context: this.#context } : {}),\n credentials: 'same-origin',\n });\n } catch (error) {\n this.#dispatchError({ code: 'session_failed', retryable: true });\n throw error;\n }\n if (!response.ok) {\n this.#dispatchError({ code: 'session_failed', status: response.status, retryable: true });\n throw new Error(`Assistant session failed (${response.status})`);\n }\n let session: SessionResponse;\n try {\n session = (await response.json()) as SessionResponse;\n } catch (error) {\n this.#dispatchError({ code: 'session_failed', retryable: true });\n throw error;\n }\n if (session.configuration) {\n this.#appearance = resolveAppearance(session.configuration);\n this.#render();\n }\n this.dispatchEvent(\n new CustomEvent('assistant-session-started', { detail: { expiresAt: session.expiresAt } }),\n );\n return session;\n }\n\n #appendMessage(role: 'user' | 'assistant', text: string): HTMLElement | undefined {\n if (!this.#messages) return undefined;\n const message = document.createElement('div');\n message.className = `message ${role}`;\n if (\n role === 'assistant' &&\n this.#appearance.behavior.showAvatars &&\n this.#appearance.brand.avatar[this.#resolvedMode()]\n ) {\n const avatar = document.createElement('img');\n avatar.className = 'avatar';\n avatar.src = this.#appearance.brand.avatar[this.#resolvedMode()] ?? '';\n avatar.alt = '';\n message.append(avatar);\n }\n const body = document.createElement('span');\n body.textContent = text;\n message.append(body);\n if (this.#appearance.behavior.showTimestamps) {\n const timestamp = document.createElement('time');\n timestamp.dateTime = new Date().toISOString();\n timestamp.textContent = new Intl.DateTimeFormat(this.#appearance.locale, {\n hour: 'numeric',\n minute: '2-digit',\n }).format(new Date());\n message.append(timestamp);\n }\n this.#messages.append(message);\n return body;\n }\n\n #dispatchError(detail: AssistantErrorDetail): void {\n this.dispatchEvent(new CustomEvent('assistant-error', { detail }));\n }\n\n #appendToolProposal(id: string, tool: string): void {\n if (!this.#messages || !id) return;\n const card = document.createElement('section');\n card.className = 'tool-proposal';\n const label = document.createElement('strong');\n label.textContent = tool;\n const confirm = document.createElement('button');\n confirm.type = 'button';\n confirm.textContent = this.#appearance.labels.confirm;\n confirm.addEventListener('click', () => {\n confirm.disabled = true;\n void this.confirmTool(id).catch(() => {\n confirm.disabled = false;\n this.dispatchEvent(\n new CustomEvent('assistant-error', { detail: { code: 'confirmation_failed' } }),\n );\n });\n });\n const cancel = document.createElement('button');\n cancel.type = 'button';\n cancel.textContent = this.#appearance.labels.cancel;\n cancel.addEventListener('click', () => card.remove());\n card.append(label, confirm, cancel);\n this.#messages.append(card);\n this.dispatchEvent(new CustomEvent('assistant-tool-proposed', { detail: { id, tool } }));\n }\n\n #resolvedMode(): Exclude<AssistantThemeMode, 'auto'> {\n const configured =\n (this.getAttribute('theme') as AssistantThemeMode | null) ??\n this.#appearance.theme.defaultMode;\n return configured === 'auto' ? (this.#media?.matches ? 'dark' : 'light') : configured;\n }\n\n #applyTheme(): void {\n const mode = this.#resolvedMode();\n this.setAttribute('data-theme', mode);\n const tokens = this.#appearance.theme[mode];\n for (const [name, value] of Object.entries(tokens)) {\n this.style.setProperty(\n `--ns-assistant-default-${camelToKebab(name)}`,\n tokenValue(name, value),\n );\n }\n this.style.setProperty(\n '--ns-assistant-default-panel-width',\n `${this.#appearance.layout.panelWidth}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-min-height',\n `${this.#appearance.layout.panelMinHeight}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-max-height',\n `${this.#appearance.layout.panelMaxHeight}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-z-index',\n String(this.#appearance.layout.zIndex),\n );\n const logo = this.shadowRoot?.querySelector<HTMLImageElement>('.brand-logo');\n const logoUrl = this.#appearance.brand.logo[mode];\n if (logo) {\n logo.hidden = !logoUrl;\n if (logoUrl) logo.src = logoUrl;\n }\n }\n\n #render(): void {\n if (!this.shadowRoot) return;\n const appearance = this.#appearance;\n this.setAttribute('role', 'complementary');\n this.setAttribute('aria-label', appearance.brand.name);\n this.setAttribute('lang', appearance.locale);\n this.setAttribute('dir', appearance.direction);\n this.dataset.mode = appearance.layout.mode;\n this.dataset.position = appearance.layout.position;\n this.dataset.density = appearance.layout.density;\n this.toggleAttribute('mobile-fullscreen', appearance.layout.mobileFullscreen);\n this.shadowRoot.innerHTML = `${styles}\n <button class=\"launcher\" type=\"button\" aria-label=\"${escapeAttribute(appearance.labels.open)}\"><slot name=\"launcher-icon\">✦</slot></button>\n <section class=\"panel\" aria-label=\"${escapeAttribute(appearance.brand.name)}\">\n <header><slot name=\"header-leading\"></slot><img class=\"brand-logo\" alt=\"\"><strong></strong><slot name=\"header-actions\"></slot><button class=\"close\" type=\"button\" aria-label=\"${escapeAttribute(appearance.labels.close)}\">×</button></header>\n <div class=\"welcome\"><slot name=\"empty-state\"><h2></h2><p></p></slot></div>\n <div class=\"suggested-prompts\"></div>\n <div class=\"messages\" aria-live=\"polite\"></div>\n <form><slot name=\"composer-leading\"></slot><textarea rows=\"1\"></textarea><button class=\"send\" type=\"submit\"></button><slot name=\"composer-trailing\"></slot></form>\n <nav class=\"legal\" aria-label=\"Legal\"></nav>\n <slot name=\"conversation-footer\"></slot>\n </section>`;\n queryRequired<HTMLElement>(this.shadowRoot, 'strong').textContent = appearance.brand.name;\n const launcherIcon = appearance.brand.mark[this.#resolvedMode()];\n if (launcherIcon) {\n const launcherSlot = queryRequired<HTMLSlotElement>(\n this.shadowRoot,\n 'slot[name=\"launcher-icon\"]',\n );\n const icon = document.createElement('img');\n icon.src = launcherIcon;\n icon.alt = '';\n launcherSlot.replaceChildren(icon);\n }\n const logo = queryRequired<HTMLImageElement>(this.shadowRoot, '.brand-logo');\n const logoUrl = appearance.brand.logo[this.#resolvedMode()];\n if (logoUrl) {\n logo.src = logoUrl;\n logo.alt = appearance.brand.name;\n } else {\n logo.hidden = true;\n }\n queryRequired<HTMLElement>(this.shadowRoot, 'h2').textContent =\n appearance.labels.welcomeHeading;\n queryRequired<HTMLElement>(this.shadowRoot, 'p').textContent = appearance.labels.welcomeMessage;\n const textarea = queryRequired<HTMLTextAreaElement>(this.shadowRoot, 'textarea');\n textarea.placeholder = appearance.labels.composerPlaceholder;\n textarea.setAttribute('aria-label', appearance.labels.composerPlaceholder);\n queryRequired<HTMLElement>(this.shadowRoot, '.send').textContent = appearance.labels.send;\n const prompts = queryRequired<HTMLElement>(this.shadowRoot, '.suggested-prompts');\n for (const prompt of appearance.suggestedPrompts) {\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = prompt;\n button.addEventListener('click', () => this.#sendGuarded(prompt));\n prompts.append(button);\n }\n if (!appearance.behavior.showLauncher)\n queryRequired<HTMLElement>(this.shadowRoot, '.launcher').hidden = true;\n if (!appearance.behavior.showHeader)\n queryRequired<HTMLElement>(this.shadowRoot, 'header').hidden = true;\n const legal = queryRequired<HTMLElement>(this.shadowRoot, '.legal');\n for (const [label, href] of [\n ['Privacy', appearance.privacyUrl],\n ['Terms', appearance.termsUrl],\n ] as const) {\n if (!href) continue;\n const link = document.createElement('a');\n link.href = href;\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.textContent = label;\n legal.append(link);\n }\n this.#messages = this.shadowRoot.querySelector('.messages') ?? undefined;\n this.shadowRoot.querySelector('.launcher')?.addEventListener('click', () => this.open());\n this.shadowRoot.querySelector('.close')?.addEventListener('click', () => this.close());\n this.shadowRoot.querySelector('form')?.addEventListener('submit', (event) => {\n event.preventDefault();\n const value = textarea.value;\n textarea.value = '';\n this.#sendGuarded(value);\n });\n this.#applyTheme();\n }\n}\n\nexport function registerNoodleAssistant(): void {\n if (globalThis.customElements && !customElements.get(ASSISTANT_TAG_NAME)) {\n customElements.define(ASSISTANT_TAG_NAME, NoodleAssistantElement);\n }\n}\n\nfunction camelToKebab(value: string): string {\n return value.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n}\n\nfunction tokenValue(name: string, value: AssistantThemeTokens[keyof AssistantThemeTokens]): string {\n if (typeof value !== 'number') return value;\n if (name === 'lineHeight' || name === 'motionScale') return String(value);\n return `${value}px`;\n}\n\nfunction escapeAttribute(value: string): string {\n return value.replaceAll('&', '&amp;').replaceAll('\"', '&quot;').replaceAll('<', '&lt;');\n}\n\nfunction queryRequired<T extends Element>(root: ShadowRoot, selector: string): T {\n const element = root.querySelector<T>(selector);\n if (!element) throw new Error(`assistant renderer is missing ${selector}`);\n return element;\n}\n\nconst styles = `<style>\n :host { color-scheme: light dark; font-family: var(--ns-assistant-font-family, var(--ns-assistant-default-font-family)); font-size: var(--ns-assistant-base-font-size, var(--ns-assistant-default-base-font-size)); line-height: var(--ns-assistant-line-height, var(--ns-assistant-default-line-height)); z-index: var(--ns-assistant-z-index, var(--ns-assistant-default-z-index)); }\n :host([data-mode=\"floating\"]) { position: fixed; bottom: 24px; right: 24px; }\n :host([data-mode=\"floating\"][data-position=\"bottom-left\"]) { right: auto; left: 24px; }\n .launcher { width: 54px; height: 54px; border: 0; border-radius: var(--ns-assistant-launcher-radius, var(--ns-assistant-default-launcher-radius)); color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); cursor: pointer; }\n .launcher img { width: 24px; height: 24px; object-fit: contain; }\n .panel { display: none; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 32px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 32px)); overflow: hidden; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); }\n :host([open]) .panel { display: grid; grid-template-rows: auto auto 1fr auto; }\n :host([open]) .launcher { display: none; }\n header { display: flex; gap: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); align-items: center; padding: calc(var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)) * 1.2); border-bottom: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); }\n header strong { flex: 1; }\n .brand-logo { display: block; max-width: 120px; max-height: 28px; object-fit: contain; }\n button { font: inherit; }\n .close, .send { border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); cursor: pointer; }\n .close { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; font-size: 24px; }\n .welcome { padding: calc(var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)) * 1.5); }\n .welcome h2 { margin: 0; font-size: 1.25em; }\n .welcome p { margin: 6px 0 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }\n .suggested-prompts { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); }\n .suggested-prompts:empty { display: none; }\n .suggested-prompts button { padding: 7px 10px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: transparent; border: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: 999px; cursor: pointer; }\n .messages { min-height: 120px; padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); overflow: auto; }\n .message { width: fit-content; max-width: 84%; margin: 8px 0; padding: 10px 12px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); white-space: pre-wrap; }\n .message .avatar { float: left; width: 24px; height: 24px; margin-right: 8px; border-radius: 50%; object-fit: cover; }\n .message time { display: block; margin-top: 4px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .75em; }\n .message.user { margin-left: auto; color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n .tool-proposal { display: grid; grid-template-columns: 1fr auto auto; gap: 8px; align-items: center; margin: 10px 0; padding: 12px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); }\n .tool-proposal button { padding: 8px 10px; border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); cursor: pointer; }\n .tool-proposal button:first-of-type { color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n form { display: flex; gap: 8px; align-items: end; padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); border-top: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); }\n textarea { flex: 1; resize: none; padding: 10px 12px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); border: 0; border-radius: var(--ns-assistant-input-radius, var(--ns-assistant-default-input-radius)); font: inherit; }\n textarea:focus-visible, button:focus-visible { outline: 3px solid var(--ns-assistant-focus, var(--ns-assistant-default-focus)); outline-offset: 2px; }\n .send { padding: 10px 14px; color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n .legal { display: flex; gap: 12px; justify-content: center; padding: 0 12px 10px; font-size: .8em; }\n .legal:empty { display: none; }\n .legal a { color: var(--ns-assistant-link, var(--ns-assistant-default-link)); }\n :host([data-density=\"compact\"]) .welcome { padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); }\n @media (max-width: 640px) { :host([mobile-fullscreen][open]) { inset: 0; } :host([mobile-fullscreen][open]) .panel { width: 100vw; min-height: 100vh; max-height: 100vh; border-radius: 0; } }\n @media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; } }\n @media (max-width: 560px) { :host([data-mode=\"floating\"]) { inset: auto 12px 12px; } :host([open]) .panel { width: calc(100vw - 24px); max-height: calc(100vh - 24px); } }\n</style>`;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/appearance.ts","../src/transport.ts","../src/element.ts"],"sourcesContent":["export {\n ASSISTANT_TAG_NAME,\n NoodleAssistantElement,\n registerNoodleAssistant,\n} from './element.js';\nexport type { AssistantErrorDetail, AssistantEvent } from './transport.js';\n\nimport { registerNoodleAssistant } from './element.js';\n\nregisterNoodleAssistant();\n","export type AssistantThemeMode = 'auto' | 'light' | 'dark';\nexport type AssistantLayoutMode = 'floating' | 'inline' | 'drawer';\nexport type AssistantPosition = 'bottom-left' | 'bottom-right';\n\nexport interface AssistantThemeTokens {\n readonly page: string;\n readonly panel: string;\n readonly elevated: string;\n readonly input: string;\n readonly hover: string;\n readonly selected: string;\n readonly text: string;\n readonly mutedText: string;\n readonly accent: string;\n readonly accentText: string;\n readonly link: string;\n readonly divider: string;\n readonly focus: string;\n readonly success: string;\n readonly warning: string;\n readonly danger: string;\n readonly overlay: string;\n readonly code: string;\n readonly widgetFrame: string;\n readonly fontFamily: string;\n readonly monoFontFamily: string;\n readonly baseFontSize: number;\n readonly messageFontSize: number;\n readonly lineHeight: number;\n readonly panelRadius: number;\n readonly cardRadius: number;\n readonly inputRadius: number;\n readonly buttonRadius: number;\n readonly launcherRadius: number;\n readonly spacing: number;\n readonly shadow: string;\n readonly backdropBlur: number;\n readonly motionScale: number;\n}\n\nexport interface AssistantConfiguration {\n readonly branding?: {\n readonly name?: string;\n readonly accent?: string;\n readonly surface?: string;\n readonly surfaceDark?: string;\n readonly logo?: AssistantBrandAsset;\n readonly mark?: AssistantBrandAsset;\n readonly avatar?: AssistantBrandAsset;\n readonly theme?: {\n readonly light?: BrandThemeOverrides;\n readonly dark?: BrandThemeOverrides;\n };\n readonly radius?: 'none' | 'sm' | 'md' | 'lg';\n readonly density?: 'compact' | 'comfortable';\n readonly typography?: 'system' | 'serif' | 'mono';\n readonly colorScheme?: AssistantThemeMode;\n };\n readonly assistant?: AssistantUiConfiguration;\n}\n\ninterface AssistantBrandAsset {\n readonly uri: string;\n readonly darkUri?: string;\n readonly alt: string;\n}\n\ninterface BrandThemeOverrides {\n readonly surface?: string;\n readonly surfaceRaised?: string;\n readonly surfaceMuted?: string;\n readonly text?: string;\n readonly textMuted?: string;\n readonly accent?: string;\n readonly accentText?: string;\n readonly link?: string;\n readonly border?: string;\n readonly borderStrong?: string;\n readonly focus?: string;\n readonly success?: string;\n readonly warning?: string;\n readonly danger?: string;\n readonly code?: string;\n}\n\ninterface AssistantUiConfiguration {\n readonly layout?: {\n readonly mode?: AssistantLayoutMode;\n readonly position?: AssistantPosition;\n readonly panelWidth?: number;\n readonly panelMinHeight?: number;\n readonly panelMaxHeight?: number;\n readonly zIndex?: number;\n readonly density?: 'compact' | 'comfortable';\n readonly mobileFullscreen?: boolean;\n };\n readonly behavior?: {\n readonly startOpen?: boolean;\n readonly closeOnEscape?: boolean;\n readonly closeOnOutsideClick?: boolean;\n readonly showLauncher?: boolean;\n readonly showHeader?: boolean;\n readonly showAvatars?: boolean;\n readonly showTimestamps?: boolean;\n };\n readonly labels?: Partial<AssistantLabels>;\n readonly suggestedPrompts?: readonly string[];\n readonly privacyUrl?: string;\n readonly termsUrl?: string;\n readonly locale?: string;\n readonly direction?: 'ltr' | 'rtl' | 'auto';\n}\n\nexport interface AssistantLabels {\n readonly welcomeHeading: string;\n readonly welcomeMessage: string;\n readonly composerPlaceholder: string;\n readonly send: string;\n readonly stop: string;\n readonly close: string;\n readonly open: string;\n readonly confirm: string;\n readonly cancel: string;\n readonly retry: string;\n readonly unavailable: string;\n readonly sessionExpired: string;\n}\n\nexport interface ResolvedAssistantAppearance {\n readonly brand: {\n readonly name: string;\n readonly logo: { readonly light?: string; readonly dark?: string };\n readonly avatar: { readonly light?: string; readonly dark?: string };\n readonly mark: { readonly light?: string; readonly dark?: string };\n };\n readonly theme: {\n readonly defaultMode: AssistantThemeMode;\n readonly light: AssistantThemeTokens;\n readonly dark: AssistantThemeTokens;\n };\n readonly layout: {\n readonly mode: AssistantLayoutMode;\n readonly position: AssistantPosition;\n readonly panelWidth: number;\n readonly panelMinHeight: number;\n readonly panelMaxHeight: number;\n readonly zIndex: number;\n readonly density: 'compact' | 'comfortable';\n readonly mobileFullscreen: boolean;\n };\n readonly behavior: {\n readonly startOpen: boolean;\n readonly closeOnEscape: boolean;\n readonly closeOnOutsideClick: boolean;\n readonly showLauncher: boolean;\n readonly showHeader: boolean;\n readonly showAvatars: boolean;\n readonly showTimestamps: boolean;\n };\n readonly labels: AssistantLabels;\n readonly suggestedPrompts: readonly string[];\n readonly privacyUrl?: string;\n readonly termsUrl?: string;\n readonly locale: string;\n readonly direction: 'ltr' | 'rtl' | 'auto';\n}\n\nconst common = {\n fontFamily: 'inherit',\n monoFontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n baseFontSize: 15,\n messageFontSize: 15,\n lineHeight: 1.5,\n panelRadius: 20,\n cardRadius: 14,\n inputRadius: 14,\n buttonRadius: 12,\n launcherRadius: 999,\n spacing: 12,\n backdropBlur: 18,\n motionScale: 1,\n} as const;\n\nexport const DEFAULT_APPEARANCE: ResolvedAssistantAppearance = {\n brand: { name: 'Assistant', logo: {}, avatar: {}, mark: {} },\n theme: {\n defaultMode: 'auto',\n light: {\n ...common,\n page: '#F7F7F8',\n panel: '#FFFFFF',\n elevated: '#FFFFFF',\n input: '#F1F1F3',\n hover: '#ECECEF',\n selected: '#E4E2FF',\n text: '#18181B',\n mutedText: '#71717A',\n accent: '#5B4CF0',\n accentText: '#FFFFFF',\n link: '#4A3BD5',\n divider: '#E4E4E7',\n focus: '#5B4CF0',\n success: '#16835D',\n warning: '#A45B00',\n danger: '#C92A45',\n overlay: '#18181B66',\n code: '#F1F1F3',\n widgetFrame: '#E4E4E7',\n shadow: '0 24px 80px rgba(24, 24, 27, 0.18)',\n },\n dark: {\n ...common,\n page: '#111113',\n panel: '#19191D',\n elevated: '#222228',\n input: '#26262C',\n hover: '#303038',\n selected: '#37315F',\n text: '#FAFAFA',\n mutedText: '#A1A1AA',\n accent: '#A99FFF',\n accentText: '#17131F',\n link: '#B9B1FF',\n divider: '#34343B',\n focus: '#B9B1FF',\n success: '#58C69A',\n warning: '#F2B45F',\n danger: '#FF8094',\n overlay: '#00000099',\n code: '#26262C',\n widgetFrame: '#34343B',\n shadow: '0 24px 90px rgba(0, 0, 0, 0.55)',\n },\n },\n layout: {\n mode: 'floating',\n position: 'bottom-right',\n panelWidth: 400,\n panelMinHeight: 420,\n panelMaxHeight: 720,\n zIndex: 2147483000,\n density: 'comfortable',\n mobileFullscreen: true,\n },\n behavior: {\n startOpen: false,\n closeOnEscape: true,\n closeOnOutsideClick: false,\n showLauncher: true,\n showHeader: true,\n showAvatars: true,\n showTimestamps: false,\n },\n labels: {\n welcomeHeading: 'How can I help?',\n welcomeMessage: '',\n composerPlaceholder: 'Ask a question…',\n send: 'Send',\n stop: 'Stop',\n close: 'Close assistant',\n open: 'Open assistant',\n confirm: 'Confirm',\n cancel: 'Cancel',\n retry: 'Try again',\n unavailable: 'The assistant is temporarily unavailable.',\n sessionExpired: 'Your assistant session expired. Reopen it to continue.',\n },\n suggestedPrompts: [],\n locale: 'en',\n direction: 'auto',\n};\n\nexport function resolveAppearance(input: AssistantConfiguration = {}): ResolvedAssistantAppearance {\n const branding = input.branding;\n const assistant = input.assistant;\n return {\n brand: {\n ...DEFAULT_APPEARANCE.brand,\n ...(branding?.name ? { name: branding.name } : {}),\n logo: themedAsset(branding?.logo),\n avatar: themedAsset(branding?.avatar),\n mark: themedAsset(branding?.mark),\n },\n theme: {\n defaultMode: branding?.colorScheme ?? DEFAULT_APPEARANCE.theme.defaultMode,\n light: resolveTheme('light', branding),\n dark: resolveTheme('dark', branding),\n },\n layout: {\n ...DEFAULT_APPEARANCE.layout,\n ...(branding?.density ? { density: branding.density } : {}),\n ...assistant?.layout,\n },\n behavior: { ...DEFAULT_APPEARANCE.behavior, ...assistant?.behavior },\n labels: { ...DEFAULT_APPEARANCE.labels, ...assistant?.labels },\n suggestedPrompts: assistant?.suggestedPrompts ?? DEFAULT_APPEARANCE.suggestedPrompts,\n ...(assistant?.privacyUrl ? { privacyUrl: assistant.privacyUrl } : {}),\n ...(assistant?.termsUrl ? { termsUrl: assistant.termsUrl } : {}),\n locale: assistant?.locale ?? DEFAULT_APPEARANCE.locale,\n direction: assistant?.direction ?? DEFAULT_APPEARANCE.direction,\n };\n}\n\nfunction themedAsset(asset: AssistantBrandAsset | undefined): {\n readonly light?: string;\n readonly dark?: string;\n} {\n return asset ? { light: asset.uri, dark: asset.darkUri ?? asset.uri } : {};\n}\n\nfunction resolveTheme(\n mode: 'light' | 'dark',\n branding: AssistantConfiguration['branding'],\n): AssistantThemeTokens {\n const defaults = DEFAULT_APPEARANCE.theme[mode];\n const surface = mode === 'light' ? branding?.surface : branding?.surfaceDark;\n const portable = branding?.theme?.[mode];\n const radius = branding?.radius ? radiusValue(branding.radius) : undefined;\n return {\n ...defaults,\n ...(branding?.accent ? { accent: branding.accent } : {}),\n ...(surface ? { page: surface, panel: surface } : {}),\n ...mapPortableTheme(portable),\n ...(radius === undefined\n ? {}\n : {\n panelRadius: radius,\n cardRadius: radius,\n inputRadius: Math.max(0, radius - 2),\n buttonRadius: Math.max(0, radius - 2),\n }),\n ...(branding?.typography === 'serif'\n ? { fontFamily: 'ui-serif, Georgia, serif' }\n : branding?.typography === 'mono'\n ? { fontFamily: defaults.monoFontFamily }\n : {}),\n };\n}\n\nfunction mapPortableTheme(input: BrandThemeOverrides | undefined): Partial<AssistantThemeTokens> {\n if (!input) return {};\n return {\n ...(input.surface ? { page: input.surface, panel: input.surface } : {}),\n ...(input.surfaceRaised ? { elevated: input.surfaceRaised } : {}),\n ...(input.surfaceMuted\n ? { input: input.surfaceMuted, hover: input.surfaceMuted, selected: input.surfaceMuted }\n : {}),\n ...(input.text ? { text: input.text } : {}),\n ...(input.textMuted ? { mutedText: input.textMuted } : {}),\n ...(input.accent ? { accent: input.accent } : {}),\n ...(input.accentText ? { accentText: input.accentText } : {}),\n ...(input.link ? { link: input.link } : {}),\n ...(input.border ? { divider: input.border, widgetFrame: input.border } : {}),\n ...(input.focus ? { focus: input.focus } : {}),\n ...(input.success ? { success: input.success } : {}),\n ...(input.warning ? { warning: input.warning } : {}),\n ...(input.danger ? { danger: input.danger } : {}),\n ...(input.code ? { code: input.code } : {}),\n };\n}\n\nfunction radiusValue(radius: 'none' | 'sm' | 'md' | 'lg'): number {\n if (radius === 'none') return 0;\n if (radius === 'sm') return 8;\n if (radius === 'lg') return 18;\n return 14;\n}\n","export interface AssistantEvent {\n readonly event: string;\n readonly data: Readonly<Record<string, unknown>>;\n}\n\nexport interface AssistantErrorDetail {\n readonly code: string;\n readonly status?: number;\n readonly retryable: boolean;\n}\n\n/**\n * A 2xx response whose body carried no assistant events at all — typically an auth redirect or\n * proxy page returning HTML with a 200. Silently rendering nothing strands the end user, so the\n * transport fails loudly instead (ADR 0151 hardening).\n */\nexport class AssistantTransportError extends Error {\n readonly code = 'invalid_response' as const;\n\n constructor(contentType: string) {\n super(`assistant response was not an event stream (content-type: ${contentType || 'unknown'})`);\n this.name = 'AssistantTransportError';\n }\n}\n\n/** Consume JSON-bearing server-sent events without buffering the whole assistant turn. */\nexport async function consumeAssistantEvents(\n response: Response,\n onEvent: (event: AssistantEvent) => void,\n): Promise<void> {\n let delivered = 0;\n let sawText = false;\n const deliver = (event: AssistantEvent): void => {\n delivered += 1;\n onEvent(event);\n };\n if (!response.body) {\n const text = await response.text();\n sawText = text.trim().length > 0;\n emitFrames(text, deliver, true);\n } else {\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let pending = '';\n while (true) {\n const { done, value } = await reader.read();\n const chunk = decoder.decode(value, { stream: !done });\n if (!sawText && chunk.trim().length > 0) sawText = true;\n pending += chunk;\n pending = emitFrames(pending, deliver, done);\n if (done) break;\n }\n }\n if (delivered === 0 && sawText) {\n throw new AssistantTransportError(response.headers.get('content-type') ?? '');\n }\n}\n\nfunction emitFrames(\n input: string,\n onEvent: (event: AssistantEvent) => void,\n flush: boolean,\n): string {\n const normalized = input.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n');\n const frames = normalized.split('\\n\\n');\n const pending = flush ? '' : (frames.pop() ?? '');\n for (const frame of frames) {\n const event = parseFrame(frame);\n if (event) onEvent(event);\n }\n if (flush && frames.length === 0 && normalized.trim()) {\n const event = parseFrame(normalized);\n if (event) onEvent(event);\n }\n return pending;\n}\n\nfunction parseFrame(frame: string): AssistantEvent | undefined {\n let event = 'message';\n const data: string[] = [];\n for (const line of frame.split('\\n')) {\n if (line.startsWith(':')) continue;\n const separator = line.indexOf(':');\n const field = separator < 0 ? line : line.slice(0, separator);\n const value = separator < 0 ? '' : line.slice(separator + 1).replace(/^ /, '');\n if (field === 'event') event = value;\n if (field === 'data') data.push(value);\n }\n if (data.length === 0) return undefined;\n try {\n return { event, data: JSON.parse(data.join('\\n')) as Readonly<Record<string, unknown>> };\n } catch {\n return undefined;\n }\n}\n","import {\n type AssistantConfiguration,\n type AssistantThemeMode,\n type AssistantThemeTokens,\n resolveAppearance,\n} from './appearance.js';\nimport {\n type AssistantErrorDetail,\n AssistantTransportError,\n consumeAssistantEvents,\n} from './transport.js';\n\nexport const ASSISTANT_TAG_NAME = 'noodle-assistant';\nconst HTMLElementBase: typeof HTMLElement =\n globalThis.HTMLElement ?? (class {} as unknown as typeof HTMLElement);\n\ninterface SessionResponse {\n readonly token: string;\n readonly expiresAt: string;\n readonly endpoints: {\n readonly turns: string;\n readonly toolConfirmations: string;\n };\n readonly configuration?: AssistantConfiguration;\n}\n\nexport class NoodleAssistantElement extends HTMLElementBase {\n static readonly observedAttributes = ['open', 'theme'];\n #appearance = resolveAppearance();\n #session: SessionResponse | undefined;\n #messages: HTMLElement | undefined;\n #media: MediaQueryList | undefined;\n #context: Readonly<Record<string, string | number | boolean | null>> | undefined;\n sessionEndpoint = '';\n\n connectedCallback(): void {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n if (!this.sessionEndpoint) this.sessionEndpoint = this.getAttribute('session-endpoint') ?? '';\n this.#media = globalThis.matchMedia?.('(prefers-color-scheme: dark)');\n this.#media?.addEventListener('change', this.#handleSystemTheme);\n document.addEventListener('keydown', this.#handleDocumentKeydown);\n document.addEventListener('pointerdown', this.#handleDocumentPointerDown);\n if (this.#appearance.behavior.startOpen) this.setAttribute('open', '');\n this.#render();\n this.dispatchEvent(new CustomEvent('assistant-ready'));\n }\n\n disconnectedCallback(): void {\n this.#media?.removeEventListener('change', this.#handleSystemTheme);\n document.removeEventListener('keydown', this.#handleDocumentKeydown);\n document.removeEventListener('pointerdown', this.#handleDocumentPointerDown);\n }\n\n attributeChangedCallback(name: string): void {\n if (name === 'theme') this.#applyTheme();\n }\n\n open(): void {\n this.setAttribute('open', '');\n this.dispatchEvent(new CustomEvent('assistant-open'));\n }\n\n close(): void {\n this.removeAttribute('open');\n this.dispatchEvent(new CustomEvent('assistant-close'));\n }\n\n toggle(): void {\n this.hasAttribute('open') ? this.close() : this.open();\n }\n\n focusComposer(): void {\n this.shadowRoot?.querySelector<HTMLTextAreaElement>('textarea')?.focus();\n }\n\n resetSession(): void {\n this.#session = undefined;\n this.#messages?.replaceChildren();\n this.dispatchEvent(new CustomEvent('assistant-session-reset'));\n }\n\n updateContext(context: Readonly<Record<string, string | number | boolean | null>>): void {\n this.#context = { ...context };\n this.dispatchEvent(new CustomEvent('assistant-context-changed', { detail: { context } }));\n }\n\n async sendMessage(text: string): Promise<void> {\n const message = text.trim();\n if (!message) return;\n if (!this.#session) this.#session = await this.#createSession();\n this.#appendMessage('user', message);\n this.dispatchEvent(new CustomEvent('assistant-message-started'));\n await this.#sendTurn(message, true);\n }\n\n async #sendTurn(message: string, mayRetry: boolean): Promise<void> {\n if (!this.#session) this.#session = await this.#createSession();\n const response = await fetch(this.#session.endpoints.turns, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.#session.token}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({ message }),\n });\n if (response.status === 401 && mayRetry) {\n this.#session = undefined;\n this.dispatchEvent(new CustomEvent('assistant-session-expired'));\n await this.#sendTurn(message, false);\n return;\n }\n if (!response.ok) {\n this.#dispatchError({ code: 'turn_failed', status: response.status, retryable: false });\n throw new Error(`Assistant turn failed (${response.status})`);\n }\n let assistantBody: HTMLElement | undefined;\n try {\n await consumeAssistantEvents(response, (event) => {\n if (event.event === 'content') {\n const body = assistantBody ?? this.#appendMessage('assistant', '');\n assistantBody = body;\n if (body) body.textContent += String(event.data.delta ?? '');\n }\n if (event.event === 'tool_proposed') {\n this.#appendToolProposal(\n String(event.data.id ?? ''),\n String(event.data.tool ?? 'Action'),\n );\n }\n if (event.event === 'error') {\n this.#dispatchError({\n code: String(event.data.code ?? 'stream_failed'),\n retryable: event.data.retryable === true,\n });\n }\n });\n } catch (error) {\n if (error instanceof AssistantTransportError) {\n this.#dispatchError({ code: error.code, retryable: false });\n }\n throw error;\n }\n this.dispatchEvent(new CustomEvent('assistant-message-completed'));\n }\n\n /**\n * Every listener the element attaches to its own DOM must go through this guard: internal UI\n * failures surface as `assistant-error` events (already dispatched by the failing path) and must\n * never escape as unhandled rejections into the embedding page. Programmatic callers use\n * `sendMessage`/`confirmTool` directly and keep the rejection.\n */\n #sendGuarded(text: string): void {\n void this.sendMessage(text).catch(() => {});\n }\n\n async confirmTool(id: string): Promise<void> {\n if (!this.#session) {\n this.#dispatchError({ code: 'confirmation_expired', retryable: false });\n throw new Error('assistant session is not active');\n }\n const response = await fetch(this.#session.endpoints.toolConfirmations, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.#session.token}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({ id }),\n });\n if (!response.ok) {\n const expired = response.status === 401 || response.status === 409;\n if (response.status === 401) {\n this.#session = undefined;\n this.dispatchEvent(new CustomEvent('assistant-session-expired'));\n }\n this.#dispatchError({\n code: expired ? 'confirmation_expired' : 'confirmation_failed',\n status: response.status,\n retryable: false,\n });\n throw new Error(`Assistant confirmation failed (${response.status})`);\n }\n let completed: Readonly<Record<string, unknown>> | undefined;\n let narrationBody: HTMLElement | undefined;\n await consumeAssistantEvents(response, (event) => {\n if (event.event === 'tool_completed') completed = event.data;\n if (event.event === 'content') {\n const body = narrationBody ?? this.#appendMessage('assistant', '');\n narrationBody = body;\n if (body) body.textContent += String(event.data.delta ?? '');\n }\n });\n // The narrated reply supersedes the raw result; older services send only tool_completed,\n // so the JSON rendering remains as the fallback.\n if (completed && !narrationBody) {\n this.#appendMessage('assistant', JSON.stringify(completed.result ?? {}));\n }\n this.dispatchEvent(new CustomEvent('assistant-tool-completed', { detail: { id } }));\n }\n\n #handleSystemTheme = (): void => this.#applyTheme();\n\n #handleDocumentKeydown = (event: KeyboardEvent): void => {\n if (\n event.key === 'Escape' &&\n this.hasAttribute('open') &&\n this.#appearance.behavior.closeOnEscape\n ) {\n this.close();\n }\n };\n\n #handleDocumentPointerDown = (event: PointerEvent): void => {\n if (\n this.hasAttribute('open') &&\n this.#appearance.behavior.closeOnOutsideClick &&\n !event.composedPath().includes(this)\n ) {\n this.close();\n }\n };\n\n async #createSession(): Promise<SessionResponse> {\n if (!this.sessionEndpoint) throw new Error('sessionEndpoint is required');\n let response: Response;\n try {\n response = await fetch(this.sessionEndpoint, {\n method: 'POST',\n headers: { Accept: 'application/json', 'Content-Type': 'application/json' },\n body: JSON.stringify(this.#context ? { context: this.#context } : {}),\n credentials: 'same-origin',\n });\n } catch (error) {\n this.#dispatchError({ code: 'session_failed', retryable: true });\n throw error;\n }\n if (!response.ok) {\n this.#dispatchError({ code: 'session_failed', status: response.status, retryable: true });\n throw new Error(`Assistant session failed (${response.status})`);\n }\n let session: SessionResponse;\n try {\n session = (await response.json()) as SessionResponse;\n } catch (error) {\n this.#dispatchError({ code: 'session_failed', retryable: true });\n throw error;\n }\n if (session.configuration) {\n this.#appearance = resolveAppearance(session.configuration);\n this.#render();\n }\n this.dispatchEvent(\n new CustomEvent('assistant-session-started', { detail: { expiresAt: session.expiresAt } }),\n );\n return session;\n }\n\n #appendMessage(role: 'user' | 'assistant', text: string): HTMLElement | undefined {\n if (!this.#messages) return undefined;\n const message = document.createElement('div');\n message.className = `message ${role}`;\n if (\n role === 'assistant' &&\n this.#appearance.behavior.showAvatars &&\n this.#appearance.brand.avatar[this.#resolvedMode()]\n ) {\n const avatar = document.createElement('img');\n avatar.className = 'avatar';\n avatar.src = this.#appearance.brand.avatar[this.#resolvedMode()] ?? '';\n avatar.alt = '';\n message.append(avatar);\n }\n const body = document.createElement('span');\n body.textContent = text;\n message.append(body);\n if (this.#appearance.behavior.showTimestamps) {\n const timestamp = document.createElement('time');\n timestamp.dateTime = new Date().toISOString();\n timestamp.textContent = new Intl.DateTimeFormat(this.#appearance.locale, {\n hour: 'numeric',\n minute: '2-digit',\n }).format(new Date());\n message.append(timestamp);\n }\n this.#messages.append(message);\n return body;\n }\n\n #dispatchError(detail: AssistantErrorDetail): void {\n this.dispatchEvent(new CustomEvent('assistant-error', { detail }));\n }\n\n #appendToolProposal(id: string, tool: string): void {\n if (!this.#messages || !id) return;\n const card = document.createElement('section');\n card.className = 'tool-proposal';\n const label = document.createElement('strong');\n label.textContent = tool;\n const confirm = document.createElement('button');\n confirm.type = 'button';\n confirm.textContent = this.#appearance.labels.confirm;\n confirm.addEventListener('click', () => {\n confirm.disabled = true;\n void this.confirmTool(id).catch(() => {\n confirm.disabled = false;\n this.dispatchEvent(\n new CustomEvent('assistant-error', { detail: { code: 'confirmation_failed' } }),\n );\n });\n });\n const cancel = document.createElement('button');\n cancel.type = 'button';\n cancel.textContent = this.#appearance.labels.cancel;\n cancel.addEventListener('click', () => card.remove());\n card.append(label, confirm, cancel);\n this.#messages.append(card);\n this.dispatchEvent(new CustomEvent('assistant-tool-proposed', { detail: { id, tool } }));\n }\n\n #resolvedMode(): Exclude<AssistantThemeMode, 'auto'> {\n const configured =\n (this.getAttribute('theme') as AssistantThemeMode | null) ??\n this.#appearance.theme.defaultMode;\n return configured === 'auto' ? (this.#media?.matches ? 'dark' : 'light') : configured;\n }\n\n #applyTheme(): void {\n const mode = this.#resolvedMode();\n this.setAttribute('data-theme', mode);\n const tokens = this.#appearance.theme[mode];\n for (const [name, value] of Object.entries(tokens)) {\n this.style.setProperty(\n `--ns-assistant-default-${camelToKebab(name)}`,\n tokenValue(name, value),\n );\n }\n this.style.setProperty(\n '--ns-assistant-default-panel-width',\n `${this.#appearance.layout.panelWidth}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-min-height',\n `${this.#appearance.layout.panelMinHeight}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-max-height',\n `${this.#appearance.layout.panelMaxHeight}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-z-index',\n String(this.#appearance.layout.zIndex),\n );\n const logo = this.shadowRoot?.querySelector<HTMLImageElement>('.brand-logo');\n const logoUrl = this.#appearance.brand.logo[mode];\n if (logo) {\n logo.hidden = !logoUrl;\n if (logoUrl) logo.src = logoUrl;\n }\n }\n\n #render(): void {\n if (!this.shadowRoot) return;\n const appearance = this.#appearance;\n this.setAttribute('role', 'complementary');\n this.setAttribute('aria-label', appearance.brand.name);\n this.setAttribute('lang', appearance.locale);\n this.setAttribute('dir', appearance.direction);\n this.dataset.mode = appearance.layout.mode;\n this.dataset.position = appearance.layout.position;\n this.dataset.density = appearance.layout.density;\n this.toggleAttribute('mobile-fullscreen', appearance.layout.mobileFullscreen);\n this.shadowRoot.innerHTML = `${styles}\n <button class=\"launcher\" type=\"button\" aria-label=\"${escapeAttribute(appearance.labels.open)}\"><slot name=\"launcher-icon\">✦</slot></button>\n <section class=\"panel\" aria-label=\"${escapeAttribute(appearance.brand.name)}\">\n <header><slot name=\"header-leading\"></slot><img class=\"brand-logo\" alt=\"\"><strong></strong><slot name=\"header-actions\"></slot><button class=\"close\" type=\"button\" aria-label=\"${escapeAttribute(appearance.labels.close)}\">×</button></header>\n <div class=\"welcome\"><slot name=\"empty-state\"><h2></h2><p></p></slot></div>\n <div class=\"suggested-prompts\"></div>\n <div class=\"messages\" aria-live=\"polite\"></div>\n <form><slot name=\"composer-leading\"></slot><textarea rows=\"1\"></textarea><button class=\"send\" type=\"submit\"></button><slot name=\"composer-trailing\"></slot></form>\n <nav class=\"legal\" aria-label=\"Legal\"></nav>\n <slot name=\"conversation-footer\"></slot>\n </section>`;\n queryRequired<HTMLElement>(this.shadowRoot, 'strong').textContent = appearance.brand.name;\n const launcherIcon = appearance.brand.mark[this.#resolvedMode()];\n if (launcherIcon) {\n const launcherSlot = queryRequired<HTMLSlotElement>(\n this.shadowRoot,\n 'slot[name=\"launcher-icon\"]',\n );\n const icon = document.createElement('img');\n icon.src = launcherIcon;\n icon.alt = '';\n launcherSlot.replaceChildren(icon);\n }\n const logo = queryRequired<HTMLImageElement>(this.shadowRoot, '.brand-logo');\n const logoUrl = appearance.brand.logo[this.#resolvedMode()];\n if (logoUrl) {\n logo.src = logoUrl;\n logo.alt = appearance.brand.name;\n } else {\n logo.hidden = true;\n }\n queryRequired<HTMLElement>(this.shadowRoot, 'h2').textContent =\n appearance.labels.welcomeHeading;\n queryRequired<HTMLElement>(this.shadowRoot, 'p').textContent = appearance.labels.welcomeMessage;\n const textarea = queryRequired<HTMLTextAreaElement>(this.shadowRoot, 'textarea');\n textarea.placeholder = appearance.labels.composerPlaceholder;\n textarea.setAttribute('aria-label', appearance.labels.composerPlaceholder);\n queryRequired<HTMLElement>(this.shadowRoot, '.send').textContent = appearance.labels.send;\n const prompts = queryRequired<HTMLElement>(this.shadowRoot, '.suggested-prompts');\n for (const prompt of appearance.suggestedPrompts) {\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = prompt;\n button.addEventListener('click', () => this.#sendGuarded(prompt));\n prompts.append(button);\n }\n if (!appearance.behavior.showLauncher)\n queryRequired<HTMLElement>(this.shadowRoot, '.launcher').hidden = true;\n if (!appearance.behavior.showHeader)\n queryRequired<HTMLElement>(this.shadowRoot, 'header').hidden = true;\n const legal = queryRequired<HTMLElement>(this.shadowRoot, '.legal');\n for (const [label, href] of [\n ['Privacy', appearance.privacyUrl],\n ['Terms', appearance.termsUrl],\n ] as const) {\n if (!href) continue;\n const link = document.createElement('a');\n link.href = href;\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.textContent = label;\n legal.append(link);\n }\n this.#messages = this.shadowRoot.querySelector('.messages') ?? undefined;\n this.shadowRoot.querySelector('.launcher')?.addEventListener('click', () => this.open());\n this.shadowRoot.querySelector('.close')?.addEventListener('click', () => this.close());\n this.shadowRoot.querySelector('form')?.addEventListener('submit', (event) => {\n event.preventDefault();\n const value = textarea.value;\n textarea.value = '';\n this.#sendGuarded(value);\n });\n this.#applyTheme();\n }\n}\n\nexport function registerNoodleAssistant(): void {\n if (globalThis.customElements && !customElements.get(ASSISTANT_TAG_NAME)) {\n customElements.define(ASSISTANT_TAG_NAME, NoodleAssistantElement);\n }\n}\n\nfunction camelToKebab(value: string): string {\n return value.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n}\n\nfunction tokenValue(name: string, value: AssistantThemeTokens[keyof AssistantThemeTokens]): string {\n if (typeof value !== 'number') return value;\n if (name === 'lineHeight' || name === 'motionScale') return String(value);\n return `${value}px`;\n}\n\nfunction escapeAttribute(value: string): string {\n return value.replaceAll('&', '&amp;').replaceAll('\"', '&quot;').replaceAll('<', '&lt;');\n}\n\nfunction queryRequired<T extends Element>(root: ShadowRoot, selector: string): T {\n const element = root.querySelector<T>(selector);\n if (!element) throw new Error(`assistant renderer is missing ${selector}`);\n return element;\n}\n\nconst styles = `<style>\n :host { color-scheme: light dark; font-family: var(--ns-assistant-font-family, var(--ns-assistant-default-font-family)); font-size: var(--ns-assistant-base-font-size, var(--ns-assistant-default-base-font-size)); line-height: var(--ns-assistant-line-height, var(--ns-assistant-default-line-height)); z-index: var(--ns-assistant-z-index, var(--ns-assistant-default-z-index)); }\n :host([data-mode=\"floating\"]) { position: fixed; bottom: 24px; right: 24px; }\n :host([data-mode=\"floating\"][data-position=\"bottom-left\"]) { right: auto; left: 24px; }\n .launcher { width: 54px; height: 54px; border: 0; border-radius: var(--ns-assistant-launcher-radius, var(--ns-assistant-default-launcher-radius)); color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); cursor: pointer; }\n .launcher img { width: 24px; height: 24px; object-fit: contain; }\n .panel { display: none; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 32px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 32px)); overflow: hidden; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); }\n :host([open]) .panel { display: grid; grid-template-rows: auto auto 1fr auto; }\n :host([open]) .launcher { display: none; }\n header { display: flex; gap: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); align-items: center; padding: calc(var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)) * 1.2); border-bottom: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); }\n header strong { flex: 1; }\n .brand-logo { display: block; max-width: 120px; max-height: 28px; object-fit: contain; }\n button { font: inherit; }\n .close, .send { border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); cursor: pointer; }\n .close { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; font-size: 24px; }\n .welcome { padding: calc(var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)) * 1.5); }\n .welcome h2 { margin: 0; font-size: 1.25em; }\n .welcome p { margin: 6px 0 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }\n .suggested-prompts { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); }\n .suggested-prompts:empty { display: none; }\n .suggested-prompts button { padding: 7px 10px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: transparent; border: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: 999px; cursor: pointer; }\n .messages { min-height: 120px; padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); overflow: auto; }\n .message { width: fit-content; max-width: 84%; margin: 8px 0; padding: 10px 12px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); white-space: pre-wrap; }\n .message .avatar { float: left; width: 24px; height: 24px; margin-right: 8px; border-radius: 50%; object-fit: cover; }\n .message time { display: block; margin-top: 4px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .75em; }\n .message.user { margin-left: auto; color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n .tool-proposal { display: grid; grid-template-columns: 1fr auto auto; gap: 8px; align-items: center; margin: 10px 0; padding: 12px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); }\n .tool-proposal button { padding: 8px 10px; border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); cursor: pointer; }\n .tool-proposal button:first-of-type { color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n form { display: flex; gap: 8px; align-items: end; padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); border-top: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); }\n textarea { flex: 1; resize: none; padding: 10px 12px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); border: 0; border-radius: var(--ns-assistant-input-radius, var(--ns-assistant-default-input-radius)); font: inherit; }\n textarea:focus-visible, button:focus-visible { outline: 3px solid var(--ns-assistant-focus, var(--ns-assistant-default-focus)); outline-offset: 2px; }\n .send { padding: 10px 14px; color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n .legal { display: flex; gap: 12px; justify-content: center; padding: 0 12px 10px; font-size: .8em; }\n .legal:empty { display: none; }\n .legal a { color: var(--ns-assistant-link, var(--ns-assistant-default-link)); }\n :host([data-density=\"compact\"]) .welcome { padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); }\n @media (max-width: 640px) { :host([mobile-fullscreen][open]) { inset: 0; } :host([mobile-fullscreen][open]) .panel { width: 100vw; min-height: 100vh; max-height: 100vh; border-radius: 0; } }\n @media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; } }\n @media (max-width: 560px) { :host([data-mode=\"floating\"]) { inset: auto 12px 12px; } :host([open]) .panel { width: calc(100vw - 24px); max-height: calc(100vh - 24px); } }\n</style>`;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACuKA,IAAM,SAAS;AAAA,EACb,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,SAAS;AAAA,EACT,cAAc;AAAA,EACd,aAAa;AACf;AAEO,IAAM,qBAAkD;AAAA,EAC7D,OAAO,EAAE,MAAM,aAAa,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,MAAM,CAAC,EAAE;AAAA,EAC3D,OAAO;AAAA,IACL,aAAa;AAAA,IACb,OAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM;AAAA,MACN,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,OAAO;AAAA,MACP,UAAU;AAAA,MACV,MAAM;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,MAAM;AAAA,MACN,aAAa;AAAA,MACb,QAAQ;AAAA,IACV;AAAA,IACA,MAAM;AAAA,MACJ,GAAG;AAAA,MACH,MAAM;AAAA,MACN,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,OAAO;AAAA,MACP,UAAU;AAAA,MACV,MAAM;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,MAAM;AAAA,MACN,aAAa;AAAA,MACb,QAAQ;AAAA,IACV;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,kBAAkB;AAAA,EACpB;AAAA,EACA,UAAU;AAAA,IACR,WAAW;AAAA,IACX,eAAe;AAAA,IACf,qBAAqB;AAAA,IACrB,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,gBAAgB;AAAA,EAClB;AAAA,EACA,QAAQ;AAAA,IACN,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,qBAAqB;AAAA,IACrB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,IACN,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,aAAa;AAAA,IACb,gBAAgB;AAAA,EAClB;AAAA,EACA,kBAAkB,CAAC;AAAA,EACnB,QAAQ;AAAA,EACR,WAAW;AACb;AAEO,SAAS,kBAAkB,QAAgC,CAAC,GAAgC;AACjG,QAAM,WAAW,MAAM;AACvB,QAAM,YAAY,MAAM;AACxB,SAAO;AAAA,IACL,OAAO;AAAA,MACL,GAAG,mBAAmB;AAAA,MACtB,GAAI,UAAU,OAAO,EAAE,MAAM,SAAS,KAAK,IAAI,CAAC;AAAA,MAChD,MAAM,YAAY,UAAU,IAAI;AAAA,MAChC,QAAQ,YAAY,UAAU,MAAM;AAAA,MACpC,MAAM,YAAY,UAAU,IAAI;AAAA,IAClC;AAAA,IACA,OAAO;AAAA,MACL,aAAa,UAAU,eAAe,mBAAmB,MAAM;AAAA,MAC/D,OAAO,aAAa,SAAS,QAAQ;AAAA,MACrC,MAAM,aAAa,QAAQ,QAAQ;AAAA,IACrC;AAAA,IACA,QAAQ;AAAA,MACN,GAAG,mBAAmB;AAAA,MACtB,GAAI,UAAU,UAAU,EAAE,SAAS,SAAS,QAAQ,IAAI,CAAC;AAAA,MACzD,GAAG,WAAW;AAAA,IAChB;AAAA,IACA,UAAU,EAAE,GAAG,mBAAmB,UAAU,GAAG,WAAW,SAAS;AAAA,IACnE,QAAQ,EAAE,GAAG,mBAAmB,QAAQ,GAAG,WAAW,OAAO;AAAA,IAC7D,kBAAkB,WAAW,oBAAoB,mBAAmB;AAAA,IACpE,GAAI,WAAW,aAAa,EAAE,YAAY,UAAU,WAAW,IAAI,CAAC;AAAA,IACpE,GAAI,WAAW,WAAW,EAAE,UAAU,UAAU,SAAS,IAAI,CAAC;AAAA,IAC9D,QAAQ,WAAW,UAAU,mBAAmB;AAAA,IAChD,WAAW,WAAW,aAAa,mBAAmB;AAAA,EACxD;AACF;AAEA,SAAS,YAAY,OAGnB;AACA,SAAO,QAAQ,EAAE,OAAO,MAAM,KAAK,MAAM,MAAM,WAAW,MAAM,IAAI,IAAI,CAAC;AAC3E;AAEA,SAAS,aACP,MACA,UACsB;AACtB,QAAM,WAAW,mBAAmB,MAAM,IAAI;AAC9C,QAAM,UAAU,SAAS,UAAU,UAAU,UAAU,UAAU;AACjE,QAAM,WAAW,UAAU,QAAQ,IAAI;AACvC,QAAM,SAAS,UAAU,SAAS,YAAY,SAAS,MAAM,IAAI;AACjE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAI,UAAU,SAAS,EAAE,QAAQ,SAAS,OAAO,IAAI,CAAC;AAAA,IACtD,GAAI,UAAU,EAAE,MAAM,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,IACnD,GAAG,iBAAiB,QAAQ;AAAA,IAC5B,GAAI,WAAW,SACX,CAAC,IACD;AAAA,MACE,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,aAAa,KAAK,IAAI,GAAG,SAAS,CAAC;AAAA,MACnC,cAAc,KAAK,IAAI,GAAG,SAAS,CAAC;AAAA,IACtC;AAAA,IACJ,GAAI,UAAU,eAAe,UACzB,EAAE,YAAY,2BAA2B,IACzC,UAAU,eAAe,SACvB,EAAE,YAAY,SAAS,eAAe,IACtC,CAAC;AAAA,EACT;AACF;AAEA,SAAS,iBAAiB,OAAuE;AAC/F,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,SAAO;AAAA,IACL,GAAI,MAAM,UAAU,EAAE,MAAM,MAAM,SAAS,OAAO,MAAM,QAAQ,IAAI,CAAC;AAAA,IACrE,GAAI,MAAM,gBAAgB,EAAE,UAAU,MAAM,cAAc,IAAI,CAAC;AAAA,IAC/D,GAAI,MAAM,eACN,EAAE,OAAO,MAAM,cAAc,OAAO,MAAM,cAAc,UAAU,MAAM,aAAa,IACrF,CAAC;AAAA,IACL,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,IACzC,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;AAAA,IACxD,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,IAC/C,GAAI,MAAM,aAAa,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;AAAA,IAC3D,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,IACzC,GAAI,MAAM,SAAS,EAAE,SAAS,MAAM,QAAQ,aAAa,MAAM,OAAO,IAAI,CAAC;AAAA,IAC3E,GAAI,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;AAAA,IAC5C,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,IAClD,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,IAClD,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,IAC/C,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,EAC3C;AACF;AAEA,SAAS,YAAY,QAA6C;AAChE,MAAI,WAAW,OAAQ,QAAO;AAC9B,MAAI,WAAW,KAAM,QAAO;AAC5B,MAAI,WAAW,KAAM,QAAO;AAC5B,SAAO;AACT;;;AC9VO,IAAM,0BAAN,cAAsC,MAAM;AAAA,EACxC,OAAO;AAAA,EAEhB,YAAY,aAAqB;AAC/B,UAAM,6DAA6D,eAAe,SAAS,GAAG;AAC9F,SAAK,OAAO;AAAA,EACd;AACF;AAGA,eAAsB,uBACpB,UACA,SACe;AACf,MAAI,YAAY;AAChB,MAAI,UAAU;AACd,QAAM,UAAU,CAAC,UAAgC;AAC/C,iBAAa;AACb,YAAQ,KAAK;AAAA,EACf;AACA,MAAI,CAAC,SAAS,MAAM;AAClB,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,cAAU,KAAK,KAAK,EAAE,SAAS;AAC/B,eAAW,MAAM,SAAS,IAAI;AAAA,EAChC,OAAO;AACL,UAAM,SAAS,SAAS,KAAK,UAAU;AACvC,UAAM,UAAU,IAAI,YAAY;AAChC,QAAI,UAAU;AACd,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAM,QAAQ,QAAQ,OAAO,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC;AACrD,UAAI,CAAC,WAAW,MAAM,KAAK,EAAE,SAAS,EAAG,WAAU;AACnD,iBAAW;AACX,gBAAU,WAAW,SAAS,SAAS,IAAI;AAC3C,UAAI,KAAM;AAAA,IACZ;AAAA,EACF;AACA,MAAI,cAAc,KAAK,SAAS;AAC9B,UAAM,IAAI,wBAAwB,SAAS,QAAQ,IAAI,cAAc,KAAK,EAAE;AAAA,EAC9E;AACF;AAEA,SAAS,WACP,OACA,SACA,OACQ;AACR,QAAM,aAAa,MAAM,WAAW,QAAQ,IAAI,EAAE,WAAW,MAAM,IAAI;AACvE,QAAM,SAAS,WAAW,MAAM,MAAM;AACtC,QAAM,UAAU,QAAQ,KAAM,OAAO,IAAI,KAAK;AAC9C,aAAW,SAAS,QAAQ;AAC1B,UAAM,QAAQ,WAAW,KAAK;AAC9B,QAAI,MAAO,SAAQ,KAAK;AAAA,EAC1B;AACA,MAAI,SAAS,OAAO,WAAW,KAAK,WAAW,KAAK,GAAG;AACrD,UAAM,QAAQ,WAAW,UAAU;AACnC,QAAI,MAAO,SAAQ,KAAK;AAAA,EAC1B;AACA,SAAO;AACT;AAEA,SAAS,WAAW,OAA2C;AAC7D,MAAI,QAAQ;AACZ,QAAM,OAAiB,CAAC;AACxB,aAAW,QAAQ,MAAM,MAAM,IAAI,GAAG;AACpC,QAAI,KAAK,WAAW,GAAG,EAAG;AAC1B,UAAM,YAAY,KAAK,QAAQ,GAAG;AAClC,UAAM,QAAQ,YAAY,IAAI,OAAO,KAAK,MAAM,GAAG,SAAS;AAC5D,UAAM,QAAQ,YAAY,IAAI,KAAK,KAAK,MAAM,YAAY,CAAC,EAAE,QAAQ,MAAM,EAAE;AAC7E,QAAI,UAAU,QAAS,SAAQ;AAC/B,QAAI,UAAU,OAAQ,MAAK,KAAK,KAAK;AAAA,EACvC;AACA,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,MAAI;AACF,WAAO,EAAE,OAAO,MAAM,KAAK,MAAM,KAAK,KAAK,IAAI,CAAC,EAAuC;AAAA,EACzF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AClFO,IAAM,qBAAqB;AAClC,IAAM,kBACJ,WAAW,eAAgB,MAAM;AAAC;AAY7B,IAAM,yBAAN,cAAqC,gBAAgB;AAAA,EAC1D,OAAgB,qBAAqB,CAAC,QAAQ,OAAO;AAAA,EACrD,cAAc,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAElB,oBAA0B;AACxB,QAAI,CAAC,KAAK,WAAY,MAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AACxD,QAAI,CAAC,KAAK,gBAAiB,MAAK,kBAAkB,KAAK,aAAa,kBAAkB,KAAK;AAC3F,SAAK,SAAS,WAAW,aAAa,8BAA8B;AACpE,SAAK,QAAQ,iBAAiB,UAAU,KAAK,kBAAkB;AAC/D,aAAS,iBAAiB,WAAW,KAAK,sBAAsB;AAChE,aAAS,iBAAiB,eAAe,KAAK,0BAA0B;AACxE,QAAI,KAAK,YAAY,SAAS,UAAW,MAAK,aAAa,QAAQ,EAAE;AACrE,SAAK,QAAQ;AACb,SAAK,cAAc,IAAI,YAAY,iBAAiB,CAAC;AAAA,EACvD;AAAA,EAEA,uBAA6B;AAC3B,SAAK,QAAQ,oBAAoB,UAAU,KAAK,kBAAkB;AAClE,aAAS,oBAAoB,WAAW,KAAK,sBAAsB;AACnE,aAAS,oBAAoB,eAAe,KAAK,0BAA0B;AAAA,EAC7E;AAAA,EAEA,yBAAyB,MAAoB;AAC3C,QAAI,SAAS,QAAS,MAAK,YAAY;AAAA,EACzC;AAAA,EAEA,OAAa;AACX,SAAK,aAAa,QAAQ,EAAE;AAC5B,SAAK,cAAc,IAAI,YAAY,gBAAgB,CAAC;AAAA,EACtD;AAAA,EAEA,QAAc;AACZ,SAAK,gBAAgB,MAAM;AAC3B,SAAK,cAAc,IAAI,YAAY,iBAAiB,CAAC;AAAA,EACvD;AAAA,EAEA,SAAe;AACb,SAAK,aAAa,MAAM,IAAI,KAAK,MAAM,IAAI,KAAK,KAAK;AAAA,EACvD;AAAA,EAEA,gBAAsB;AACpB,SAAK,YAAY,cAAmC,UAAU,GAAG,MAAM;AAAA,EACzE;AAAA,EAEA,eAAqB;AACnB,SAAK,WAAW;AAChB,SAAK,WAAW,gBAAgB;AAChC,SAAK,cAAc,IAAI,YAAY,yBAAyB,CAAC;AAAA,EAC/D;AAAA,EAEA,cAAc,SAA2E;AACvF,SAAK,WAAW,EAAE,GAAG,QAAQ;AAC7B,SAAK,cAAc,IAAI,YAAY,6BAA6B,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;AAAA,EAC1F;AAAA,EAEA,MAAM,YAAY,MAA6B;AAC7C,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,QAAS;AACd,QAAI,CAAC,KAAK,SAAU,MAAK,WAAW,MAAM,KAAK,eAAe;AAC9D,SAAK,eAAe,QAAQ,OAAO;AACnC,SAAK,cAAc,IAAI,YAAY,2BAA2B,CAAC;AAC/D,UAAM,KAAK,UAAU,SAAS,IAAI;AAAA,EACpC;AAAA,EAEA,MAAM,UAAU,SAAiB,UAAkC;AACjE,QAAI,CAAC,KAAK,SAAU,MAAK,WAAW,MAAM,KAAK,eAAe;AAC9D,UAAM,WAAW,MAAM,MAAM,KAAK,SAAS,UAAU,OAAO;AAAA,MAC1D,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,KAAK,SAAS,KAAK;AAAA,QAC5C,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MACV;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,QAAQ,CAAC;AAAA,IAClC,CAAC;AACD,QAAI,SAAS,WAAW,OAAO,UAAU;AACvC,WAAK,WAAW;AAChB,WAAK,cAAc,IAAI,YAAY,2BAA2B,CAAC;AAC/D,YAAM,KAAK,UAAU,SAAS,KAAK;AACnC;AAAA,IACF;AACA,QAAI,CAAC,SAAS,IAAI;AAChB,WAAK,eAAe,EAAE,MAAM,eAAe,QAAQ,SAAS,QAAQ,WAAW,MAAM,CAAC;AACtF,YAAM,IAAI,MAAM,0BAA0B,SAAS,MAAM,GAAG;AAAA,IAC9D;AACA,QAAI;AACJ,QAAI;AACF,YAAM,uBAAuB,UAAU,CAAC,UAAU;AAChD,YAAI,MAAM,UAAU,WAAW;AAC7B,gBAAM,OAAO,iBAAiB,KAAK,eAAe,aAAa,EAAE;AACjE,0BAAgB;AAChB,cAAI,KAAM,MAAK,eAAe,OAAO,MAAM,KAAK,SAAS,EAAE;AAAA,QAC7D;AACA,YAAI,MAAM,UAAU,iBAAiB;AACnC,eAAK;AAAA,YACH,OAAO,MAAM,KAAK,MAAM,EAAE;AAAA,YAC1B,OAAO,MAAM,KAAK,QAAQ,QAAQ;AAAA,UACpC;AAAA,QACF;AACA,YAAI,MAAM,UAAU,SAAS;AAC3B,eAAK,eAAe;AAAA,YAClB,MAAM,OAAO,MAAM,KAAK,QAAQ,eAAe;AAAA,YAC/C,WAAW,MAAM,KAAK,cAAc;AAAA,UACtC,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH,SAAS,OAAO;AACd,UAAI,iBAAiB,yBAAyB;AAC5C,aAAK,eAAe,EAAE,MAAM,MAAM,MAAM,WAAW,MAAM,CAAC;AAAA,MAC5D;AACA,YAAM;AAAA,IACR;AACA,SAAK,cAAc,IAAI,YAAY,6BAA6B,CAAC;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,MAAoB;AAC/B,SAAK,KAAK,YAAY,IAAI,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAC5C;AAAA,EAEA,MAAM,YAAY,IAA2B;AAC3C,QAAI,CAAC,KAAK,UAAU;AAClB,WAAK,eAAe,EAAE,MAAM,wBAAwB,WAAW,MAAM,CAAC;AACtE,YAAM,IAAI,MAAM,iCAAiC;AAAA,IACnD;AACA,UAAM,WAAW,MAAM,MAAM,KAAK,SAAS,UAAU,mBAAmB;AAAA,MACtE,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,KAAK,SAAS,KAAK;AAAA,QAC5C,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MACV;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,GAAG,CAAC;AAAA,IAC7B,CAAC;AACD,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,UAAU,SAAS,WAAW,OAAO,SAAS,WAAW;AAC/D,UAAI,SAAS,WAAW,KAAK;AAC3B,aAAK,WAAW;AAChB,aAAK,cAAc,IAAI,YAAY,2BAA2B,CAAC;AAAA,MACjE;AACA,WAAK,eAAe;AAAA,QAClB,MAAM,UAAU,yBAAyB;AAAA,QACzC,QAAQ,SAAS;AAAA,QACjB,WAAW;AAAA,MACb,CAAC;AACD,YAAM,IAAI,MAAM,kCAAkC,SAAS,MAAM,GAAG;AAAA,IACtE;AACA,QAAI;AACJ,QAAI;AACJ,UAAM,uBAAuB,UAAU,CAAC,UAAU;AAChD,UAAI,MAAM,UAAU,iBAAkB,aAAY,MAAM;AACxD,UAAI,MAAM,UAAU,WAAW;AAC7B,cAAM,OAAO,iBAAiB,KAAK,eAAe,aAAa,EAAE;AACjE,wBAAgB;AAChB,YAAI,KAAM,MAAK,eAAe,OAAO,MAAM,KAAK,SAAS,EAAE;AAAA,MAC7D;AAAA,IACF,CAAC;AAGD,QAAI,aAAa,CAAC,eAAe;AAC/B,WAAK,eAAe,aAAa,KAAK,UAAU,UAAU,UAAU,CAAC,CAAC,CAAC;AAAA,IACzE;AACA,SAAK,cAAc,IAAI,YAAY,4BAA4B,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;AAAA,EACpF;AAAA,EAEA,qBAAqB,MAAY,KAAK,YAAY;AAAA,EAElD,yBAAyB,CAAC,UAA+B;AACvD,QACE,MAAM,QAAQ,YACd,KAAK,aAAa,MAAM,KACxB,KAAK,YAAY,SAAS,eAC1B;AACA,WAAK,MAAM;AAAA,IACb;AAAA,EACF;AAAA,EAEA,6BAA6B,CAAC,UAA8B;AAC1D,QACE,KAAK,aAAa,MAAM,KACxB,KAAK,YAAY,SAAS,uBAC1B,CAAC,MAAM,aAAa,EAAE,SAAS,IAAI,GACnC;AACA,WAAK,MAAM;AAAA,IACb;AAAA,EACF;AAAA,EAEA,MAAM,iBAA2C;AAC/C,QAAI,CAAC,KAAK,gBAAiB,OAAM,IAAI,MAAM,6BAA6B;AACxE,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,MAAM,KAAK,iBAAiB;AAAA,QAC3C,QAAQ;AAAA,QACR,SAAS,EAAE,QAAQ,oBAAoB,gBAAgB,mBAAmB;AAAA,QAC1E,MAAM,KAAK,UAAU,KAAK,WAAW,EAAE,SAAS,KAAK,SAAS,IAAI,CAAC,CAAC;AAAA,QACpE,aAAa;AAAA,MACf,CAAC;AAAA,IACH,SAAS,OAAO;AACd,WAAK,eAAe,EAAE,MAAM,kBAAkB,WAAW,KAAK,CAAC;AAC/D,YAAM;AAAA,IACR;AACA,QAAI,CAAC,SAAS,IAAI;AAChB,WAAK,eAAe,EAAE,MAAM,kBAAkB,QAAQ,SAAS,QAAQ,WAAW,KAAK,CAAC;AACxF,YAAM,IAAI,MAAM,6BAA6B,SAAS,MAAM,GAAG;AAAA,IACjE;AACA,QAAI;AACJ,QAAI;AACF,gBAAW,MAAM,SAAS,KAAK;AAAA,IACjC,SAAS,OAAO;AACd,WAAK,eAAe,EAAE,MAAM,kBAAkB,WAAW,KAAK,CAAC;AAC/D,YAAM;AAAA,IACR;AACA,QAAI,QAAQ,eAAe;AACzB,WAAK,cAAc,kBAAkB,QAAQ,aAAa;AAC1D,WAAK,QAAQ;AAAA,IACf;AACA,SAAK;AAAA,MACH,IAAI,YAAY,6BAA6B,EAAE,QAAQ,EAAE,WAAW,QAAQ,UAAU,EAAE,CAAC;AAAA,IAC3F;AACA,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,MAA4B,MAAuC;AAChF,QAAI,CAAC,KAAK,UAAW,QAAO;AAC5B,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,YAAY,WAAW,IAAI;AACnC,QACE,SAAS,eACT,KAAK,YAAY,SAAS,eAC1B,KAAK,YAAY,MAAM,OAAO,KAAK,cAAc,CAAC,GAClD;AACA,YAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,aAAO,YAAY;AACnB,aAAO,MAAM,KAAK,YAAY,MAAM,OAAO,KAAK,cAAc,CAAC,KAAK;AACpE,aAAO,MAAM;AACb,cAAQ,OAAO,MAAM;AAAA,IACvB;AACA,UAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,SAAK,cAAc;AACnB,YAAQ,OAAO,IAAI;AACnB,QAAI,KAAK,YAAY,SAAS,gBAAgB;AAC5C,YAAM,YAAY,SAAS,cAAc,MAAM;AAC/C,gBAAU,YAAW,oBAAI,KAAK,GAAE,YAAY;AAC5C,gBAAU,cAAc,IAAI,KAAK,eAAe,KAAK,YAAY,QAAQ;AAAA,QACvE,MAAM;AAAA,QACN,QAAQ;AAAA,MACV,CAAC,EAAE,OAAO,oBAAI,KAAK,CAAC;AACpB,cAAQ,OAAO,SAAS;AAAA,IAC1B;AACA,SAAK,UAAU,OAAO,OAAO;AAC7B,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,QAAoC;AACjD,SAAK,cAAc,IAAI,YAAY,mBAAmB,EAAE,OAAO,CAAC,CAAC;AAAA,EACnE;AAAA,EAEA,oBAAoB,IAAY,MAAoB;AAClD,QAAI,CAAC,KAAK,aAAa,CAAC,GAAI;AAC5B,UAAM,OAAO,SAAS,cAAc,SAAS;AAC7C,SAAK,YAAY;AACjB,UAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,UAAM,cAAc;AACpB,UAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,YAAQ,OAAO;AACf,YAAQ,cAAc,KAAK,YAAY,OAAO;AAC9C,YAAQ,iBAAiB,SAAS,MAAM;AACtC,cAAQ,WAAW;AACnB,WAAK,KAAK,YAAY,EAAE,EAAE,MAAM,MAAM;AACpC,gBAAQ,WAAW;AACnB,aAAK;AAAA,UACH,IAAI,YAAY,mBAAmB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,EAAE,CAAC;AAAA,QAChF;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AACD,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,OAAO;AACd,WAAO,cAAc,KAAK,YAAY,OAAO;AAC7C,WAAO,iBAAiB,SAAS,MAAM,KAAK,OAAO,CAAC;AACpD,SAAK,OAAO,OAAO,SAAS,MAAM;AAClC,SAAK,UAAU,OAAO,IAAI;AAC1B,SAAK,cAAc,IAAI,YAAY,2BAA2B,EAAE,QAAQ,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC;AAAA,EACzF;AAAA,EAEA,gBAAqD;AACnD,UAAM,aACH,KAAK,aAAa,OAAO,KAC1B,KAAK,YAAY,MAAM;AACzB,WAAO,eAAe,SAAU,KAAK,QAAQ,UAAU,SAAS,UAAW;AAAA,EAC7E;AAAA,EAEA,cAAoB;AAClB,UAAM,OAAO,KAAK,cAAc;AAChC,SAAK,aAAa,cAAc,IAAI;AACpC,UAAM,SAAS,KAAK,YAAY,MAAM,IAAI;AAC1C,eAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,WAAK,MAAM;AAAA,QACT,0BAA0B,aAAa,IAAI,CAAC;AAAA,QAC5C,WAAW,MAAM,KAAK;AAAA,MACxB;AAAA,IACF;AACA,SAAK,MAAM;AAAA,MACT;AAAA,MACA,GAAG,KAAK,YAAY,OAAO,UAAU;AAAA,IACvC;AACA,SAAK,MAAM;AAAA,MACT;AAAA,MACA,GAAG,KAAK,YAAY,OAAO,cAAc;AAAA,IAC3C;AACA,SAAK,MAAM;AAAA,MACT;AAAA,MACA,GAAG,KAAK,YAAY,OAAO,cAAc;AAAA,IAC3C;AACA,SAAK,MAAM;AAAA,MACT;AAAA,MACA,OAAO,KAAK,YAAY,OAAO,MAAM;AAAA,IACvC;AACA,UAAM,OAAO,KAAK,YAAY,cAAgC,aAAa;AAC3E,UAAM,UAAU,KAAK,YAAY,MAAM,KAAK,IAAI;AAChD,QAAI,MAAM;AACR,WAAK,SAAS,CAAC;AACf,UAAI,QAAS,MAAK,MAAM;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,QAAI,CAAC,KAAK,WAAY;AACtB,UAAM,aAAa,KAAK;AACxB,SAAK,aAAa,QAAQ,eAAe;AACzC,SAAK,aAAa,cAAc,WAAW,MAAM,IAAI;AACrD,SAAK,aAAa,QAAQ,WAAW,MAAM;AAC3C,SAAK,aAAa,OAAO,WAAW,SAAS;AAC7C,SAAK,QAAQ,OAAO,WAAW,OAAO;AACtC,SAAK,QAAQ,WAAW,WAAW,OAAO;AAC1C,SAAK,QAAQ,UAAU,WAAW,OAAO;AACzC,SAAK,gBAAgB,qBAAqB,WAAW,OAAO,gBAAgB;AAC5E,SAAK,WAAW,YAAY,GAAG,MAAM;AAAA,2DACkB,gBAAgB,WAAW,OAAO,IAAI,CAAC;AAAA,2CACvD,gBAAgB,WAAW,MAAM,IAAI,CAAC;AAAA,wLACuG,gBAAgB,WAAW,OAAO,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQ5N,kBAA2B,KAAK,YAAY,QAAQ,EAAE,cAAc,WAAW,MAAM;AACrF,UAAM,eAAe,WAAW,MAAM,KAAK,KAAK,cAAc,CAAC;AAC/D,QAAI,cAAc;AAChB,YAAM,eAAe;AAAA,QACnB,KAAK;AAAA,QACL;AAAA,MACF;AACA,YAAM,OAAO,SAAS,cAAc,KAAK;AACzC,WAAK,MAAM;AACX,WAAK,MAAM;AACX,mBAAa,gBAAgB,IAAI;AAAA,IACnC;AACA,UAAM,OAAO,cAAgC,KAAK,YAAY,aAAa;AAC3E,UAAM,UAAU,WAAW,MAAM,KAAK,KAAK,cAAc,CAAC;AAC1D,QAAI,SAAS;AACX,WAAK,MAAM;AACX,WAAK,MAAM,WAAW,MAAM;AAAA,IAC9B,OAAO;AACL,WAAK,SAAS;AAAA,IAChB;AACA,kBAA2B,KAAK,YAAY,IAAI,EAAE,cAChD,WAAW,OAAO;AACpB,kBAA2B,KAAK,YAAY,GAAG,EAAE,cAAc,WAAW,OAAO;AACjF,UAAM,WAAW,cAAmC,KAAK,YAAY,UAAU;AAC/E,aAAS,cAAc,WAAW,OAAO;AACzC,aAAS,aAAa,cAAc,WAAW,OAAO,mBAAmB;AACzE,kBAA2B,KAAK,YAAY,OAAO,EAAE,cAAc,WAAW,OAAO;AACrF,UAAM,UAAU,cAA2B,KAAK,YAAY,oBAAoB;AAChF,eAAW,UAAU,WAAW,kBAAkB;AAChD,YAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,aAAO,OAAO;AACd,aAAO,cAAc;AACrB,aAAO,iBAAiB,SAAS,MAAM,KAAK,aAAa,MAAM,CAAC;AAChE,cAAQ,OAAO,MAAM;AAAA,IACvB;AACA,QAAI,CAAC,WAAW,SAAS;AACvB,oBAA2B,KAAK,YAAY,WAAW,EAAE,SAAS;AACpE,QAAI,CAAC,WAAW,SAAS;AACvB,oBAA2B,KAAK,YAAY,QAAQ,EAAE,SAAS;AACjE,UAAM,QAAQ,cAA2B,KAAK,YAAY,QAAQ;AAClE,eAAW,CAAC,OAAO,IAAI,KAAK;AAAA,MAC1B,CAAC,WAAW,WAAW,UAAU;AAAA,MACjC,CAAC,SAAS,WAAW,QAAQ;AAAA,IAC/B,GAAY;AACV,UAAI,CAAC,KAAM;AACX,YAAM,OAAO,SAAS,cAAc,GAAG;AACvC,WAAK,OAAO;AACZ,WAAK,SAAS;AACd,WAAK,MAAM;AACX,WAAK,cAAc;AACnB,YAAM,OAAO,IAAI;AAAA,IACnB;AACA,SAAK,YAAY,KAAK,WAAW,cAAc,WAAW,KAAK;AAC/D,SAAK,WAAW,cAAc,WAAW,GAAG,iBAAiB,SAAS,MAAM,KAAK,KAAK,CAAC;AACvF,SAAK,WAAW,cAAc,QAAQ,GAAG,iBAAiB,SAAS,MAAM,KAAK,MAAM,CAAC;AACrF,SAAK,WAAW,cAAc,MAAM,GAAG,iBAAiB,UAAU,CAAC,UAAU;AAC3E,YAAM,eAAe;AACrB,YAAM,QAAQ,SAAS;AACvB,eAAS,QAAQ;AACjB,WAAK,aAAa,KAAK;AAAA,IACzB,CAAC;AACD,SAAK,YAAY;AAAA,EACnB;AACF;AAEO,SAAS,0BAAgC;AAC9C,MAAI,WAAW,kBAAkB,CAAC,eAAe,IAAI,kBAAkB,GAAG;AACxE,mBAAe,OAAO,oBAAoB,sBAAsB;AAAA,EAClE;AACF;AAEA,SAAS,aAAa,OAAuB;AAC3C,SAAO,MAAM,QAAQ,UAAU,CAAC,WAAW,IAAI,OAAO,YAAY,CAAC,EAAE;AACvE;AAEA,SAAS,WAAW,MAAc,OAAiE;AACjG,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,SAAS,gBAAgB,SAAS,cAAe,QAAO,OAAO,KAAK;AACxE,SAAO,GAAG,KAAK;AACjB;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,SAAO,MAAM,WAAW,KAAK,OAAO,EAAE,WAAW,KAAK,QAAQ,EAAE,WAAW,KAAK,MAAM;AACxF;AAEA,SAAS,cAAiC,MAAkB,UAAqB;AAC/E,QAAM,UAAU,KAAK,cAAiB,QAAQ;AAC9C,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,iCAAiC,QAAQ,EAAE;AACzE,SAAO;AACT;AAEA,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AHjdf,wBAAwB;","names":[]}
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  ASSISTANT_TAG_NAME,
3
3
  NoodleAssistantElement,
4
4
  registerNoodleAssistant
5
- } from "./chunk-OXFV6KZ2.js";
5
+ } from "./chunk-IM7SAHNE.js";
6
6
 
7
7
  // src/index.ts
8
8
  registerNoodleAssistant();
package/dist/react.cjs CHANGED
@@ -426,10 +426,18 @@ var NoodleAssistantElement = class extends HTMLElementBase {
426
426
  throw new Error(`Assistant confirmation failed (${response.status})`);
427
427
  }
428
428
  let completed;
429
+ let narrationBody;
429
430
  await consumeAssistantEvents(response, (event) => {
430
431
  if (event.event === "tool_completed") completed = event.data;
432
+ if (event.event === "content") {
433
+ const body = narrationBody ?? this.#appendMessage("assistant", "");
434
+ narrationBody = body;
435
+ if (body) body.textContent += String(event.data.delta ?? "");
436
+ }
431
437
  });
432
- if (completed) this.#appendMessage("assistant", JSON.stringify(completed.result ?? {}));
438
+ if (completed && !narrationBody) {
439
+ this.#appendMessage("assistant", JSON.stringify(completed.result ?? {}));
440
+ }
433
441
  this.dispatchEvent(new CustomEvent("assistant-tool-completed", { detail: { id } }));
434
442
  }
435
443
  #handleSystemTheme = () => this.#applyTheme();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react.ts","../src/appearance.ts","../src/transport.ts","../src/element.ts"],"sourcesContent":["import {\n createElement,\n forwardRef,\n type ReactElement,\n useEffect,\n useImperativeHandle,\n useRef,\n} from 'react';\nimport type { AssistantThemeMode } from './appearance.js';\nimport { type NoodleAssistantElement, registerNoodleAssistant } from './element.js';\nimport type { AssistantErrorDetail } from './transport.js';\n\nexport interface NoodleAssistantProps {\n readonly sessionEndpoint: string;\n readonly theme?: AssistantThemeMode;\n readonly open?: boolean;\n readonly className?: string;\n readonly onReady?: () => void;\n readonly onError?: (error: AssistantErrorDetail) => void;\n readonly onSessionExpired?: () => void;\n}\n\nexport const NoodleAssistant = forwardRef<NoodleAssistantElement, NoodleAssistantProps>(\n function NoodleAssistant(props, forwardedRef): ReactElement {\n const ref = useRef<NoodleAssistantElement>(null);\n useImperativeHandle(forwardedRef, () => ref.current as NoodleAssistantElement, []);\n useEffect(() => {\n registerNoodleAssistant();\n const element = ref.current;\n if (!element) return;\n element.sessionEndpoint = props.sessionEndpoint;\n const ready = () => props.onReady?.();\n const error = (event: Event) =>\n props.onError?.((event as CustomEvent<AssistantErrorDetail>).detail);\n const expired = () => props.onSessionExpired?.();\n element.addEventListener('assistant-ready', ready);\n element.addEventListener('assistant-error', error);\n element.addEventListener('assistant-session-expired', expired);\n return () => {\n element.removeEventListener('assistant-ready', ready);\n element.removeEventListener('assistant-error', error);\n element.removeEventListener('assistant-session-expired', expired);\n };\n }, [props.onError, props.onReady, props.onSessionExpired, props.sessionEndpoint]);\n return createElement('noodle-assistant', {\n ref,\n class: props.className,\n 'session-endpoint': props.sessionEndpoint,\n ...(props.theme ? { theme: props.theme } : {}),\n ...(props.open ? { open: '' } : {}),\n });\n },\n);\n","export type AssistantThemeMode = 'auto' | 'light' | 'dark';\nexport type AssistantLayoutMode = 'floating' | 'inline' | 'drawer';\nexport type AssistantPosition = 'bottom-left' | 'bottom-right';\n\nexport interface AssistantThemeTokens {\n readonly page: string;\n readonly panel: string;\n readonly elevated: string;\n readonly input: string;\n readonly hover: string;\n readonly selected: string;\n readonly text: string;\n readonly mutedText: string;\n readonly accent: string;\n readonly accentText: string;\n readonly link: string;\n readonly divider: string;\n readonly focus: string;\n readonly success: string;\n readonly warning: string;\n readonly danger: string;\n readonly overlay: string;\n readonly code: string;\n readonly widgetFrame: string;\n readonly fontFamily: string;\n readonly monoFontFamily: string;\n readonly baseFontSize: number;\n readonly messageFontSize: number;\n readonly lineHeight: number;\n readonly panelRadius: number;\n readonly cardRadius: number;\n readonly inputRadius: number;\n readonly buttonRadius: number;\n readonly launcherRadius: number;\n readonly spacing: number;\n readonly shadow: string;\n readonly backdropBlur: number;\n readonly motionScale: number;\n}\n\nexport interface AssistantConfiguration {\n readonly branding?: {\n readonly name?: string;\n readonly accent?: string;\n readonly surface?: string;\n readonly surfaceDark?: string;\n readonly logo?: AssistantBrandAsset;\n readonly mark?: AssistantBrandAsset;\n readonly avatar?: AssistantBrandAsset;\n readonly theme?: {\n readonly light?: BrandThemeOverrides;\n readonly dark?: BrandThemeOverrides;\n };\n readonly radius?: 'none' | 'sm' | 'md' | 'lg';\n readonly density?: 'compact' | 'comfortable';\n readonly typography?: 'system' | 'serif' | 'mono';\n readonly colorScheme?: AssistantThemeMode;\n };\n readonly assistant?: AssistantUiConfiguration;\n}\n\ninterface AssistantBrandAsset {\n readonly uri: string;\n readonly darkUri?: string;\n readonly alt: string;\n}\n\ninterface BrandThemeOverrides {\n readonly surface?: string;\n readonly surfaceRaised?: string;\n readonly surfaceMuted?: string;\n readonly text?: string;\n readonly textMuted?: string;\n readonly accent?: string;\n readonly accentText?: string;\n readonly link?: string;\n readonly border?: string;\n readonly borderStrong?: string;\n readonly focus?: string;\n readonly success?: string;\n readonly warning?: string;\n readonly danger?: string;\n readonly code?: string;\n}\n\ninterface AssistantUiConfiguration {\n readonly layout?: {\n readonly mode?: AssistantLayoutMode;\n readonly position?: AssistantPosition;\n readonly panelWidth?: number;\n readonly panelMinHeight?: number;\n readonly panelMaxHeight?: number;\n readonly zIndex?: number;\n readonly density?: 'compact' | 'comfortable';\n readonly mobileFullscreen?: boolean;\n };\n readonly behavior?: {\n readonly startOpen?: boolean;\n readonly closeOnEscape?: boolean;\n readonly closeOnOutsideClick?: boolean;\n readonly showLauncher?: boolean;\n readonly showHeader?: boolean;\n readonly showAvatars?: boolean;\n readonly showTimestamps?: boolean;\n };\n readonly labels?: Partial<AssistantLabels>;\n readonly suggestedPrompts?: readonly string[];\n readonly privacyUrl?: string;\n readonly termsUrl?: string;\n readonly locale?: string;\n readonly direction?: 'ltr' | 'rtl' | 'auto';\n}\n\nexport interface AssistantLabels {\n readonly welcomeHeading: string;\n readonly welcomeMessage: string;\n readonly composerPlaceholder: string;\n readonly send: string;\n readonly stop: string;\n readonly close: string;\n readonly open: string;\n readonly confirm: string;\n readonly cancel: string;\n readonly retry: string;\n readonly unavailable: string;\n readonly sessionExpired: string;\n}\n\nexport interface ResolvedAssistantAppearance {\n readonly brand: {\n readonly name: string;\n readonly logo: { readonly light?: string; readonly dark?: string };\n readonly avatar: { readonly light?: string; readonly dark?: string };\n readonly mark: { readonly light?: string; readonly dark?: string };\n };\n readonly theme: {\n readonly defaultMode: AssistantThemeMode;\n readonly light: AssistantThemeTokens;\n readonly dark: AssistantThemeTokens;\n };\n readonly layout: {\n readonly mode: AssistantLayoutMode;\n readonly position: AssistantPosition;\n readonly panelWidth: number;\n readonly panelMinHeight: number;\n readonly panelMaxHeight: number;\n readonly zIndex: number;\n readonly density: 'compact' | 'comfortable';\n readonly mobileFullscreen: boolean;\n };\n readonly behavior: {\n readonly startOpen: boolean;\n readonly closeOnEscape: boolean;\n readonly closeOnOutsideClick: boolean;\n readonly showLauncher: boolean;\n readonly showHeader: boolean;\n readonly showAvatars: boolean;\n readonly showTimestamps: boolean;\n };\n readonly labels: AssistantLabels;\n readonly suggestedPrompts: readonly string[];\n readonly privacyUrl?: string;\n readonly termsUrl?: string;\n readonly locale: string;\n readonly direction: 'ltr' | 'rtl' | 'auto';\n}\n\nconst common = {\n fontFamily: 'inherit',\n monoFontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n baseFontSize: 15,\n messageFontSize: 15,\n lineHeight: 1.5,\n panelRadius: 20,\n cardRadius: 14,\n inputRadius: 14,\n buttonRadius: 12,\n launcherRadius: 999,\n spacing: 12,\n backdropBlur: 18,\n motionScale: 1,\n} as const;\n\nexport const DEFAULT_APPEARANCE: ResolvedAssistantAppearance = {\n brand: { name: 'Assistant', logo: {}, avatar: {}, mark: {} },\n theme: {\n defaultMode: 'auto',\n light: {\n ...common,\n page: '#F7F7F8',\n panel: '#FFFFFF',\n elevated: '#FFFFFF',\n input: '#F1F1F3',\n hover: '#ECECEF',\n selected: '#E4E2FF',\n text: '#18181B',\n mutedText: '#71717A',\n accent: '#5B4CF0',\n accentText: '#FFFFFF',\n link: '#4A3BD5',\n divider: '#E4E4E7',\n focus: '#5B4CF0',\n success: '#16835D',\n warning: '#A45B00',\n danger: '#C92A45',\n overlay: '#18181B66',\n code: '#F1F1F3',\n widgetFrame: '#E4E4E7',\n shadow: '0 24px 80px rgba(24, 24, 27, 0.18)',\n },\n dark: {\n ...common,\n page: '#111113',\n panel: '#19191D',\n elevated: '#222228',\n input: '#26262C',\n hover: '#303038',\n selected: '#37315F',\n text: '#FAFAFA',\n mutedText: '#A1A1AA',\n accent: '#A99FFF',\n accentText: '#17131F',\n link: '#B9B1FF',\n divider: '#34343B',\n focus: '#B9B1FF',\n success: '#58C69A',\n warning: '#F2B45F',\n danger: '#FF8094',\n overlay: '#00000099',\n code: '#26262C',\n widgetFrame: '#34343B',\n shadow: '0 24px 90px rgba(0, 0, 0, 0.55)',\n },\n },\n layout: {\n mode: 'floating',\n position: 'bottom-right',\n panelWidth: 400,\n panelMinHeight: 420,\n panelMaxHeight: 720,\n zIndex: 2147483000,\n density: 'comfortable',\n mobileFullscreen: true,\n },\n behavior: {\n startOpen: false,\n closeOnEscape: true,\n closeOnOutsideClick: false,\n showLauncher: true,\n showHeader: true,\n showAvatars: true,\n showTimestamps: false,\n },\n labels: {\n welcomeHeading: 'How can I help?',\n welcomeMessage: '',\n composerPlaceholder: 'Ask a question…',\n send: 'Send',\n stop: 'Stop',\n close: 'Close assistant',\n open: 'Open assistant',\n confirm: 'Confirm',\n cancel: 'Cancel',\n retry: 'Try again',\n unavailable: 'The assistant is temporarily unavailable.',\n sessionExpired: 'Your assistant session expired. Reopen it to continue.',\n },\n suggestedPrompts: [],\n locale: 'en',\n direction: 'auto',\n};\n\nexport function resolveAppearance(input: AssistantConfiguration = {}): ResolvedAssistantAppearance {\n const branding = input.branding;\n const assistant = input.assistant;\n return {\n brand: {\n ...DEFAULT_APPEARANCE.brand,\n ...(branding?.name ? { name: branding.name } : {}),\n logo: themedAsset(branding?.logo),\n avatar: themedAsset(branding?.avatar),\n mark: themedAsset(branding?.mark),\n },\n theme: {\n defaultMode: branding?.colorScheme ?? DEFAULT_APPEARANCE.theme.defaultMode,\n light: resolveTheme('light', branding),\n dark: resolveTheme('dark', branding),\n },\n layout: {\n ...DEFAULT_APPEARANCE.layout,\n ...(branding?.density ? { density: branding.density } : {}),\n ...assistant?.layout,\n },\n behavior: { ...DEFAULT_APPEARANCE.behavior, ...assistant?.behavior },\n labels: { ...DEFAULT_APPEARANCE.labels, ...assistant?.labels },\n suggestedPrompts: assistant?.suggestedPrompts ?? DEFAULT_APPEARANCE.suggestedPrompts,\n ...(assistant?.privacyUrl ? { privacyUrl: assistant.privacyUrl } : {}),\n ...(assistant?.termsUrl ? { termsUrl: assistant.termsUrl } : {}),\n locale: assistant?.locale ?? DEFAULT_APPEARANCE.locale,\n direction: assistant?.direction ?? DEFAULT_APPEARANCE.direction,\n };\n}\n\nfunction themedAsset(asset: AssistantBrandAsset | undefined): {\n readonly light?: string;\n readonly dark?: string;\n} {\n return asset ? { light: asset.uri, dark: asset.darkUri ?? asset.uri } : {};\n}\n\nfunction resolveTheme(\n mode: 'light' | 'dark',\n branding: AssistantConfiguration['branding'],\n): AssistantThemeTokens {\n const defaults = DEFAULT_APPEARANCE.theme[mode];\n const surface = mode === 'light' ? branding?.surface : branding?.surfaceDark;\n const portable = branding?.theme?.[mode];\n const radius = branding?.radius ? radiusValue(branding.radius) : undefined;\n return {\n ...defaults,\n ...(branding?.accent ? { accent: branding.accent } : {}),\n ...(surface ? { page: surface, panel: surface } : {}),\n ...mapPortableTheme(portable),\n ...(radius === undefined\n ? {}\n : {\n panelRadius: radius,\n cardRadius: radius,\n inputRadius: Math.max(0, radius - 2),\n buttonRadius: Math.max(0, radius - 2),\n }),\n ...(branding?.typography === 'serif'\n ? { fontFamily: 'ui-serif, Georgia, serif' }\n : branding?.typography === 'mono'\n ? { fontFamily: defaults.monoFontFamily }\n : {}),\n };\n}\n\nfunction mapPortableTheme(input: BrandThemeOverrides | undefined): Partial<AssistantThemeTokens> {\n if (!input) return {};\n return {\n ...(input.surface ? { page: input.surface, panel: input.surface } : {}),\n ...(input.surfaceRaised ? { elevated: input.surfaceRaised } : {}),\n ...(input.surfaceMuted\n ? { input: input.surfaceMuted, hover: input.surfaceMuted, selected: input.surfaceMuted }\n : {}),\n ...(input.text ? { text: input.text } : {}),\n ...(input.textMuted ? { mutedText: input.textMuted } : {}),\n ...(input.accent ? { accent: input.accent } : {}),\n ...(input.accentText ? { accentText: input.accentText } : {}),\n ...(input.link ? { link: input.link } : {}),\n ...(input.border ? { divider: input.border, widgetFrame: input.border } : {}),\n ...(input.focus ? { focus: input.focus } : {}),\n ...(input.success ? { success: input.success } : {}),\n ...(input.warning ? { warning: input.warning } : {}),\n ...(input.danger ? { danger: input.danger } : {}),\n ...(input.code ? { code: input.code } : {}),\n };\n}\n\nfunction radiusValue(radius: 'none' | 'sm' | 'md' | 'lg'): number {\n if (radius === 'none') return 0;\n if (radius === 'sm') return 8;\n if (radius === 'lg') return 18;\n return 14;\n}\n","export interface AssistantEvent {\n readonly event: string;\n readonly data: Readonly<Record<string, unknown>>;\n}\n\nexport interface AssistantErrorDetail {\n readonly code: string;\n readonly status?: number;\n readonly retryable: boolean;\n}\n\n/**\n * A 2xx response whose body carried no assistant events at all — typically an auth redirect or\n * proxy page returning HTML with a 200. Silently rendering nothing strands the end user, so the\n * transport fails loudly instead (ADR 0151 hardening).\n */\nexport class AssistantTransportError extends Error {\n readonly code = 'invalid_response' as const;\n\n constructor(contentType: string) {\n super(`assistant response was not an event stream (content-type: ${contentType || 'unknown'})`);\n this.name = 'AssistantTransportError';\n }\n}\n\n/** Consume JSON-bearing server-sent events without buffering the whole assistant turn. */\nexport async function consumeAssistantEvents(\n response: Response,\n onEvent: (event: AssistantEvent) => void,\n): Promise<void> {\n let delivered = 0;\n let sawText = false;\n const deliver = (event: AssistantEvent): void => {\n delivered += 1;\n onEvent(event);\n };\n if (!response.body) {\n const text = await response.text();\n sawText = text.trim().length > 0;\n emitFrames(text, deliver, true);\n } else {\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let pending = '';\n while (true) {\n const { done, value } = await reader.read();\n const chunk = decoder.decode(value, { stream: !done });\n if (!sawText && chunk.trim().length > 0) sawText = true;\n pending += chunk;\n pending = emitFrames(pending, deliver, done);\n if (done) break;\n }\n }\n if (delivered === 0 && sawText) {\n throw new AssistantTransportError(response.headers.get('content-type') ?? '');\n }\n}\n\nfunction emitFrames(\n input: string,\n onEvent: (event: AssistantEvent) => void,\n flush: boolean,\n): string {\n const normalized = input.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n');\n const frames = normalized.split('\\n\\n');\n const pending = flush ? '' : (frames.pop() ?? '');\n for (const frame of frames) {\n const event = parseFrame(frame);\n if (event) onEvent(event);\n }\n if (flush && frames.length === 0 && normalized.trim()) {\n const event = parseFrame(normalized);\n if (event) onEvent(event);\n }\n return pending;\n}\n\nfunction parseFrame(frame: string): AssistantEvent | undefined {\n let event = 'message';\n const data: string[] = [];\n for (const line of frame.split('\\n')) {\n if (line.startsWith(':')) continue;\n const separator = line.indexOf(':');\n const field = separator < 0 ? line : line.slice(0, separator);\n const value = separator < 0 ? '' : line.slice(separator + 1).replace(/^ /, '');\n if (field === 'event') event = value;\n if (field === 'data') data.push(value);\n }\n if (data.length === 0) return undefined;\n try {\n return { event, data: JSON.parse(data.join('\\n')) as Readonly<Record<string, unknown>> };\n } catch {\n return undefined;\n }\n}\n","import {\n type AssistantConfiguration,\n type AssistantThemeMode,\n type AssistantThemeTokens,\n resolveAppearance,\n} from './appearance.js';\nimport {\n type AssistantErrorDetail,\n AssistantTransportError,\n consumeAssistantEvents,\n} from './transport.js';\n\nexport const ASSISTANT_TAG_NAME = 'noodle-assistant';\nconst HTMLElementBase: typeof HTMLElement =\n globalThis.HTMLElement ?? (class {} as unknown as typeof HTMLElement);\n\ninterface SessionResponse {\n readonly token: string;\n readonly expiresAt: string;\n readonly endpoints: {\n readonly turns: string;\n readonly toolConfirmations: string;\n };\n readonly configuration?: AssistantConfiguration;\n}\n\nexport class NoodleAssistantElement extends HTMLElementBase {\n static readonly observedAttributes = ['open', 'theme'];\n #appearance = resolveAppearance();\n #session: SessionResponse | undefined;\n #messages: HTMLElement | undefined;\n #media: MediaQueryList | undefined;\n #context: Readonly<Record<string, string | number | boolean | null>> | undefined;\n sessionEndpoint = '';\n\n connectedCallback(): void {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n if (!this.sessionEndpoint) this.sessionEndpoint = this.getAttribute('session-endpoint') ?? '';\n this.#media = globalThis.matchMedia?.('(prefers-color-scheme: dark)');\n this.#media?.addEventListener('change', this.#handleSystemTheme);\n document.addEventListener('keydown', this.#handleDocumentKeydown);\n document.addEventListener('pointerdown', this.#handleDocumentPointerDown);\n if (this.#appearance.behavior.startOpen) this.setAttribute('open', '');\n this.#render();\n this.dispatchEvent(new CustomEvent('assistant-ready'));\n }\n\n disconnectedCallback(): void {\n this.#media?.removeEventListener('change', this.#handleSystemTheme);\n document.removeEventListener('keydown', this.#handleDocumentKeydown);\n document.removeEventListener('pointerdown', this.#handleDocumentPointerDown);\n }\n\n attributeChangedCallback(name: string): void {\n if (name === 'theme') this.#applyTheme();\n }\n\n open(): void {\n this.setAttribute('open', '');\n this.dispatchEvent(new CustomEvent('assistant-open'));\n }\n\n close(): void {\n this.removeAttribute('open');\n this.dispatchEvent(new CustomEvent('assistant-close'));\n }\n\n toggle(): void {\n this.hasAttribute('open') ? this.close() : this.open();\n }\n\n focusComposer(): void {\n this.shadowRoot?.querySelector<HTMLTextAreaElement>('textarea')?.focus();\n }\n\n resetSession(): void {\n this.#session = undefined;\n this.#messages?.replaceChildren();\n this.dispatchEvent(new CustomEvent('assistant-session-reset'));\n }\n\n updateContext(context: Readonly<Record<string, string | number | boolean | null>>): void {\n this.#context = { ...context };\n this.dispatchEvent(new CustomEvent('assistant-context-changed', { detail: { context } }));\n }\n\n async sendMessage(text: string): Promise<void> {\n const message = text.trim();\n if (!message) return;\n if (!this.#session) this.#session = await this.#createSession();\n this.#appendMessage('user', message);\n this.dispatchEvent(new CustomEvent('assistant-message-started'));\n await this.#sendTurn(message, true);\n }\n\n async #sendTurn(message: string, mayRetry: boolean): Promise<void> {\n if (!this.#session) this.#session = await this.#createSession();\n const response = await fetch(this.#session.endpoints.turns, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.#session.token}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({ message }),\n });\n if (response.status === 401 && mayRetry) {\n this.#session = undefined;\n this.dispatchEvent(new CustomEvent('assistant-session-expired'));\n await this.#sendTurn(message, false);\n return;\n }\n if (!response.ok) {\n this.#dispatchError({ code: 'turn_failed', status: response.status, retryable: false });\n throw new Error(`Assistant turn failed (${response.status})`);\n }\n let assistantBody: HTMLElement | undefined;\n try {\n await consumeAssistantEvents(response, (event) => {\n if (event.event === 'content') {\n const body = assistantBody ?? this.#appendMessage('assistant', '');\n assistantBody = body;\n if (body) body.textContent += String(event.data.delta ?? '');\n }\n if (event.event === 'tool_proposed') {\n this.#appendToolProposal(\n String(event.data.id ?? ''),\n String(event.data.tool ?? 'Action'),\n );\n }\n if (event.event === 'error') {\n this.#dispatchError({\n code: String(event.data.code ?? 'stream_failed'),\n retryable: event.data.retryable === true,\n });\n }\n });\n } catch (error) {\n if (error instanceof AssistantTransportError) {\n this.#dispatchError({ code: error.code, retryable: false });\n }\n throw error;\n }\n this.dispatchEvent(new CustomEvent('assistant-message-completed'));\n }\n\n /**\n * Every listener the element attaches to its own DOM must go through this guard: internal UI\n * failures surface as `assistant-error` events (already dispatched by the failing path) and must\n * never escape as unhandled rejections into the embedding page. Programmatic callers use\n * `sendMessage`/`confirmTool` directly and keep the rejection.\n */\n #sendGuarded(text: string): void {\n void this.sendMessage(text).catch(() => {});\n }\n\n async confirmTool(id: string): Promise<void> {\n if (!this.#session) {\n this.#dispatchError({ code: 'confirmation_expired', retryable: false });\n throw new Error('assistant session is not active');\n }\n const response = await fetch(this.#session.endpoints.toolConfirmations, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.#session.token}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({ id }),\n });\n if (!response.ok) {\n const expired = response.status === 401 || response.status === 409;\n if (response.status === 401) {\n this.#session = undefined;\n this.dispatchEvent(new CustomEvent('assistant-session-expired'));\n }\n this.#dispatchError({\n code: expired ? 'confirmation_expired' : 'confirmation_failed',\n status: response.status,\n retryable: false,\n });\n throw new Error(`Assistant confirmation failed (${response.status})`);\n }\n let completed: Readonly<Record<string, unknown>> | undefined;\n await consumeAssistantEvents(response, (event) => {\n if (event.event === 'tool_completed') completed = event.data;\n });\n if (completed) this.#appendMessage('assistant', JSON.stringify(completed.result ?? {}));\n this.dispatchEvent(new CustomEvent('assistant-tool-completed', { detail: { id } }));\n }\n\n #handleSystemTheme = (): void => this.#applyTheme();\n\n #handleDocumentKeydown = (event: KeyboardEvent): void => {\n if (\n event.key === 'Escape' &&\n this.hasAttribute('open') &&\n this.#appearance.behavior.closeOnEscape\n ) {\n this.close();\n }\n };\n\n #handleDocumentPointerDown = (event: PointerEvent): void => {\n if (\n this.hasAttribute('open') &&\n this.#appearance.behavior.closeOnOutsideClick &&\n !event.composedPath().includes(this)\n ) {\n this.close();\n }\n };\n\n async #createSession(): Promise<SessionResponse> {\n if (!this.sessionEndpoint) throw new Error('sessionEndpoint is required');\n let response: Response;\n try {\n response = await fetch(this.sessionEndpoint, {\n method: 'POST',\n headers: { Accept: 'application/json', 'Content-Type': 'application/json' },\n body: JSON.stringify(this.#context ? { context: this.#context } : {}),\n credentials: 'same-origin',\n });\n } catch (error) {\n this.#dispatchError({ code: 'session_failed', retryable: true });\n throw error;\n }\n if (!response.ok) {\n this.#dispatchError({ code: 'session_failed', status: response.status, retryable: true });\n throw new Error(`Assistant session failed (${response.status})`);\n }\n let session: SessionResponse;\n try {\n session = (await response.json()) as SessionResponse;\n } catch (error) {\n this.#dispatchError({ code: 'session_failed', retryable: true });\n throw error;\n }\n if (session.configuration) {\n this.#appearance = resolveAppearance(session.configuration);\n this.#render();\n }\n this.dispatchEvent(\n new CustomEvent('assistant-session-started', { detail: { expiresAt: session.expiresAt } }),\n );\n return session;\n }\n\n #appendMessage(role: 'user' | 'assistant', text: string): HTMLElement | undefined {\n if (!this.#messages) return undefined;\n const message = document.createElement('div');\n message.className = `message ${role}`;\n if (\n role === 'assistant' &&\n this.#appearance.behavior.showAvatars &&\n this.#appearance.brand.avatar[this.#resolvedMode()]\n ) {\n const avatar = document.createElement('img');\n avatar.className = 'avatar';\n avatar.src = this.#appearance.brand.avatar[this.#resolvedMode()] ?? '';\n avatar.alt = '';\n message.append(avatar);\n }\n const body = document.createElement('span');\n body.textContent = text;\n message.append(body);\n if (this.#appearance.behavior.showTimestamps) {\n const timestamp = document.createElement('time');\n timestamp.dateTime = new Date().toISOString();\n timestamp.textContent = new Intl.DateTimeFormat(this.#appearance.locale, {\n hour: 'numeric',\n minute: '2-digit',\n }).format(new Date());\n message.append(timestamp);\n }\n this.#messages.append(message);\n return body;\n }\n\n #dispatchError(detail: AssistantErrorDetail): void {\n this.dispatchEvent(new CustomEvent('assistant-error', { detail }));\n }\n\n #appendToolProposal(id: string, tool: string): void {\n if (!this.#messages || !id) return;\n const card = document.createElement('section');\n card.className = 'tool-proposal';\n const label = document.createElement('strong');\n label.textContent = tool;\n const confirm = document.createElement('button');\n confirm.type = 'button';\n confirm.textContent = this.#appearance.labels.confirm;\n confirm.addEventListener('click', () => {\n confirm.disabled = true;\n void this.confirmTool(id).catch(() => {\n confirm.disabled = false;\n this.dispatchEvent(\n new CustomEvent('assistant-error', { detail: { code: 'confirmation_failed' } }),\n );\n });\n });\n const cancel = document.createElement('button');\n cancel.type = 'button';\n cancel.textContent = this.#appearance.labels.cancel;\n cancel.addEventListener('click', () => card.remove());\n card.append(label, confirm, cancel);\n this.#messages.append(card);\n this.dispatchEvent(new CustomEvent('assistant-tool-proposed', { detail: { id, tool } }));\n }\n\n #resolvedMode(): Exclude<AssistantThemeMode, 'auto'> {\n const configured =\n (this.getAttribute('theme') as AssistantThemeMode | null) ??\n this.#appearance.theme.defaultMode;\n return configured === 'auto' ? (this.#media?.matches ? 'dark' : 'light') : configured;\n }\n\n #applyTheme(): void {\n const mode = this.#resolvedMode();\n this.setAttribute('data-theme', mode);\n const tokens = this.#appearance.theme[mode];\n for (const [name, value] of Object.entries(tokens)) {\n this.style.setProperty(\n `--ns-assistant-default-${camelToKebab(name)}`,\n tokenValue(name, value),\n );\n }\n this.style.setProperty(\n '--ns-assistant-default-panel-width',\n `${this.#appearance.layout.panelWidth}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-min-height',\n `${this.#appearance.layout.panelMinHeight}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-max-height',\n `${this.#appearance.layout.panelMaxHeight}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-z-index',\n String(this.#appearance.layout.zIndex),\n );\n const logo = this.shadowRoot?.querySelector<HTMLImageElement>('.brand-logo');\n const logoUrl = this.#appearance.brand.logo[mode];\n if (logo) {\n logo.hidden = !logoUrl;\n if (logoUrl) logo.src = logoUrl;\n }\n }\n\n #render(): void {\n if (!this.shadowRoot) return;\n const appearance = this.#appearance;\n this.setAttribute('role', 'complementary');\n this.setAttribute('aria-label', appearance.brand.name);\n this.setAttribute('lang', appearance.locale);\n this.setAttribute('dir', appearance.direction);\n this.dataset.mode = appearance.layout.mode;\n this.dataset.position = appearance.layout.position;\n this.dataset.density = appearance.layout.density;\n this.toggleAttribute('mobile-fullscreen', appearance.layout.mobileFullscreen);\n this.shadowRoot.innerHTML = `${styles}\n <button class=\"launcher\" type=\"button\" aria-label=\"${escapeAttribute(appearance.labels.open)}\"><slot name=\"launcher-icon\">✦</slot></button>\n <section class=\"panel\" aria-label=\"${escapeAttribute(appearance.brand.name)}\">\n <header><slot name=\"header-leading\"></slot><img class=\"brand-logo\" alt=\"\"><strong></strong><slot name=\"header-actions\"></slot><button class=\"close\" type=\"button\" aria-label=\"${escapeAttribute(appearance.labels.close)}\">×</button></header>\n <div class=\"welcome\"><slot name=\"empty-state\"><h2></h2><p></p></slot></div>\n <div class=\"suggested-prompts\"></div>\n <div class=\"messages\" aria-live=\"polite\"></div>\n <form><slot name=\"composer-leading\"></slot><textarea rows=\"1\"></textarea><button class=\"send\" type=\"submit\"></button><slot name=\"composer-trailing\"></slot></form>\n <nav class=\"legal\" aria-label=\"Legal\"></nav>\n <slot name=\"conversation-footer\"></slot>\n </section>`;\n queryRequired<HTMLElement>(this.shadowRoot, 'strong').textContent = appearance.brand.name;\n const launcherIcon = appearance.brand.mark[this.#resolvedMode()];\n if (launcherIcon) {\n const launcherSlot = queryRequired<HTMLSlotElement>(\n this.shadowRoot,\n 'slot[name=\"launcher-icon\"]',\n );\n const icon = document.createElement('img');\n icon.src = launcherIcon;\n icon.alt = '';\n launcherSlot.replaceChildren(icon);\n }\n const logo = queryRequired<HTMLImageElement>(this.shadowRoot, '.brand-logo');\n const logoUrl = appearance.brand.logo[this.#resolvedMode()];\n if (logoUrl) {\n logo.src = logoUrl;\n logo.alt = appearance.brand.name;\n } else {\n logo.hidden = true;\n }\n queryRequired<HTMLElement>(this.shadowRoot, 'h2').textContent =\n appearance.labels.welcomeHeading;\n queryRequired<HTMLElement>(this.shadowRoot, 'p').textContent = appearance.labels.welcomeMessage;\n const textarea = queryRequired<HTMLTextAreaElement>(this.shadowRoot, 'textarea');\n textarea.placeholder = appearance.labels.composerPlaceholder;\n textarea.setAttribute('aria-label', appearance.labels.composerPlaceholder);\n queryRequired<HTMLElement>(this.shadowRoot, '.send').textContent = appearance.labels.send;\n const prompts = queryRequired<HTMLElement>(this.shadowRoot, '.suggested-prompts');\n for (const prompt of appearance.suggestedPrompts) {\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = prompt;\n button.addEventListener('click', () => this.#sendGuarded(prompt));\n prompts.append(button);\n }\n if (!appearance.behavior.showLauncher)\n queryRequired<HTMLElement>(this.shadowRoot, '.launcher').hidden = true;\n if (!appearance.behavior.showHeader)\n queryRequired<HTMLElement>(this.shadowRoot, 'header').hidden = true;\n const legal = queryRequired<HTMLElement>(this.shadowRoot, '.legal');\n for (const [label, href] of [\n ['Privacy', appearance.privacyUrl],\n ['Terms', appearance.termsUrl],\n ] as const) {\n if (!href) continue;\n const link = document.createElement('a');\n link.href = href;\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.textContent = label;\n legal.append(link);\n }\n this.#messages = this.shadowRoot.querySelector('.messages') ?? undefined;\n this.shadowRoot.querySelector('.launcher')?.addEventListener('click', () => this.open());\n this.shadowRoot.querySelector('.close')?.addEventListener('click', () => this.close());\n this.shadowRoot.querySelector('form')?.addEventListener('submit', (event) => {\n event.preventDefault();\n const value = textarea.value;\n textarea.value = '';\n this.#sendGuarded(value);\n });\n this.#applyTheme();\n }\n}\n\nexport function registerNoodleAssistant(): void {\n if (globalThis.customElements && !customElements.get(ASSISTANT_TAG_NAME)) {\n customElements.define(ASSISTANT_TAG_NAME, NoodleAssistantElement);\n }\n}\n\nfunction camelToKebab(value: string): string {\n return value.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n}\n\nfunction tokenValue(name: string, value: AssistantThemeTokens[keyof AssistantThemeTokens]): string {\n if (typeof value !== 'number') return value;\n if (name === 'lineHeight' || name === 'motionScale') return String(value);\n return `${value}px`;\n}\n\nfunction escapeAttribute(value: string): string {\n return value.replaceAll('&', '&amp;').replaceAll('\"', '&quot;').replaceAll('<', '&lt;');\n}\n\nfunction queryRequired<T extends Element>(root: ShadowRoot, selector: string): T {\n const element = root.querySelector<T>(selector);\n if (!element) throw new Error(`assistant renderer is missing ${selector}`);\n return element;\n}\n\nconst styles = `<style>\n :host { color-scheme: light dark; font-family: var(--ns-assistant-font-family, var(--ns-assistant-default-font-family)); font-size: var(--ns-assistant-base-font-size, var(--ns-assistant-default-base-font-size)); line-height: var(--ns-assistant-line-height, var(--ns-assistant-default-line-height)); z-index: var(--ns-assistant-z-index, var(--ns-assistant-default-z-index)); }\n :host([data-mode=\"floating\"]) { position: fixed; bottom: 24px; right: 24px; }\n :host([data-mode=\"floating\"][data-position=\"bottom-left\"]) { right: auto; left: 24px; }\n .launcher { width: 54px; height: 54px; border: 0; border-radius: var(--ns-assistant-launcher-radius, var(--ns-assistant-default-launcher-radius)); color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); cursor: pointer; }\n .launcher img { width: 24px; height: 24px; object-fit: contain; }\n .panel { display: none; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 32px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 32px)); overflow: hidden; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); }\n :host([open]) .panel { display: grid; grid-template-rows: auto auto 1fr auto; }\n :host([open]) .launcher { display: none; }\n header { display: flex; gap: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); align-items: center; padding: calc(var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)) * 1.2); border-bottom: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); }\n header strong { flex: 1; }\n .brand-logo { display: block; max-width: 120px; max-height: 28px; object-fit: contain; }\n button { font: inherit; }\n .close, .send { border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); cursor: pointer; }\n .close { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; font-size: 24px; }\n .welcome { padding: calc(var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)) * 1.5); }\n .welcome h2 { margin: 0; font-size: 1.25em; }\n .welcome p { margin: 6px 0 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }\n .suggested-prompts { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); }\n .suggested-prompts:empty { display: none; }\n .suggested-prompts button { padding: 7px 10px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: transparent; border: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: 999px; cursor: pointer; }\n .messages { min-height: 120px; padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); overflow: auto; }\n .message { width: fit-content; max-width: 84%; margin: 8px 0; padding: 10px 12px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); white-space: pre-wrap; }\n .message .avatar { float: left; width: 24px; height: 24px; margin-right: 8px; border-radius: 50%; object-fit: cover; }\n .message time { display: block; margin-top: 4px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .75em; }\n .message.user { margin-left: auto; color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n .tool-proposal { display: grid; grid-template-columns: 1fr auto auto; gap: 8px; align-items: center; margin: 10px 0; padding: 12px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); }\n .tool-proposal button { padding: 8px 10px; border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); cursor: pointer; }\n .tool-proposal button:first-of-type { color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n form { display: flex; gap: 8px; align-items: end; padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); border-top: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); }\n textarea { flex: 1; resize: none; padding: 10px 12px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); border: 0; border-radius: var(--ns-assistant-input-radius, var(--ns-assistant-default-input-radius)); font: inherit; }\n textarea:focus-visible, button:focus-visible { outline: 3px solid var(--ns-assistant-focus, var(--ns-assistant-default-focus)); outline-offset: 2px; }\n .send { padding: 10px 14px; color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n .legal { display: flex; gap: 12px; justify-content: center; padding: 0 12px 10px; font-size: .8em; }\n .legal:empty { display: none; }\n .legal a { color: var(--ns-assistant-link, var(--ns-assistant-default-link)); }\n :host([data-density=\"compact\"]) .welcome { padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); }\n @media (max-width: 640px) { :host([mobile-fullscreen][open]) { inset: 0; } :host([mobile-fullscreen][open]) .panel { width: 100vw; min-height: 100vh; max-height: 100vh; border-radius: 0; } }\n @media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; } }\n @media (max-width: 560px) { :host([data-mode=\"floating\"]) { inset: auto 12px 12px; } :host([open]) .panel { width: calc(100vw - 24px); max-height: calc(100vh - 24px); } }\n</style>`;\n"],"mappings":"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","names":["NoodleAssistant"]}
1
+ {"version":3,"sources":["../src/react.ts","../src/appearance.ts","../src/transport.ts","../src/element.ts"],"sourcesContent":["import {\n createElement,\n forwardRef,\n type ReactElement,\n useEffect,\n useImperativeHandle,\n useRef,\n} from 'react';\nimport type { AssistantThemeMode } from './appearance.js';\nimport { type NoodleAssistantElement, registerNoodleAssistant } from './element.js';\nimport type { AssistantErrorDetail } from './transport.js';\n\nexport interface NoodleAssistantProps {\n readonly sessionEndpoint: string;\n readonly theme?: AssistantThemeMode;\n readonly open?: boolean;\n readonly className?: string;\n readonly onReady?: () => void;\n readonly onError?: (error: AssistantErrorDetail) => void;\n readonly onSessionExpired?: () => void;\n}\n\nexport const NoodleAssistant = forwardRef<NoodleAssistantElement, NoodleAssistantProps>(\n function NoodleAssistant(props, forwardedRef): ReactElement {\n const ref = useRef<NoodleAssistantElement>(null);\n useImperativeHandle(forwardedRef, () => ref.current as NoodleAssistantElement, []);\n useEffect(() => {\n registerNoodleAssistant();\n const element = ref.current;\n if (!element) return;\n element.sessionEndpoint = props.sessionEndpoint;\n const ready = () => props.onReady?.();\n const error = (event: Event) =>\n props.onError?.((event as CustomEvent<AssistantErrorDetail>).detail);\n const expired = () => props.onSessionExpired?.();\n element.addEventListener('assistant-ready', ready);\n element.addEventListener('assistant-error', error);\n element.addEventListener('assistant-session-expired', expired);\n return () => {\n element.removeEventListener('assistant-ready', ready);\n element.removeEventListener('assistant-error', error);\n element.removeEventListener('assistant-session-expired', expired);\n };\n }, [props.onError, props.onReady, props.onSessionExpired, props.sessionEndpoint]);\n return createElement('noodle-assistant', {\n ref,\n class: props.className,\n 'session-endpoint': props.sessionEndpoint,\n ...(props.theme ? { theme: props.theme } : {}),\n ...(props.open ? { open: '' } : {}),\n });\n },\n);\n","export type AssistantThemeMode = 'auto' | 'light' | 'dark';\nexport type AssistantLayoutMode = 'floating' | 'inline' | 'drawer';\nexport type AssistantPosition = 'bottom-left' | 'bottom-right';\n\nexport interface AssistantThemeTokens {\n readonly page: string;\n readonly panel: string;\n readonly elevated: string;\n readonly input: string;\n readonly hover: string;\n readonly selected: string;\n readonly text: string;\n readonly mutedText: string;\n readonly accent: string;\n readonly accentText: string;\n readonly link: string;\n readonly divider: string;\n readonly focus: string;\n readonly success: string;\n readonly warning: string;\n readonly danger: string;\n readonly overlay: string;\n readonly code: string;\n readonly widgetFrame: string;\n readonly fontFamily: string;\n readonly monoFontFamily: string;\n readonly baseFontSize: number;\n readonly messageFontSize: number;\n readonly lineHeight: number;\n readonly panelRadius: number;\n readonly cardRadius: number;\n readonly inputRadius: number;\n readonly buttonRadius: number;\n readonly launcherRadius: number;\n readonly spacing: number;\n readonly shadow: string;\n readonly backdropBlur: number;\n readonly motionScale: number;\n}\n\nexport interface AssistantConfiguration {\n readonly branding?: {\n readonly name?: string;\n readonly accent?: string;\n readonly surface?: string;\n readonly surfaceDark?: string;\n readonly logo?: AssistantBrandAsset;\n readonly mark?: AssistantBrandAsset;\n readonly avatar?: AssistantBrandAsset;\n readonly theme?: {\n readonly light?: BrandThemeOverrides;\n readonly dark?: BrandThemeOverrides;\n };\n readonly radius?: 'none' | 'sm' | 'md' | 'lg';\n readonly density?: 'compact' | 'comfortable';\n readonly typography?: 'system' | 'serif' | 'mono';\n readonly colorScheme?: AssistantThemeMode;\n };\n readonly assistant?: AssistantUiConfiguration;\n}\n\ninterface AssistantBrandAsset {\n readonly uri: string;\n readonly darkUri?: string;\n readonly alt: string;\n}\n\ninterface BrandThemeOverrides {\n readonly surface?: string;\n readonly surfaceRaised?: string;\n readonly surfaceMuted?: string;\n readonly text?: string;\n readonly textMuted?: string;\n readonly accent?: string;\n readonly accentText?: string;\n readonly link?: string;\n readonly border?: string;\n readonly borderStrong?: string;\n readonly focus?: string;\n readonly success?: string;\n readonly warning?: string;\n readonly danger?: string;\n readonly code?: string;\n}\n\ninterface AssistantUiConfiguration {\n readonly layout?: {\n readonly mode?: AssistantLayoutMode;\n readonly position?: AssistantPosition;\n readonly panelWidth?: number;\n readonly panelMinHeight?: number;\n readonly panelMaxHeight?: number;\n readonly zIndex?: number;\n readonly density?: 'compact' | 'comfortable';\n readonly mobileFullscreen?: boolean;\n };\n readonly behavior?: {\n readonly startOpen?: boolean;\n readonly closeOnEscape?: boolean;\n readonly closeOnOutsideClick?: boolean;\n readonly showLauncher?: boolean;\n readonly showHeader?: boolean;\n readonly showAvatars?: boolean;\n readonly showTimestamps?: boolean;\n };\n readonly labels?: Partial<AssistantLabels>;\n readonly suggestedPrompts?: readonly string[];\n readonly privacyUrl?: string;\n readonly termsUrl?: string;\n readonly locale?: string;\n readonly direction?: 'ltr' | 'rtl' | 'auto';\n}\n\nexport interface AssistantLabels {\n readonly welcomeHeading: string;\n readonly welcomeMessage: string;\n readonly composerPlaceholder: string;\n readonly send: string;\n readonly stop: string;\n readonly close: string;\n readonly open: string;\n readonly confirm: string;\n readonly cancel: string;\n readonly retry: string;\n readonly unavailable: string;\n readonly sessionExpired: string;\n}\n\nexport interface ResolvedAssistantAppearance {\n readonly brand: {\n readonly name: string;\n readonly logo: { readonly light?: string; readonly dark?: string };\n readonly avatar: { readonly light?: string; readonly dark?: string };\n readonly mark: { readonly light?: string; readonly dark?: string };\n };\n readonly theme: {\n readonly defaultMode: AssistantThemeMode;\n readonly light: AssistantThemeTokens;\n readonly dark: AssistantThemeTokens;\n };\n readonly layout: {\n readonly mode: AssistantLayoutMode;\n readonly position: AssistantPosition;\n readonly panelWidth: number;\n readonly panelMinHeight: number;\n readonly panelMaxHeight: number;\n readonly zIndex: number;\n readonly density: 'compact' | 'comfortable';\n readonly mobileFullscreen: boolean;\n };\n readonly behavior: {\n readonly startOpen: boolean;\n readonly closeOnEscape: boolean;\n readonly closeOnOutsideClick: boolean;\n readonly showLauncher: boolean;\n readonly showHeader: boolean;\n readonly showAvatars: boolean;\n readonly showTimestamps: boolean;\n };\n readonly labels: AssistantLabels;\n readonly suggestedPrompts: readonly string[];\n readonly privacyUrl?: string;\n readonly termsUrl?: string;\n readonly locale: string;\n readonly direction: 'ltr' | 'rtl' | 'auto';\n}\n\nconst common = {\n fontFamily: 'inherit',\n monoFontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n baseFontSize: 15,\n messageFontSize: 15,\n lineHeight: 1.5,\n panelRadius: 20,\n cardRadius: 14,\n inputRadius: 14,\n buttonRadius: 12,\n launcherRadius: 999,\n spacing: 12,\n backdropBlur: 18,\n motionScale: 1,\n} as const;\n\nexport const DEFAULT_APPEARANCE: ResolvedAssistantAppearance = {\n brand: { name: 'Assistant', logo: {}, avatar: {}, mark: {} },\n theme: {\n defaultMode: 'auto',\n light: {\n ...common,\n page: '#F7F7F8',\n panel: '#FFFFFF',\n elevated: '#FFFFFF',\n input: '#F1F1F3',\n hover: '#ECECEF',\n selected: '#E4E2FF',\n text: '#18181B',\n mutedText: '#71717A',\n accent: '#5B4CF0',\n accentText: '#FFFFFF',\n link: '#4A3BD5',\n divider: '#E4E4E7',\n focus: '#5B4CF0',\n success: '#16835D',\n warning: '#A45B00',\n danger: '#C92A45',\n overlay: '#18181B66',\n code: '#F1F1F3',\n widgetFrame: '#E4E4E7',\n shadow: '0 24px 80px rgba(24, 24, 27, 0.18)',\n },\n dark: {\n ...common,\n page: '#111113',\n panel: '#19191D',\n elevated: '#222228',\n input: '#26262C',\n hover: '#303038',\n selected: '#37315F',\n text: '#FAFAFA',\n mutedText: '#A1A1AA',\n accent: '#A99FFF',\n accentText: '#17131F',\n link: '#B9B1FF',\n divider: '#34343B',\n focus: '#B9B1FF',\n success: '#58C69A',\n warning: '#F2B45F',\n danger: '#FF8094',\n overlay: '#00000099',\n code: '#26262C',\n widgetFrame: '#34343B',\n shadow: '0 24px 90px rgba(0, 0, 0, 0.55)',\n },\n },\n layout: {\n mode: 'floating',\n position: 'bottom-right',\n panelWidth: 400,\n panelMinHeight: 420,\n panelMaxHeight: 720,\n zIndex: 2147483000,\n density: 'comfortable',\n mobileFullscreen: true,\n },\n behavior: {\n startOpen: false,\n closeOnEscape: true,\n closeOnOutsideClick: false,\n showLauncher: true,\n showHeader: true,\n showAvatars: true,\n showTimestamps: false,\n },\n labels: {\n welcomeHeading: 'How can I help?',\n welcomeMessage: '',\n composerPlaceholder: 'Ask a question…',\n send: 'Send',\n stop: 'Stop',\n close: 'Close assistant',\n open: 'Open assistant',\n confirm: 'Confirm',\n cancel: 'Cancel',\n retry: 'Try again',\n unavailable: 'The assistant is temporarily unavailable.',\n sessionExpired: 'Your assistant session expired. Reopen it to continue.',\n },\n suggestedPrompts: [],\n locale: 'en',\n direction: 'auto',\n};\n\nexport function resolveAppearance(input: AssistantConfiguration = {}): ResolvedAssistantAppearance {\n const branding = input.branding;\n const assistant = input.assistant;\n return {\n brand: {\n ...DEFAULT_APPEARANCE.brand,\n ...(branding?.name ? { name: branding.name } : {}),\n logo: themedAsset(branding?.logo),\n avatar: themedAsset(branding?.avatar),\n mark: themedAsset(branding?.mark),\n },\n theme: {\n defaultMode: branding?.colorScheme ?? DEFAULT_APPEARANCE.theme.defaultMode,\n light: resolveTheme('light', branding),\n dark: resolveTheme('dark', branding),\n },\n layout: {\n ...DEFAULT_APPEARANCE.layout,\n ...(branding?.density ? { density: branding.density } : {}),\n ...assistant?.layout,\n },\n behavior: { ...DEFAULT_APPEARANCE.behavior, ...assistant?.behavior },\n labels: { ...DEFAULT_APPEARANCE.labels, ...assistant?.labels },\n suggestedPrompts: assistant?.suggestedPrompts ?? DEFAULT_APPEARANCE.suggestedPrompts,\n ...(assistant?.privacyUrl ? { privacyUrl: assistant.privacyUrl } : {}),\n ...(assistant?.termsUrl ? { termsUrl: assistant.termsUrl } : {}),\n locale: assistant?.locale ?? DEFAULT_APPEARANCE.locale,\n direction: assistant?.direction ?? DEFAULT_APPEARANCE.direction,\n };\n}\n\nfunction themedAsset(asset: AssistantBrandAsset | undefined): {\n readonly light?: string;\n readonly dark?: string;\n} {\n return asset ? { light: asset.uri, dark: asset.darkUri ?? asset.uri } : {};\n}\n\nfunction resolveTheme(\n mode: 'light' | 'dark',\n branding: AssistantConfiguration['branding'],\n): AssistantThemeTokens {\n const defaults = DEFAULT_APPEARANCE.theme[mode];\n const surface = mode === 'light' ? branding?.surface : branding?.surfaceDark;\n const portable = branding?.theme?.[mode];\n const radius = branding?.radius ? radiusValue(branding.radius) : undefined;\n return {\n ...defaults,\n ...(branding?.accent ? { accent: branding.accent } : {}),\n ...(surface ? { page: surface, panel: surface } : {}),\n ...mapPortableTheme(portable),\n ...(radius === undefined\n ? {}\n : {\n panelRadius: radius,\n cardRadius: radius,\n inputRadius: Math.max(0, radius - 2),\n buttonRadius: Math.max(0, radius - 2),\n }),\n ...(branding?.typography === 'serif'\n ? { fontFamily: 'ui-serif, Georgia, serif' }\n : branding?.typography === 'mono'\n ? { fontFamily: defaults.monoFontFamily }\n : {}),\n };\n}\n\nfunction mapPortableTheme(input: BrandThemeOverrides | undefined): Partial<AssistantThemeTokens> {\n if (!input) return {};\n return {\n ...(input.surface ? { page: input.surface, panel: input.surface } : {}),\n ...(input.surfaceRaised ? { elevated: input.surfaceRaised } : {}),\n ...(input.surfaceMuted\n ? { input: input.surfaceMuted, hover: input.surfaceMuted, selected: input.surfaceMuted }\n : {}),\n ...(input.text ? { text: input.text } : {}),\n ...(input.textMuted ? { mutedText: input.textMuted } : {}),\n ...(input.accent ? { accent: input.accent } : {}),\n ...(input.accentText ? { accentText: input.accentText } : {}),\n ...(input.link ? { link: input.link } : {}),\n ...(input.border ? { divider: input.border, widgetFrame: input.border } : {}),\n ...(input.focus ? { focus: input.focus } : {}),\n ...(input.success ? { success: input.success } : {}),\n ...(input.warning ? { warning: input.warning } : {}),\n ...(input.danger ? { danger: input.danger } : {}),\n ...(input.code ? { code: input.code } : {}),\n };\n}\n\nfunction radiusValue(radius: 'none' | 'sm' | 'md' | 'lg'): number {\n if (radius === 'none') return 0;\n if (radius === 'sm') return 8;\n if (radius === 'lg') return 18;\n return 14;\n}\n","export interface AssistantEvent {\n readonly event: string;\n readonly data: Readonly<Record<string, unknown>>;\n}\n\nexport interface AssistantErrorDetail {\n readonly code: string;\n readonly status?: number;\n readonly retryable: boolean;\n}\n\n/**\n * A 2xx response whose body carried no assistant events at all — typically an auth redirect or\n * proxy page returning HTML with a 200. Silently rendering nothing strands the end user, so the\n * transport fails loudly instead (ADR 0151 hardening).\n */\nexport class AssistantTransportError extends Error {\n readonly code = 'invalid_response' as const;\n\n constructor(contentType: string) {\n super(`assistant response was not an event stream (content-type: ${contentType || 'unknown'})`);\n this.name = 'AssistantTransportError';\n }\n}\n\n/** Consume JSON-bearing server-sent events without buffering the whole assistant turn. */\nexport async function consumeAssistantEvents(\n response: Response,\n onEvent: (event: AssistantEvent) => void,\n): Promise<void> {\n let delivered = 0;\n let sawText = false;\n const deliver = (event: AssistantEvent): void => {\n delivered += 1;\n onEvent(event);\n };\n if (!response.body) {\n const text = await response.text();\n sawText = text.trim().length > 0;\n emitFrames(text, deliver, true);\n } else {\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let pending = '';\n while (true) {\n const { done, value } = await reader.read();\n const chunk = decoder.decode(value, { stream: !done });\n if (!sawText && chunk.trim().length > 0) sawText = true;\n pending += chunk;\n pending = emitFrames(pending, deliver, done);\n if (done) break;\n }\n }\n if (delivered === 0 && sawText) {\n throw new AssistantTransportError(response.headers.get('content-type') ?? '');\n }\n}\n\nfunction emitFrames(\n input: string,\n onEvent: (event: AssistantEvent) => void,\n flush: boolean,\n): string {\n const normalized = input.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n');\n const frames = normalized.split('\\n\\n');\n const pending = flush ? '' : (frames.pop() ?? '');\n for (const frame of frames) {\n const event = parseFrame(frame);\n if (event) onEvent(event);\n }\n if (flush && frames.length === 0 && normalized.trim()) {\n const event = parseFrame(normalized);\n if (event) onEvent(event);\n }\n return pending;\n}\n\nfunction parseFrame(frame: string): AssistantEvent | undefined {\n let event = 'message';\n const data: string[] = [];\n for (const line of frame.split('\\n')) {\n if (line.startsWith(':')) continue;\n const separator = line.indexOf(':');\n const field = separator < 0 ? line : line.slice(0, separator);\n const value = separator < 0 ? '' : line.slice(separator + 1).replace(/^ /, '');\n if (field === 'event') event = value;\n if (field === 'data') data.push(value);\n }\n if (data.length === 0) return undefined;\n try {\n return { event, data: JSON.parse(data.join('\\n')) as Readonly<Record<string, unknown>> };\n } catch {\n return undefined;\n }\n}\n","import {\n type AssistantConfiguration,\n type AssistantThemeMode,\n type AssistantThemeTokens,\n resolveAppearance,\n} from './appearance.js';\nimport {\n type AssistantErrorDetail,\n AssistantTransportError,\n consumeAssistantEvents,\n} from './transport.js';\n\nexport const ASSISTANT_TAG_NAME = 'noodle-assistant';\nconst HTMLElementBase: typeof HTMLElement =\n globalThis.HTMLElement ?? (class {} as unknown as typeof HTMLElement);\n\ninterface SessionResponse {\n readonly token: string;\n readonly expiresAt: string;\n readonly endpoints: {\n readonly turns: string;\n readonly toolConfirmations: string;\n };\n readonly configuration?: AssistantConfiguration;\n}\n\nexport class NoodleAssistantElement extends HTMLElementBase {\n static readonly observedAttributes = ['open', 'theme'];\n #appearance = resolveAppearance();\n #session: SessionResponse | undefined;\n #messages: HTMLElement | undefined;\n #media: MediaQueryList | undefined;\n #context: Readonly<Record<string, string | number | boolean | null>> | undefined;\n sessionEndpoint = '';\n\n connectedCallback(): void {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n if (!this.sessionEndpoint) this.sessionEndpoint = this.getAttribute('session-endpoint') ?? '';\n this.#media = globalThis.matchMedia?.('(prefers-color-scheme: dark)');\n this.#media?.addEventListener('change', this.#handleSystemTheme);\n document.addEventListener('keydown', this.#handleDocumentKeydown);\n document.addEventListener('pointerdown', this.#handleDocumentPointerDown);\n if (this.#appearance.behavior.startOpen) this.setAttribute('open', '');\n this.#render();\n this.dispatchEvent(new CustomEvent('assistant-ready'));\n }\n\n disconnectedCallback(): void {\n this.#media?.removeEventListener('change', this.#handleSystemTheme);\n document.removeEventListener('keydown', this.#handleDocumentKeydown);\n document.removeEventListener('pointerdown', this.#handleDocumentPointerDown);\n }\n\n attributeChangedCallback(name: string): void {\n if (name === 'theme') this.#applyTheme();\n }\n\n open(): void {\n this.setAttribute('open', '');\n this.dispatchEvent(new CustomEvent('assistant-open'));\n }\n\n close(): void {\n this.removeAttribute('open');\n this.dispatchEvent(new CustomEvent('assistant-close'));\n }\n\n toggle(): void {\n this.hasAttribute('open') ? this.close() : this.open();\n }\n\n focusComposer(): void {\n this.shadowRoot?.querySelector<HTMLTextAreaElement>('textarea')?.focus();\n }\n\n resetSession(): void {\n this.#session = undefined;\n this.#messages?.replaceChildren();\n this.dispatchEvent(new CustomEvent('assistant-session-reset'));\n }\n\n updateContext(context: Readonly<Record<string, string | number | boolean | null>>): void {\n this.#context = { ...context };\n this.dispatchEvent(new CustomEvent('assistant-context-changed', { detail: { context } }));\n }\n\n async sendMessage(text: string): Promise<void> {\n const message = text.trim();\n if (!message) return;\n if (!this.#session) this.#session = await this.#createSession();\n this.#appendMessage('user', message);\n this.dispatchEvent(new CustomEvent('assistant-message-started'));\n await this.#sendTurn(message, true);\n }\n\n async #sendTurn(message: string, mayRetry: boolean): Promise<void> {\n if (!this.#session) this.#session = await this.#createSession();\n const response = await fetch(this.#session.endpoints.turns, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.#session.token}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({ message }),\n });\n if (response.status === 401 && mayRetry) {\n this.#session = undefined;\n this.dispatchEvent(new CustomEvent('assistant-session-expired'));\n await this.#sendTurn(message, false);\n return;\n }\n if (!response.ok) {\n this.#dispatchError({ code: 'turn_failed', status: response.status, retryable: false });\n throw new Error(`Assistant turn failed (${response.status})`);\n }\n let assistantBody: HTMLElement | undefined;\n try {\n await consumeAssistantEvents(response, (event) => {\n if (event.event === 'content') {\n const body = assistantBody ?? this.#appendMessage('assistant', '');\n assistantBody = body;\n if (body) body.textContent += String(event.data.delta ?? '');\n }\n if (event.event === 'tool_proposed') {\n this.#appendToolProposal(\n String(event.data.id ?? ''),\n String(event.data.tool ?? 'Action'),\n );\n }\n if (event.event === 'error') {\n this.#dispatchError({\n code: String(event.data.code ?? 'stream_failed'),\n retryable: event.data.retryable === true,\n });\n }\n });\n } catch (error) {\n if (error instanceof AssistantTransportError) {\n this.#dispatchError({ code: error.code, retryable: false });\n }\n throw error;\n }\n this.dispatchEvent(new CustomEvent('assistant-message-completed'));\n }\n\n /**\n * Every listener the element attaches to its own DOM must go through this guard: internal UI\n * failures surface as `assistant-error` events (already dispatched by the failing path) and must\n * never escape as unhandled rejections into the embedding page. Programmatic callers use\n * `sendMessage`/`confirmTool` directly and keep the rejection.\n */\n #sendGuarded(text: string): void {\n void this.sendMessage(text).catch(() => {});\n }\n\n async confirmTool(id: string): Promise<void> {\n if (!this.#session) {\n this.#dispatchError({ code: 'confirmation_expired', retryable: false });\n throw new Error('assistant session is not active');\n }\n const response = await fetch(this.#session.endpoints.toolConfirmations, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.#session.token}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({ id }),\n });\n if (!response.ok) {\n const expired = response.status === 401 || response.status === 409;\n if (response.status === 401) {\n this.#session = undefined;\n this.dispatchEvent(new CustomEvent('assistant-session-expired'));\n }\n this.#dispatchError({\n code: expired ? 'confirmation_expired' : 'confirmation_failed',\n status: response.status,\n retryable: false,\n });\n throw new Error(`Assistant confirmation failed (${response.status})`);\n }\n let completed: Readonly<Record<string, unknown>> | undefined;\n let narrationBody: HTMLElement | undefined;\n await consumeAssistantEvents(response, (event) => {\n if (event.event === 'tool_completed') completed = event.data;\n if (event.event === 'content') {\n const body = narrationBody ?? this.#appendMessage('assistant', '');\n narrationBody = body;\n if (body) body.textContent += String(event.data.delta ?? '');\n }\n });\n // The narrated reply supersedes the raw result; older services send only tool_completed,\n // so the JSON rendering remains as the fallback.\n if (completed && !narrationBody) {\n this.#appendMessage('assistant', JSON.stringify(completed.result ?? {}));\n }\n this.dispatchEvent(new CustomEvent('assistant-tool-completed', { detail: { id } }));\n }\n\n #handleSystemTheme = (): void => this.#applyTheme();\n\n #handleDocumentKeydown = (event: KeyboardEvent): void => {\n if (\n event.key === 'Escape' &&\n this.hasAttribute('open') &&\n this.#appearance.behavior.closeOnEscape\n ) {\n this.close();\n }\n };\n\n #handleDocumentPointerDown = (event: PointerEvent): void => {\n if (\n this.hasAttribute('open') &&\n this.#appearance.behavior.closeOnOutsideClick &&\n !event.composedPath().includes(this)\n ) {\n this.close();\n }\n };\n\n async #createSession(): Promise<SessionResponse> {\n if (!this.sessionEndpoint) throw new Error('sessionEndpoint is required');\n let response: Response;\n try {\n response = await fetch(this.sessionEndpoint, {\n method: 'POST',\n headers: { Accept: 'application/json', 'Content-Type': 'application/json' },\n body: JSON.stringify(this.#context ? { context: this.#context } : {}),\n credentials: 'same-origin',\n });\n } catch (error) {\n this.#dispatchError({ code: 'session_failed', retryable: true });\n throw error;\n }\n if (!response.ok) {\n this.#dispatchError({ code: 'session_failed', status: response.status, retryable: true });\n throw new Error(`Assistant session failed (${response.status})`);\n }\n let session: SessionResponse;\n try {\n session = (await response.json()) as SessionResponse;\n } catch (error) {\n this.#dispatchError({ code: 'session_failed', retryable: true });\n throw error;\n }\n if (session.configuration) {\n this.#appearance = resolveAppearance(session.configuration);\n this.#render();\n }\n this.dispatchEvent(\n new CustomEvent('assistant-session-started', { detail: { expiresAt: session.expiresAt } }),\n );\n return session;\n }\n\n #appendMessage(role: 'user' | 'assistant', text: string): HTMLElement | undefined {\n if (!this.#messages) return undefined;\n const message = document.createElement('div');\n message.className = `message ${role}`;\n if (\n role === 'assistant' &&\n this.#appearance.behavior.showAvatars &&\n this.#appearance.brand.avatar[this.#resolvedMode()]\n ) {\n const avatar = document.createElement('img');\n avatar.className = 'avatar';\n avatar.src = this.#appearance.brand.avatar[this.#resolvedMode()] ?? '';\n avatar.alt = '';\n message.append(avatar);\n }\n const body = document.createElement('span');\n body.textContent = text;\n message.append(body);\n if (this.#appearance.behavior.showTimestamps) {\n const timestamp = document.createElement('time');\n timestamp.dateTime = new Date().toISOString();\n timestamp.textContent = new Intl.DateTimeFormat(this.#appearance.locale, {\n hour: 'numeric',\n minute: '2-digit',\n }).format(new Date());\n message.append(timestamp);\n }\n this.#messages.append(message);\n return body;\n }\n\n #dispatchError(detail: AssistantErrorDetail): void {\n this.dispatchEvent(new CustomEvent('assistant-error', { detail }));\n }\n\n #appendToolProposal(id: string, tool: string): void {\n if (!this.#messages || !id) return;\n const card = document.createElement('section');\n card.className = 'tool-proposal';\n const label = document.createElement('strong');\n label.textContent = tool;\n const confirm = document.createElement('button');\n confirm.type = 'button';\n confirm.textContent = this.#appearance.labels.confirm;\n confirm.addEventListener('click', () => {\n confirm.disabled = true;\n void this.confirmTool(id).catch(() => {\n confirm.disabled = false;\n this.dispatchEvent(\n new CustomEvent('assistant-error', { detail: { code: 'confirmation_failed' } }),\n );\n });\n });\n const cancel = document.createElement('button');\n cancel.type = 'button';\n cancel.textContent = this.#appearance.labels.cancel;\n cancel.addEventListener('click', () => card.remove());\n card.append(label, confirm, cancel);\n this.#messages.append(card);\n this.dispatchEvent(new CustomEvent('assistant-tool-proposed', { detail: { id, tool } }));\n }\n\n #resolvedMode(): Exclude<AssistantThemeMode, 'auto'> {\n const configured =\n (this.getAttribute('theme') as AssistantThemeMode | null) ??\n this.#appearance.theme.defaultMode;\n return configured === 'auto' ? (this.#media?.matches ? 'dark' : 'light') : configured;\n }\n\n #applyTheme(): void {\n const mode = this.#resolvedMode();\n this.setAttribute('data-theme', mode);\n const tokens = this.#appearance.theme[mode];\n for (const [name, value] of Object.entries(tokens)) {\n this.style.setProperty(\n `--ns-assistant-default-${camelToKebab(name)}`,\n tokenValue(name, value),\n );\n }\n this.style.setProperty(\n '--ns-assistant-default-panel-width',\n `${this.#appearance.layout.panelWidth}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-min-height',\n `${this.#appearance.layout.panelMinHeight}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-max-height',\n `${this.#appearance.layout.panelMaxHeight}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-z-index',\n String(this.#appearance.layout.zIndex),\n );\n const logo = this.shadowRoot?.querySelector<HTMLImageElement>('.brand-logo');\n const logoUrl = this.#appearance.brand.logo[mode];\n if (logo) {\n logo.hidden = !logoUrl;\n if (logoUrl) logo.src = logoUrl;\n }\n }\n\n #render(): void {\n if (!this.shadowRoot) return;\n const appearance = this.#appearance;\n this.setAttribute('role', 'complementary');\n this.setAttribute('aria-label', appearance.brand.name);\n this.setAttribute('lang', appearance.locale);\n this.setAttribute('dir', appearance.direction);\n this.dataset.mode = appearance.layout.mode;\n this.dataset.position = appearance.layout.position;\n this.dataset.density = appearance.layout.density;\n this.toggleAttribute('mobile-fullscreen', appearance.layout.mobileFullscreen);\n this.shadowRoot.innerHTML = `${styles}\n <button class=\"launcher\" type=\"button\" aria-label=\"${escapeAttribute(appearance.labels.open)}\"><slot name=\"launcher-icon\">✦</slot></button>\n <section class=\"panel\" aria-label=\"${escapeAttribute(appearance.brand.name)}\">\n <header><slot name=\"header-leading\"></slot><img class=\"brand-logo\" alt=\"\"><strong></strong><slot name=\"header-actions\"></slot><button class=\"close\" type=\"button\" aria-label=\"${escapeAttribute(appearance.labels.close)}\">×</button></header>\n <div class=\"welcome\"><slot name=\"empty-state\"><h2></h2><p></p></slot></div>\n <div class=\"suggested-prompts\"></div>\n <div class=\"messages\" aria-live=\"polite\"></div>\n <form><slot name=\"composer-leading\"></slot><textarea rows=\"1\"></textarea><button class=\"send\" type=\"submit\"></button><slot name=\"composer-trailing\"></slot></form>\n <nav class=\"legal\" aria-label=\"Legal\"></nav>\n <slot name=\"conversation-footer\"></slot>\n </section>`;\n queryRequired<HTMLElement>(this.shadowRoot, 'strong').textContent = appearance.brand.name;\n const launcherIcon = appearance.brand.mark[this.#resolvedMode()];\n if (launcherIcon) {\n const launcherSlot = queryRequired<HTMLSlotElement>(\n this.shadowRoot,\n 'slot[name=\"launcher-icon\"]',\n );\n const icon = document.createElement('img');\n icon.src = launcherIcon;\n icon.alt = '';\n launcherSlot.replaceChildren(icon);\n }\n const logo = queryRequired<HTMLImageElement>(this.shadowRoot, '.brand-logo');\n const logoUrl = appearance.brand.logo[this.#resolvedMode()];\n if (logoUrl) {\n logo.src = logoUrl;\n logo.alt = appearance.brand.name;\n } else {\n logo.hidden = true;\n }\n queryRequired<HTMLElement>(this.shadowRoot, 'h2').textContent =\n appearance.labels.welcomeHeading;\n queryRequired<HTMLElement>(this.shadowRoot, 'p').textContent = appearance.labels.welcomeMessage;\n const textarea = queryRequired<HTMLTextAreaElement>(this.shadowRoot, 'textarea');\n textarea.placeholder = appearance.labels.composerPlaceholder;\n textarea.setAttribute('aria-label', appearance.labels.composerPlaceholder);\n queryRequired<HTMLElement>(this.shadowRoot, '.send').textContent = appearance.labels.send;\n const prompts = queryRequired<HTMLElement>(this.shadowRoot, '.suggested-prompts');\n for (const prompt of appearance.suggestedPrompts) {\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = prompt;\n button.addEventListener('click', () => this.#sendGuarded(prompt));\n prompts.append(button);\n }\n if (!appearance.behavior.showLauncher)\n queryRequired<HTMLElement>(this.shadowRoot, '.launcher').hidden = true;\n if (!appearance.behavior.showHeader)\n queryRequired<HTMLElement>(this.shadowRoot, 'header').hidden = true;\n const legal = queryRequired<HTMLElement>(this.shadowRoot, '.legal');\n for (const [label, href] of [\n ['Privacy', appearance.privacyUrl],\n ['Terms', appearance.termsUrl],\n ] as const) {\n if (!href) continue;\n const link = document.createElement('a');\n link.href = href;\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.textContent = label;\n legal.append(link);\n }\n this.#messages = this.shadowRoot.querySelector('.messages') ?? undefined;\n this.shadowRoot.querySelector('.launcher')?.addEventListener('click', () => this.open());\n this.shadowRoot.querySelector('.close')?.addEventListener('click', () => this.close());\n this.shadowRoot.querySelector('form')?.addEventListener('submit', (event) => {\n event.preventDefault();\n const value = textarea.value;\n textarea.value = '';\n this.#sendGuarded(value);\n });\n this.#applyTheme();\n }\n}\n\nexport function registerNoodleAssistant(): void {\n if (globalThis.customElements && !customElements.get(ASSISTANT_TAG_NAME)) {\n customElements.define(ASSISTANT_TAG_NAME, NoodleAssistantElement);\n }\n}\n\nfunction camelToKebab(value: string): string {\n return value.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n}\n\nfunction tokenValue(name: string, value: AssistantThemeTokens[keyof AssistantThemeTokens]): string {\n if (typeof value !== 'number') return value;\n if (name === 'lineHeight' || name === 'motionScale') return String(value);\n return `${value}px`;\n}\n\nfunction escapeAttribute(value: string): string {\n return value.replaceAll('&', '&amp;').replaceAll('\"', '&quot;').replaceAll('<', '&lt;');\n}\n\nfunction queryRequired<T extends Element>(root: ShadowRoot, selector: string): T {\n const element = root.querySelector<T>(selector);\n if (!element) throw new Error(`assistant renderer is missing ${selector}`);\n return element;\n}\n\nconst styles = `<style>\n :host { color-scheme: light dark; font-family: var(--ns-assistant-font-family, var(--ns-assistant-default-font-family)); font-size: var(--ns-assistant-base-font-size, var(--ns-assistant-default-base-font-size)); line-height: var(--ns-assistant-line-height, var(--ns-assistant-default-line-height)); z-index: var(--ns-assistant-z-index, var(--ns-assistant-default-z-index)); }\n :host([data-mode=\"floating\"]) { position: fixed; bottom: 24px; right: 24px; }\n :host([data-mode=\"floating\"][data-position=\"bottom-left\"]) { right: auto; left: 24px; }\n .launcher { width: 54px; height: 54px; border: 0; border-radius: var(--ns-assistant-launcher-radius, var(--ns-assistant-default-launcher-radius)); color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); cursor: pointer; }\n .launcher img { width: 24px; height: 24px; object-fit: contain; }\n .panel { display: none; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 32px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 32px)); overflow: hidden; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); }\n :host([open]) .panel { display: grid; grid-template-rows: auto auto 1fr auto; }\n :host([open]) .launcher { display: none; }\n header { display: flex; gap: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); align-items: center; padding: calc(var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)) * 1.2); border-bottom: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); }\n header strong { flex: 1; }\n .brand-logo { display: block; max-width: 120px; max-height: 28px; object-fit: contain; }\n button { font: inherit; }\n .close, .send { border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); cursor: pointer; }\n .close { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; font-size: 24px; }\n .welcome { padding: calc(var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)) * 1.5); }\n .welcome h2 { margin: 0; font-size: 1.25em; }\n .welcome p { margin: 6px 0 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }\n .suggested-prompts { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); }\n .suggested-prompts:empty { display: none; }\n .suggested-prompts button { padding: 7px 10px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: transparent; border: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: 999px; cursor: pointer; }\n .messages { min-height: 120px; padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); overflow: auto; }\n .message { width: fit-content; max-width: 84%; margin: 8px 0; padding: 10px 12px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); white-space: pre-wrap; }\n .message .avatar { float: left; width: 24px; height: 24px; margin-right: 8px; border-radius: 50%; object-fit: cover; }\n .message time { display: block; margin-top: 4px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .75em; }\n .message.user { margin-left: auto; color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n .tool-proposal { display: grid; grid-template-columns: 1fr auto auto; gap: 8px; align-items: center; margin: 10px 0; padding: 12px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); }\n .tool-proposal button { padding: 8px 10px; border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); cursor: pointer; }\n .tool-proposal button:first-of-type { color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n form { display: flex; gap: 8px; align-items: end; padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); border-top: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); }\n textarea { flex: 1; resize: none; padding: 10px 12px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); border: 0; border-radius: var(--ns-assistant-input-radius, var(--ns-assistant-default-input-radius)); font: inherit; }\n textarea:focus-visible, button:focus-visible { outline: 3px solid var(--ns-assistant-focus, var(--ns-assistant-default-focus)); outline-offset: 2px; }\n .send { padding: 10px 14px; color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n .legal { display: flex; gap: 12px; justify-content: center; padding: 0 12px 10px; font-size: .8em; }\n .legal:empty { display: none; }\n .legal a { color: var(--ns-assistant-link, var(--ns-assistant-default-link)); }\n :host([data-density=\"compact\"]) .welcome { padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); }\n @media (max-width: 640px) { :host([mobile-fullscreen][open]) { inset: 0; } :host([mobile-fullscreen][open]) .panel { width: 100vw; min-height: 100vh; max-height: 100vh; border-radius: 0; } }\n @media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; } }\n @media (max-width: 560px) { :host([data-mode=\"floating\"]) { inset: auto 12px 12px; } :host([open]) .panel { width: calc(100vw - 24px); max-height: calc(100vh - 24px); } }\n</style>`;\n"],"mappings":"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","names":["NoodleAssistant"]}
package/dist/react.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  registerNoodleAssistant
3
- } from "./chunk-OXFV6KZ2.js";
3
+ } from "./chunk-IM7SAHNE.js";
4
4
 
5
5
  // src/react.ts
6
6
  import {
package/dist/server.cjs CHANGED
@@ -39,6 +39,7 @@ async function createAssistantSession(input, dependencies = {}) {
39
39
  body: JSON.stringify({
40
40
  origin: input.origin,
41
41
  user: input.user,
42
+ ...input.claims ? { claims: input.claims } : {},
42
43
  ...input.context ? { context: input.context } : {}
43
44
  })
44
45
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import type { AssistantConfiguration } from './appearance.js';\n\nexport interface CreateAssistantSessionInput {\n readonly serviceUrl: string;\n readonly clientId: string;\n readonly clientSecret: string;\n /** Browser origin to bind into the short-lived assistant session. */\n readonly origin: string;\n readonly user: {\n readonly id: string;\n readonly email?: string;\n readonly name?: string;\n readonly tenant?: string;\n readonly roles?: readonly string[];\n };\n readonly context?: Readonly<Record<string, string | number | boolean | null>>;\n}\n\nexport interface AssistantSession {\n readonly token: string;\n readonly expiresAt: string;\n readonly endpoints: {\n readonly turns: string;\n readonly toolConfirmations: string;\n };\n readonly configuration?: AssistantConfiguration;\n}\n\nexport async function createAssistantSession(\n input: CreateAssistantSessionInput,\n dependencies: { readonly fetch?: typeof fetch } = {},\n): Promise<AssistantSession> {\n const request = dependencies.fetch ?? fetch;\n const serviceUrl = input.serviceUrl.replace(/\\/$/, '');\n const credentials = Buffer.from(`${input.clientId}:${input.clientSecret}`, 'utf8').toString(\n 'base64',\n );\n const response = await request(`${serviceUrl}/v1/assistant/sessions`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${credentials}`,\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n origin: input.origin,\n user: input.user,\n ...(input.context ? { context: input.context } : {}),\n }),\n });\n if (!response.ok) throw new Error(`Assistant session exchange failed (${response.status})`);\n return (await response.json()) as AssistantSession;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BA,eAAsB,uBACpB,OACA,eAAkD,CAAC,GACxB;AAC3B,QAAM,UAAU,aAAa,SAAS;AACtC,QAAM,aAAa,MAAM,WAAW,QAAQ,OAAO,EAAE;AACrD,QAAM,cAAc,OAAO,KAAK,GAAG,MAAM,QAAQ,IAAI,MAAM,YAAY,IAAI,MAAM,EAAE;AAAA,IACjF;AAAA,EACF;AACA,QAAM,WAAW,MAAM,QAAQ,GAAG,UAAU,0BAA0B;AAAA,IACpE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,SAAS,WAAW;AAAA,MACnC,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB,QAAQ,MAAM;AAAA,MACd,MAAM,MAAM;AAAA,MACZ,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,IACpD,CAAC;AAAA,EACH,CAAC;AACD,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,sCAAsC,SAAS,MAAM,GAAG;AAC1F,SAAQ,MAAM,SAAS,KAAK;AAC9B;","names":[]}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import type { AssistantConfiguration } from './appearance.js';\n\nexport interface CreateAssistantSessionInput {\n readonly serviceUrl: string;\n readonly clientId: string;\n readonly clientSecret: string;\n /** Browser origin to bind into the short-lived assistant session. */\n readonly origin: string;\n readonly user: {\n readonly id: string;\n readonly email?: string;\n readonly name?: string;\n readonly tenant?: string;\n readonly roles?: readonly string[];\n };\n readonly context?: Readonly<Record<string, string | number | boolean | null>>;\n /**\n * Verified session claims from your authenticated backend. Only claims the server declares in\n * `embeddedAssistant({ sessionClaims })` reach tools (`\\${user.claims.<key>}`) and, when marked\n * `exposeToModel`, the assistant's identity context. Flat scalars only.\n */\n readonly claims?: Readonly<Record<string, string | number | boolean | null>>;\n}\n\nexport interface AssistantSession {\n readonly token: string;\n readonly expiresAt: string;\n readonly endpoints: {\n readonly turns: string;\n readonly toolConfirmations: string;\n };\n readonly configuration?: AssistantConfiguration;\n}\n\nexport async function createAssistantSession(\n input: CreateAssistantSessionInput,\n dependencies: { readonly fetch?: typeof fetch } = {},\n): Promise<AssistantSession> {\n const request = dependencies.fetch ?? fetch;\n const serviceUrl = input.serviceUrl.replace(/\\/$/, '');\n const credentials = Buffer.from(`${input.clientId}:${input.clientSecret}`, 'utf8').toString(\n 'base64',\n );\n const response = await request(`${serviceUrl}/v1/assistant/sessions`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${credentials}`,\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n origin: input.origin,\n user: input.user,\n ...(input.claims ? { claims: input.claims } : {}),\n ...(input.context ? { context: input.context } : {}),\n }),\n });\n if (!response.ok) throw new Error(`Assistant session exchange failed (${response.status})`);\n return (await response.json()) as AssistantSession;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkCA,eAAsB,uBACpB,OACA,eAAkD,CAAC,GACxB;AAC3B,QAAM,UAAU,aAAa,SAAS;AACtC,QAAM,aAAa,MAAM,WAAW,QAAQ,OAAO,EAAE;AACrD,QAAM,cAAc,OAAO,KAAK,GAAG,MAAM,QAAQ,IAAI,MAAM,YAAY,IAAI,MAAM,EAAE;AAAA,IACjF;AAAA,EACF;AACA,QAAM,WAAW,MAAM,QAAQ,GAAG,UAAU,0BAA0B;AAAA,IACpE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,SAAS,WAAW;AAAA,MACnC,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB,QAAQ,MAAM;AAAA,MACd,MAAM,MAAM;AAAA,MACZ,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,MAC/C,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,IACpD,CAAC;AAAA,EACH,CAAC;AACD,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,sCAAsC,SAAS,MAAM,GAAG;AAC1F,SAAQ,MAAM,SAAS,KAAK;AAC9B;","names":[]}
package/dist/server.d.cts CHANGED
@@ -14,6 +14,12 @@ interface CreateAssistantSessionInput {
14
14
  readonly roles?: readonly string[];
15
15
  };
16
16
  readonly context?: Readonly<Record<string, string | number | boolean | null>>;
17
+ /**
18
+ * Verified session claims from your authenticated backend. Only claims the server declares in
19
+ * `embeddedAssistant({ sessionClaims })` reach tools (`\${user.claims.<key>}`) and, when marked
20
+ * `exposeToModel`, the assistant's identity context. Flat scalars only.
21
+ */
22
+ readonly claims?: Readonly<Record<string, string | number | boolean | null>>;
17
23
  }
18
24
  interface AssistantSession {
19
25
  readonly token: string;
package/dist/server.d.ts CHANGED
@@ -14,6 +14,12 @@ interface CreateAssistantSessionInput {
14
14
  readonly roles?: readonly string[];
15
15
  };
16
16
  readonly context?: Readonly<Record<string, string | number | boolean | null>>;
17
+ /**
18
+ * Verified session claims from your authenticated backend. Only claims the server declares in
19
+ * `embeddedAssistant({ sessionClaims })` reach tools (`\${user.claims.<key>}`) and, when marked
20
+ * `exposeToModel`, the assistant's identity context. Flat scalars only.
21
+ */
22
+ readonly claims?: Readonly<Record<string, string | number | boolean | null>>;
17
23
  }
18
24
  interface AssistantSession {
19
25
  readonly token: string;
package/dist/server.js CHANGED
@@ -15,6 +15,7 @@ async function createAssistantSession(input, dependencies = {}) {
15
15
  body: JSON.stringify({
16
16
  origin: input.origin,
17
17
  user: input.user,
18
+ ...input.claims ? { claims: input.claims } : {},
18
19
  ...input.context ? { context: input.context } : {}
19
20
  })
20
21
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import type { AssistantConfiguration } from './appearance.js';\n\nexport interface CreateAssistantSessionInput {\n readonly serviceUrl: string;\n readonly clientId: string;\n readonly clientSecret: string;\n /** Browser origin to bind into the short-lived assistant session. */\n readonly origin: string;\n readonly user: {\n readonly id: string;\n readonly email?: string;\n readonly name?: string;\n readonly tenant?: string;\n readonly roles?: readonly string[];\n };\n readonly context?: Readonly<Record<string, string | number | boolean | null>>;\n}\n\nexport interface AssistantSession {\n readonly token: string;\n readonly expiresAt: string;\n readonly endpoints: {\n readonly turns: string;\n readonly toolConfirmations: string;\n };\n readonly configuration?: AssistantConfiguration;\n}\n\nexport async function createAssistantSession(\n input: CreateAssistantSessionInput,\n dependencies: { readonly fetch?: typeof fetch } = {},\n): Promise<AssistantSession> {\n const request = dependencies.fetch ?? fetch;\n const serviceUrl = input.serviceUrl.replace(/\\/$/, '');\n const credentials = Buffer.from(`${input.clientId}:${input.clientSecret}`, 'utf8').toString(\n 'base64',\n );\n const response = await request(`${serviceUrl}/v1/assistant/sessions`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${credentials}`,\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n origin: input.origin,\n user: input.user,\n ...(input.context ? { context: input.context } : {}),\n }),\n });\n if (!response.ok) throw new Error(`Assistant session exchange failed (${response.status})`);\n return (await response.json()) as AssistantSession;\n}\n"],"mappings":";AA4BA,eAAsB,uBACpB,OACA,eAAkD,CAAC,GACxB;AAC3B,QAAM,UAAU,aAAa,SAAS;AACtC,QAAM,aAAa,MAAM,WAAW,QAAQ,OAAO,EAAE;AACrD,QAAM,cAAc,OAAO,KAAK,GAAG,MAAM,QAAQ,IAAI,MAAM,YAAY,IAAI,MAAM,EAAE;AAAA,IACjF;AAAA,EACF;AACA,QAAM,WAAW,MAAM,QAAQ,GAAG,UAAU,0BAA0B;AAAA,IACpE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,SAAS,WAAW;AAAA,MACnC,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB,QAAQ,MAAM;AAAA,MACd,MAAM,MAAM;AAAA,MACZ,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,IACpD,CAAC;AAAA,EACH,CAAC;AACD,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,sCAAsC,SAAS,MAAM,GAAG;AAC1F,SAAQ,MAAM,SAAS,KAAK;AAC9B;","names":[]}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import type { AssistantConfiguration } from './appearance.js';\n\nexport interface CreateAssistantSessionInput {\n readonly serviceUrl: string;\n readonly clientId: string;\n readonly clientSecret: string;\n /** Browser origin to bind into the short-lived assistant session. */\n readonly origin: string;\n readonly user: {\n readonly id: string;\n readonly email?: string;\n readonly name?: string;\n readonly tenant?: string;\n readonly roles?: readonly string[];\n };\n readonly context?: Readonly<Record<string, string | number | boolean | null>>;\n /**\n * Verified session claims from your authenticated backend. Only claims the server declares in\n * `embeddedAssistant({ sessionClaims })` reach tools (`\\${user.claims.<key>}`) and, when marked\n * `exposeToModel`, the assistant's identity context. Flat scalars only.\n */\n readonly claims?: Readonly<Record<string, string | number | boolean | null>>;\n}\n\nexport interface AssistantSession {\n readonly token: string;\n readonly expiresAt: string;\n readonly endpoints: {\n readonly turns: string;\n readonly toolConfirmations: string;\n };\n readonly configuration?: AssistantConfiguration;\n}\n\nexport async function createAssistantSession(\n input: CreateAssistantSessionInput,\n dependencies: { readonly fetch?: typeof fetch } = {},\n): Promise<AssistantSession> {\n const request = dependencies.fetch ?? fetch;\n const serviceUrl = input.serviceUrl.replace(/\\/$/, '');\n const credentials = Buffer.from(`${input.clientId}:${input.clientSecret}`, 'utf8').toString(\n 'base64',\n );\n const response = await request(`${serviceUrl}/v1/assistant/sessions`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${credentials}`,\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n origin: input.origin,\n user: input.user,\n ...(input.claims ? { claims: input.claims } : {}),\n ...(input.context ? { context: input.context } : {}),\n }),\n });\n if (!response.ok) throw new Error(`Assistant session exchange failed (${response.status})`);\n return (await response.json()) as AssistantSession;\n}\n"],"mappings":";AAkCA,eAAsB,uBACpB,OACA,eAAkD,CAAC,GACxB;AAC3B,QAAM,UAAU,aAAa,SAAS;AACtC,QAAM,aAAa,MAAM,WAAW,QAAQ,OAAO,EAAE;AACrD,QAAM,cAAc,OAAO,KAAK,GAAG,MAAM,QAAQ,IAAI,MAAM,YAAY,IAAI,MAAM,EAAE;AAAA,IACjF;AAAA,EACF;AACA,QAAM,WAAW,MAAM,QAAQ,GAAG,UAAU,0BAA0B;AAAA,IACpE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,SAAS,WAAW;AAAA,MACnC,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB,QAAQ,MAAM;AAAA,MACd,MAAM,MAAM;AAAA,MACZ,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,MAC/C,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,IACpD,CAAC;AAAA,EACH,CAAC;AACD,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,sCAAsC,SAAS,MAAM,GAAG;AAC1F,SAAQ,MAAM,SAAS,KAAK;AAC9B;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodleseed/assistant",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Embed the Noodle Seed customer-branded assistant in your web app: Web Component, React wrapper, and backend session helper. Authoring and deploying the server is @noodleseed/one.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/appearance.ts","../src/transport.ts","../src/element.ts"],"sourcesContent":["export type AssistantThemeMode = 'auto' | 'light' | 'dark';\nexport type AssistantLayoutMode = 'floating' | 'inline' | 'drawer';\nexport type AssistantPosition = 'bottom-left' | 'bottom-right';\n\nexport interface AssistantThemeTokens {\n readonly page: string;\n readonly panel: string;\n readonly elevated: string;\n readonly input: string;\n readonly hover: string;\n readonly selected: string;\n readonly text: string;\n readonly mutedText: string;\n readonly accent: string;\n readonly accentText: string;\n readonly link: string;\n readonly divider: string;\n readonly focus: string;\n readonly success: string;\n readonly warning: string;\n readonly danger: string;\n readonly overlay: string;\n readonly code: string;\n readonly widgetFrame: string;\n readonly fontFamily: string;\n readonly monoFontFamily: string;\n readonly baseFontSize: number;\n readonly messageFontSize: number;\n readonly lineHeight: number;\n readonly panelRadius: number;\n readonly cardRadius: number;\n readonly inputRadius: number;\n readonly buttonRadius: number;\n readonly launcherRadius: number;\n readonly spacing: number;\n readonly shadow: string;\n readonly backdropBlur: number;\n readonly motionScale: number;\n}\n\nexport interface AssistantConfiguration {\n readonly branding?: {\n readonly name?: string;\n readonly accent?: string;\n readonly surface?: string;\n readonly surfaceDark?: string;\n readonly logo?: AssistantBrandAsset;\n readonly mark?: AssistantBrandAsset;\n readonly avatar?: AssistantBrandAsset;\n readonly theme?: {\n readonly light?: BrandThemeOverrides;\n readonly dark?: BrandThemeOverrides;\n };\n readonly radius?: 'none' | 'sm' | 'md' | 'lg';\n readonly density?: 'compact' | 'comfortable';\n readonly typography?: 'system' | 'serif' | 'mono';\n readonly colorScheme?: AssistantThemeMode;\n };\n readonly assistant?: AssistantUiConfiguration;\n}\n\ninterface AssistantBrandAsset {\n readonly uri: string;\n readonly darkUri?: string;\n readonly alt: string;\n}\n\ninterface BrandThemeOverrides {\n readonly surface?: string;\n readonly surfaceRaised?: string;\n readonly surfaceMuted?: string;\n readonly text?: string;\n readonly textMuted?: string;\n readonly accent?: string;\n readonly accentText?: string;\n readonly link?: string;\n readonly border?: string;\n readonly borderStrong?: string;\n readonly focus?: string;\n readonly success?: string;\n readonly warning?: string;\n readonly danger?: string;\n readonly code?: string;\n}\n\ninterface AssistantUiConfiguration {\n readonly layout?: {\n readonly mode?: AssistantLayoutMode;\n readonly position?: AssistantPosition;\n readonly panelWidth?: number;\n readonly panelMinHeight?: number;\n readonly panelMaxHeight?: number;\n readonly zIndex?: number;\n readonly density?: 'compact' | 'comfortable';\n readonly mobileFullscreen?: boolean;\n };\n readonly behavior?: {\n readonly startOpen?: boolean;\n readonly closeOnEscape?: boolean;\n readonly closeOnOutsideClick?: boolean;\n readonly showLauncher?: boolean;\n readonly showHeader?: boolean;\n readonly showAvatars?: boolean;\n readonly showTimestamps?: boolean;\n };\n readonly labels?: Partial<AssistantLabels>;\n readonly suggestedPrompts?: readonly string[];\n readonly privacyUrl?: string;\n readonly termsUrl?: string;\n readonly locale?: string;\n readonly direction?: 'ltr' | 'rtl' | 'auto';\n}\n\nexport interface AssistantLabels {\n readonly welcomeHeading: string;\n readonly welcomeMessage: string;\n readonly composerPlaceholder: string;\n readonly send: string;\n readonly stop: string;\n readonly close: string;\n readonly open: string;\n readonly confirm: string;\n readonly cancel: string;\n readonly retry: string;\n readonly unavailable: string;\n readonly sessionExpired: string;\n}\n\nexport interface ResolvedAssistantAppearance {\n readonly brand: {\n readonly name: string;\n readonly logo: { readonly light?: string; readonly dark?: string };\n readonly avatar: { readonly light?: string; readonly dark?: string };\n readonly mark: { readonly light?: string; readonly dark?: string };\n };\n readonly theme: {\n readonly defaultMode: AssistantThemeMode;\n readonly light: AssistantThemeTokens;\n readonly dark: AssistantThemeTokens;\n };\n readonly layout: {\n readonly mode: AssistantLayoutMode;\n readonly position: AssistantPosition;\n readonly panelWidth: number;\n readonly panelMinHeight: number;\n readonly panelMaxHeight: number;\n readonly zIndex: number;\n readonly density: 'compact' | 'comfortable';\n readonly mobileFullscreen: boolean;\n };\n readonly behavior: {\n readonly startOpen: boolean;\n readonly closeOnEscape: boolean;\n readonly closeOnOutsideClick: boolean;\n readonly showLauncher: boolean;\n readonly showHeader: boolean;\n readonly showAvatars: boolean;\n readonly showTimestamps: boolean;\n };\n readonly labels: AssistantLabels;\n readonly suggestedPrompts: readonly string[];\n readonly privacyUrl?: string;\n readonly termsUrl?: string;\n readonly locale: string;\n readonly direction: 'ltr' | 'rtl' | 'auto';\n}\n\nconst common = {\n fontFamily: 'inherit',\n monoFontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n baseFontSize: 15,\n messageFontSize: 15,\n lineHeight: 1.5,\n panelRadius: 20,\n cardRadius: 14,\n inputRadius: 14,\n buttonRadius: 12,\n launcherRadius: 999,\n spacing: 12,\n backdropBlur: 18,\n motionScale: 1,\n} as const;\n\nexport const DEFAULT_APPEARANCE: ResolvedAssistantAppearance = {\n brand: { name: 'Assistant', logo: {}, avatar: {}, mark: {} },\n theme: {\n defaultMode: 'auto',\n light: {\n ...common,\n page: '#F7F7F8',\n panel: '#FFFFFF',\n elevated: '#FFFFFF',\n input: '#F1F1F3',\n hover: '#ECECEF',\n selected: '#E4E2FF',\n text: '#18181B',\n mutedText: '#71717A',\n accent: '#5B4CF0',\n accentText: '#FFFFFF',\n link: '#4A3BD5',\n divider: '#E4E4E7',\n focus: '#5B4CF0',\n success: '#16835D',\n warning: '#A45B00',\n danger: '#C92A45',\n overlay: '#18181B66',\n code: '#F1F1F3',\n widgetFrame: '#E4E4E7',\n shadow: '0 24px 80px rgba(24, 24, 27, 0.18)',\n },\n dark: {\n ...common,\n page: '#111113',\n panel: '#19191D',\n elevated: '#222228',\n input: '#26262C',\n hover: '#303038',\n selected: '#37315F',\n text: '#FAFAFA',\n mutedText: '#A1A1AA',\n accent: '#A99FFF',\n accentText: '#17131F',\n link: '#B9B1FF',\n divider: '#34343B',\n focus: '#B9B1FF',\n success: '#58C69A',\n warning: '#F2B45F',\n danger: '#FF8094',\n overlay: '#00000099',\n code: '#26262C',\n widgetFrame: '#34343B',\n shadow: '0 24px 90px rgba(0, 0, 0, 0.55)',\n },\n },\n layout: {\n mode: 'floating',\n position: 'bottom-right',\n panelWidth: 400,\n panelMinHeight: 420,\n panelMaxHeight: 720,\n zIndex: 2147483000,\n density: 'comfortable',\n mobileFullscreen: true,\n },\n behavior: {\n startOpen: false,\n closeOnEscape: true,\n closeOnOutsideClick: false,\n showLauncher: true,\n showHeader: true,\n showAvatars: true,\n showTimestamps: false,\n },\n labels: {\n welcomeHeading: 'How can I help?',\n welcomeMessage: '',\n composerPlaceholder: 'Ask a question…',\n send: 'Send',\n stop: 'Stop',\n close: 'Close assistant',\n open: 'Open assistant',\n confirm: 'Confirm',\n cancel: 'Cancel',\n retry: 'Try again',\n unavailable: 'The assistant is temporarily unavailable.',\n sessionExpired: 'Your assistant session expired. Reopen it to continue.',\n },\n suggestedPrompts: [],\n locale: 'en',\n direction: 'auto',\n};\n\nexport function resolveAppearance(input: AssistantConfiguration = {}): ResolvedAssistantAppearance {\n const branding = input.branding;\n const assistant = input.assistant;\n return {\n brand: {\n ...DEFAULT_APPEARANCE.brand,\n ...(branding?.name ? { name: branding.name } : {}),\n logo: themedAsset(branding?.logo),\n avatar: themedAsset(branding?.avatar),\n mark: themedAsset(branding?.mark),\n },\n theme: {\n defaultMode: branding?.colorScheme ?? DEFAULT_APPEARANCE.theme.defaultMode,\n light: resolveTheme('light', branding),\n dark: resolveTheme('dark', branding),\n },\n layout: {\n ...DEFAULT_APPEARANCE.layout,\n ...(branding?.density ? { density: branding.density } : {}),\n ...assistant?.layout,\n },\n behavior: { ...DEFAULT_APPEARANCE.behavior, ...assistant?.behavior },\n labels: { ...DEFAULT_APPEARANCE.labels, ...assistant?.labels },\n suggestedPrompts: assistant?.suggestedPrompts ?? DEFAULT_APPEARANCE.suggestedPrompts,\n ...(assistant?.privacyUrl ? { privacyUrl: assistant.privacyUrl } : {}),\n ...(assistant?.termsUrl ? { termsUrl: assistant.termsUrl } : {}),\n locale: assistant?.locale ?? DEFAULT_APPEARANCE.locale,\n direction: assistant?.direction ?? DEFAULT_APPEARANCE.direction,\n };\n}\n\nfunction themedAsset(asset: AssistantBrandAsset | undefined): {\n readonly light?: string;\n readonly dark?: string;\n} {\n return asset ? { light: asset.uri, dark: asset.darkUri ?? asset.uri } : {};\n}\n\nfunction resolveTheme(\n mode: 'light' | 'dark',\n branding: AssistantConfiguration['branding'],\n): AssistantThemeTokens {\n const defaults = DEFAULT_APPEARANCE.theme[mode];\n const surface = mode === 'light' ? branding?.surface : branding?.surfaceDark;\n const portable = branding?.theme?.[mode];\n const radius = branding?.radius ? radiusValue(branding.radius) : undefined;\n return {\n ...defaults,\n ...(branding?.accent ? { accent: branding.accent } : {}),\n ...(surface ? { page: surface, panel: surface } : {}),\n ...mapPortableTheme(portable),\n ...(radius === undefined\n ? {}\n : {\n panelRadius: radius,\n cardRadius: radius,\n inputRadius: Math.max(0, radius - 2),\n buttonRadius: Math.max(0, radius - 2),\n }),\n ...(branding?.typography === 'serif'\n ? { fontFamily: 'ui-serif, Georgia, serif' }\n : branding?.typography === 'mono'\n ? { fontFamily: defaults.monoFontFamily }\n : {}),\n };\n}\n\nfunction mapPortableTheme(input: BrandThemeOverrides | undefined): Partial<AssistantThemeTokens> {\n if (!input) return {};\n return {\n ...(input.surface ? { page: input.surface, panel: input.surface } : {}),\n ...(input.surfaceRaised ? { elevated: input.surfaceRaised } : {}),\n ...(input.surfaceMuted\n ? { input: input.surfaceMuted, hover: input.surfaceMuted, selected: input.surfaceMuted }\n : {}),\n ...(input.text ? { text: input.text } : {}),\n ...(input.textMuted ? { mutedText: input.textMuted } : {}),\n ...(input.accent ? { accent: input.accent } : {}),\n ...(input.accentText ? { accentText: input.accentText } : {}),\n ...(input.link ? { link: input.link } : {}),\n ...(input.border ? { divider: input.border, widgetFrame: input.border } : {}),\n ...(input.focus ? { focus: input.focus } : {}),\n ...(input.success ? { success: input.success } : {}),\n ...(input.warning ? { warning: input.warning } : {}),\n ...(input.danger ? { danger: input.danger } : {}),\n ...(input.code ? { code: input.code } : {}),\n };\n}\n\nfunction radiusValue(radius: 'none' | 'sm' | 'md' | 'lg'): number {\n if (radius === 'none') return 0;\n if (radius === 'sm') return 8;\n if (radius === 'lg') return 18;\n return 14;\n}\n","export interface AssistantEvent {\n readonly event: string;\n readonly data: Readonly<Record<string, unknown>>;\n}\n\nexport interface AssistantErrorDetail {\n readonly code: string;\n readonly status?: number;\n readonly retryable: boolean;\n}\n\n/**\n * A 2xx response whose body carried no assistant events at all — typically an auth redirect or\n * proxy page returning HTML with a 200. Silently rendering nothing strands the end user, so the\n * transport fails loudly instead (ADR 0151 hardening).\n */\nexport class AssistantTransportError extends Error {\n readonly code = 'invalid_response' as const;\n\n constructor(contentType: string) {\n super(`assistant response was not an event stream (content-type: ${contentType || 'unknown'})`);\n this.name = 'AssistantTransportError';\n }\n}\n\n/** Consume JSON-bearing server-sent events without buffering the whole assistant turn. */\nexport async function consumeAssistantEvents(\n response: Response,\n onEvent: (event: AssistantEvent) => void,\n): Promise<void> {\n let delivered = 0;\n let sawText = false;\n const deliver = (event: AssistantEvent): void => {\n delivered += 1;\n onEvent(event);\n };\n if (!response.body) {\n const text = await response.text();\n sawText = text.trim().length > 0;\n emitFrames(text, deliver, true);\n } else {\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let pending = '';\n while (true) {\n const { done, value } = await reader.read();\n const chunk = decoder.decode(value, { stream: !done });\n if (!sawText && chunk.trim().length > 0) sawText = true;\n pending += chunk;\n pending = emitFrames(pending, deliver, done);\n if (done) break;\n }\n }\n if (delivered === 0 && sawText) {\n throw new AssistantTransportError(response.headers.get('content-type') ?? '');\n }\n}\n\nfunction emitFrames(\n input: string,\n onEvent: (event: AssistantEvent) => void,\n flush: boolean,\n): string {\n const normalized = input.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n');\n const frames = normalized.split('\\n\\n');\n const pending = flush ? '' : (frames.pop() ?? '');\n for (const frame of frames) {\n const event = parseFrame(frame);\n if (event) onEvent(event);\n }\n if (flush && frames.length === 0 && normalized.trim()) {\n const event = parseFrame(normalized);\n if (event) onEvent(event);\n }\n return pending;\n}\n\nfunction parseFrame(frame: string): AssistantEvent | undefined {\n let event = 'message';\n const data: string[] = [];\n for (const line of frame.split('\\n')) {\n if (line.startsWith(':')) continue;\n const separator = line.indexOf(':');\n const field = separator < 0 ? line : line.slice(0, separator);\n const value = separator < 0 ? '' : line.slice(separator + 1).replace(/^ /, '');\n if (field === 'event') event = value;\n if (field === 'data') data.push(value);\n }\n if (data.length === 0) return undefined;\n try {\n return { event, data: JSON.parse(data.join('\\n')) as Readonly<Record<string, unknown>> };\n } catch {\n return undefined;\n }\n}\n","import {\n type AssistantConfiguration,\n type AssistantThemeMode,\n type AssistantThemeTokens,\n resolveAppearance,\n} from './appearance.js';\nimport {\n type AssistantErrorDetail,\n AssistantTransportError,\n consumeAssistantEvents,\n} from './transport.js';\n\nexport const ASSISTANT_TAG_NAME = 'noodle-assistant';\nconst HTMLElementBase: typeof HTMLElement =\n globalThis.HTMLElement ?? (class {} as unknown as typeof HTMLElement);\n\ninterface SessionResponse {\n readonly token: string;\n readonly expiresAt: string;\n readonly endpoints: {\n readonly turns: string;\n readonly toolConfirmations: string;\n };\n readonly configuration?: AssistantConfiguration;\n}\n\nexport class NoodleAssistantElement extends HTMLElementBase {\n static readonly observedAttributes = ['open', 'theme'];\n #appearance = resolveAppearance();\n #session: SessionResponse | undefined;\n #messages: HTMLElement | undefined;\n #media: MediaQueryList | undefined;\n #context: Readonly<Record<string, string | number | boolean | null>> | undefined;\n sessionEndpoint = '';\n\n connectedCallback(): void {\n if (!this.shadowRoot) this.attachShadow({ mode: 'open' });\n if (!this.sessionEndpoint) this.sessionEndpoint = this.getAttribute('session-endpoint') ?? '';\n this.#media = globalThis.matchMedia?.('(prefers-color-scheme: dark)');\n this.#media?.addEventListener('change', this.#handleSystemTheme);\n document.addEventListener('keydown', this.#handleDocumentKeydown);\n document.addEventListener('pointerdown', this.#handleDocumentPointerDown);\n if (this.#appearance.behavior.startOpen) this.setAttribute('open', '');\n this.#render();\n this.dispatchEvent(new CustomEvent('assistant-ready'));\n }\n\n disconnectedCallback(): void {\n this.#media?.removeEventListener('change', this.#handleSystemTheme);\n document.removeEventListener('keydown', this.#handleDocumentKeydown);\n document.removeEventListener('pointerdown', this.#handleDocumentPointerDown);\n }\n\n attributeChangedCallback(name: string): void {\n if (name === 'theme') this.#applyTheme();\n }\n\n open(): void {\n this.setAttribute('open', '');\n this.dispatchEvent(new CustomEvent('assistant-open'));\n }\n\n close(): void {\n this.removeAttribute('open');\n this.dispatchEvent(new CustomEvent('assistant-close'));\n }\n\n toggle(): void {\n this.hasAttribute('open') ? this.close() : this.open();\n }\n\n focusComposer(): void {\n this.shadowRoot?.querySelector<HTMLTextAreaElement>('textarea')?.focus();\n }\n\n resetSession(): void {\n this.#session = undefined;\n this.#messages?.replaceChildren();\n this.dispatchEvent(new CustomEvent('assistant-session-reset'));\n }\n\n updateContext(context: Readonly<Record<string, string | number | boolean | null>>): void {\n this.#context = { ...context };\n this.dispatchEvent(new CustomEvent('assistant-context-changed', { detail: { context } }));\n }\n\n async sendMessage(text: string): Promise<void> {\n const message = text.trim();\n if (!message) return;\n if (!this.#session) this.#session = await this.#createSession();\n this.#appendMessage('user', message);\n this.dispatchEvent(new CustomEvent('assistant-message-started'));\n await this.#sendTurn(message, true);\n }\n\n async #sendTurn(message: string, mayRetry: boolean): Promise<void> {\n if (!this.#session) this.#session = await this.#createSession();\n const response = await fetch(this.#session.endpoints.turns, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.#session.token}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({ message }),\n });\n if (response.status === 401 && mayRetry) {\n this.#session = undefined;\n this.dispatchEvent(new CustomEvent('assistant-session-expired'));\n await this.#sendTurn(message, false);\n return;\n }\n if (!response.ok) {\n this.#dispatchError({ code: 'turn_failed', status: response.status, retryable: false });\n throw new Error(`Assistant turn failed (${response.status})`);\n }\n let assistantBody: HTMLElement | undefined;\n try {\n await consumeAssistantEvents(response, (event) => {\n if (event.event === 'content') {\n const body = assistantBody ?? this.#appendMessage('assistant', '');\n assistantBody = body;\n if (body) body.textContent += String(event.data.delta ?? '');\n }\n if (event.event === 'tool_proposed') {\n this.#appendToolProposal(\n String(event.data.id ?? ''),\n String(event.data.tool ?? 'Action'),\n );\n }\n if (event.event === 'error') {\n this.#dispatchError({\n code: String(event.data.code ?? 'stream_failed'),\n retryable: event.data.retryable === true,\n });\n }\n });\n } catch (error) {\n if (error instanceof AssistantTransportError) {\n this.#dispatchError({ code: error.code, retryable: false });\n }\n throw error;\n }\n this.dispatchEvent(new CustomEvent('assistant-message-completed'));\n }\n\n /**\n * Every listener the element attaches to its own DOM must go through this guard: internal UI\n * failures surface as `assistant-error` events (already dispatched by the failing path) and must\n * never escape as unhandled rejections into the embedding page. Programmatic callers use\n * `sendMessage`/`confirmTool` directly and keep the rejection.\n */\n #sendGuarded(text: string): void {\n void this.sendMessage(text).catch(() => {});\n }\n\n async confirmTool(id: string): Promise<void> {\n if (!this.#session) {\n this.#dispatchError({ code: 'confirmation_expired', retryable: false });\n throw new Error('assistant session is not active');\n }\n const response = await fetch(this.#session.endpoints.toolConfirmations, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.#session.token}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({ id }),\n });\n if (!response.ok) {\n const expired = response.status === 401 || response.status === 409;\n if (response.status === 401) {\n this.#session = undefined;\n this.dispatchEvent(new CustomEvent('assistant-session-expired'));\n }\n this.#dispatchError({\n code: expired ? 'confirmation_expired' : 'confirmation_failed',\n status: response.status,\n retryable: false,\n });\n throw new Error(`Assistant confirmation failed (${response.status})`);\n }\n let completed: Readonly<Record<string, unknown>> | undefined;\n await consumeAssistantEvents(response, (event) => {\n if (event.event === 'tool_completed') completed = event.data;\n });\n if (completed) this.#appendMessage('assistant', JSON.stringify(completed.result ?? {}));\n this.dispatchEvent(new CustomEvent('assistant-tool-completed', { detail: { id } }));\n }\n\n #handleSystemTheme = (): void => this.#applyTheme();\n\n #handleDocumentKeydown = (event: KeyboardEvent): void => {\n if (\n event.key === 'Escape' &&\n this.hasAttribute('open') &&\n this.#appearance.behavior.closeOnEscape\n ) {\n this.close();\n }\n };\n\n #handleDocumentPointerDown = (event: PointerEvent): void => {\n if (\n this.hasAttribute('open') &&\n this.#appearance.behavior.closeOnOutsideClick &&\n !event.composedPath().includes(this)\n ) {\n this.close();\n }\n };\n\n async #createSession(): Promise<SessionResponse> {\n if (!this.sessionEndpoint) throw new Error('sessionEndpoint is required');\n let response: Response;\n try {\n response = await fetch(this.sessionEndpoint, {\n method: 'POST',\n headers: { Accept: 'application/json', 'Content-Type': 'application/json' },\n body: JSON.stringify(this.#context ? { context: this.#context } : {}),\n credentials: 'same-origin',\n });\n } catch (error) {\n this.#dispatchError({ code: 'session_failed', retryable: true });\n throw error;\n }\n if (!response.ok) {\n this.#dispatchError({ code: 'session_failed', status: response.status, retryable: true });\n throw new Error(`Assistant session failed (${response.status})`);\n }\n let session: SessionResponse;\n try {\n session = (await response.json()) as SessionResponse;\n } catch (error) {\n this.#dispatchError({ code: 'session_failed', retryable: true });\n throw error;\n }\n if (session.configuration) {\n this.#appearance = resolveAppearance(session.configuration);\n this.#render();\n }\n this.dispatchEvent(\n new CustomEvent('assistant-session-started', { detail: { expiresAt: session.expiresAt } }),\n );\n return session;\n }\n\n #appendMessage(role: 'user' | 'assistant', text: string): HTMLElement | undefined {\n if (!this.#messages) return undefined;\n const message = document.createElement('div');\n message.className = `message ${role}`;\n if (\n role === 'assistant' &&\n this.#appearance.behavior.showAvatars &&\n this.#appearance.brand.avatar[this.#resolvedMode()]\n ) {\n const avatar = document.createElement('img');\n avatar.className = 'avatar';\n avatar.src = this.#appearance.brand.avatar[this.#resolvedMode()] ?? '';\n avatar.alt = '';\n message.append(avatar);\n }\n const body = document.createElement('span');\n body.textContent = text;\n message.append(body);\n if (this.#appearance.behavior.showTimestamps) {\n const timestamp = document.createElement('time');\n timestamp.dateTime = new Date().toISOString();\n timestamp.textContent = new Intl.DateTimeFormat(this.#appearance.locale, {\n hour: 'numeric',\n minute: '2-digit',\n }).format(new Date());\n message.append(timestamp);\n }\n this.#messages.append(message);\n return body;\n }\n\n #dispatchError(detail: AssistantErrorDetail): void {\n this.dispatchEvent(new CustomEvent('assistant-error', { detail }));\n }\n\n #appendToolProposal(id: string, tool: string): void {\n if (!this.#messages || !id) return;\n const card = document.createElement('section');\n card.className = 'tool-proposal';\n const label = document.createElement('strong');\n label.textContent = tool;\n const confirm = document.createElement('button');\n confirm.type = 'button';\n confirm.textContent = this.#appearance.labels.confirm;\n confirm.addEventListener('click', () => {\n confirm.disabled = true;\n void this.confirmTool(id).catch(() => {\n confirm.disabled = false;\n this.dispatchEvent(\n new CustomEvent('assistant-error', { detail: { code: 'confirmation_failed' } }),\n );\n });\n });\n const cancel = document.createElement('button');\n cancel.type = 'button';\n cancel.textContent = this.#appearance.labels.cancel;\n cancel.addEventListener('click', () => card.remove());\n card.append(label, confirm, cancel);\n this.#messages.append(card);\n this.dispatchEvent(new CustomEvent('assistant-tool-proposed', { detail: { id, tool } }));\n }\n\n #resolvedMode(): Exclude<AssistantThemeMode, 'auto'> {\n const configured =\n (this.getAttribute('theme') as AssistantThemeMode | null) ??\n this.#appearance.theme.defaultMode;\n return configured === 'auto' ? (this.#media?.matches ? 'dark' : 'light') : configured;\n }\n\n #applyTheme(): void {\n const mode = this.#resolvedMode();\n this.setAttribute('data-theme', mode);\n const tokens = this.#appearance.theme[mode];\n for (const [name, value] of Object.entries(tokens)) {\n this.style.setProperty(\n `--ns-assistant-default-${camelToKebab(name)}`,\n tokenValue(name, value),\n );\n }\n this.style.setProperty(\n '--ns-assistant-default-panel-width',\n `${this.#appearance.layout.panelWidth}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-min-height',\n `${this.#appearance.layout.panelMinHeight}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-max-height',\n `${this.#appearance.layout.panelMaxHeight}px`,\n );\n this.style.setProperty(\n '--ns-assistant-default-z-index',\n String(this.#appearance.layout.zIndex),\n );\n const logo = this.shadowRoot?.querySelector<HTMLImageElement>('.brand-logo');\n const logoUrl = this.#appearance.brand.logo[mode];\n if (logo) {\n logo.hidden = !logoUrl;\n if (logoUrl) logo.src = logoUrl;\n }\n }\n\n #render(): void {\n if (!this.shadowRoot) return;\n const appearance = this.#appearance;\n this.setAttribute('role', 'complementary');\n this.setAttribute('aria-label', appearance.brand.name);\n this.setAttribute('lang', appearance.locale);\n this.setAttribute('dir', appearance.direction);\n this.dataset.mode = appearance.layout.mode;\n this.dataset.position = appearance.layout.position;\n this.dataset.density = appearance.layout.density;\n this.toggleAttribute('mobile-fullscreen', appearance.layout.mobileFullscreen);\n this.shadowRoot.innerHTML = `${styles}\n <button class=\"launcher\" type=\"button\" aria-label=\"${escapeAttribute(appearance.labels.open)}\"><slot name=\"launcher-icon\">✦</slot></button>\n <section class=\"panel\" aria-label=\"${escapeAttribute(appearance.brand.name)}\">\n <header><slot name=\"header-leading\"></slot><img class=\"brand-logo\" alt=\"\"><strong></strong><slot name=\"header-actions\"></slot><button class=\"close\" type=\"button\" aria-label=\"${escapeAttribute(appearance.labels.close)}\">×</button></header>\n <div class=\"welcome\"><slot name=\"empty-state\"><h2></h2><p></p></slot></div>\n <div class=\"suggested-prompts\"></div>\n <div class=\"messages\" aria-live=\"polite\"></div>\n <form><slot name=\"composer-leading\"></slot><textarea rows=\"1\"></textarea><button class=\"send\" type=\"submit\"></button><slot name=\"composer-trailing\"></slot></form>\n <nav class=\"legal\" aria-label=\"Legal\"></nav>\n <slot name=\"conversation-footer\"></slot>\n </section>`;\n queryRequired<HTMLElement>(this.shadowRoot, 'strong').textContent = appearance.brand.name;\n const launcherIcon = appearance.brand.mark[this.#resolvedMode()];\n if (launcherIcon) {\n const launcherSlot = queryRequired<HTMLSlotElement>(\n this.shadowRoot,\n 'slot[name=\"launcher-icon\"]',\n );\n const icon = document.createElement('img');\n icon.src = launcherIcon;\n icon.alt = '';\n launcherSlot.replaceChildren(icon);\n }\n const logo = queryRequired<HTMLImageElement>(this.shadowRoot, '.brand-logo');\n const logoUrl = appearance.brand.logo[this.#resolvedMode()];\n if (logoUrl) {\n logo.src = logoUrl;\n logo.alt = appearance.brand.name;\n } else {\n logo.hidden = true;\n }\n queryRequired<HTMLElement>(this.shadowRoot, 'h2').textContent =\n appearance.labels.welcomeHeading;\n queryRequired<HTMLElement>(this.shadowRoot, 'p').textContent = appearance.labels.welcomeMessage;\n const textarea = queryRequired<HTMLTextAreaElement>(this.shadowRoot, 'textarea');\n textarea.placeholder = appearance.labels.composerPlaceholder;\n textarea.setAttribute('aria-label', appearance.labels.composerPlaceholder);\n queryRequired<HTMLElement>(this.shadowRoot, '.send').textContent = appearance.labels.send;\n const prompts = queryRequired<HTMLElement>(this.shadowRoot, '.suggested-prompts');\n for (const prompt of appearance.suggestedPrompts) {\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = prompt;\n button.addEventListener('click', () => this.#sendGuarded(prompt));\n prompts.append(button);\n }\n if (!appearance.behavior.showLauncher)\n queryRequired<HTMLElement>(this.shadowRoot, '.launcher').hidden = true;\n if (!appearance.behavior.showHeader)\n queryRequired<HTMLElement>(this.shadowRoot, 'header').hidden = true;\n const legal = queryRequired<HTMLElement>(this.shadowRoot, '.legal');\n for (const [label, href] of [\n ['Privacy', appearance.privacyUrl],\n ['Terms', appearance.termsUrl],\n ] as const) {\n if (!href) continue;\n const link = document.createElement('a');\n link.href = href;\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.textContent = label;\n legal.append(link);\n }\n this.#messages = this.shadowRoot.querySelector('.messages') ?? undefined;\n this.shadowRoot.querySelector('.launcher')?.addEventListener('click', () => this.open());\n this.shadowRoot.querySelector('.close')?.addEventListener('click', () => this.close());\n this.shadowRoot.querySelector('form')?.addEventListener('submit', (event) => {\n event.preventDefault();\n const value = textarea.value;\n textarea.value = '';\n this.#sendGuarded(value);\n });\n this.#applyTheme();\n }\n}\n\nexport function registerNoodleAssistant(): void {\n if (globalThis.customElements && !customElements.get(ASSISTANT_TAG_NAME)) {\n customElements.define(ASSISTANT_TAG_NAME, NoodleAssistantElement);\n }\n}\n\nfunction camelToKebab(value: string): string {\n return value.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n}\n\nfunction tokenValue(name: string, value: AssistantThemeTokens[keyof AssistantThemeTokens]): string {\n if (typeof value !== 'number') return value;\n if (name === 'lineHeight' || name === 'motionScale') return String(value);\n return `${value}px`;\n}\n\nfunction escapeAttribute(value: string): string {\n return value.replaceAll('&', '&amp;').replaceAll('\"', '&quot;').replaceAll('<', '&lt;');\n}\n\nfunction queryRequired<T extends Element>(root: ShadowRoot, selector: string): T {\n const element = root.querySelector<T>(selector);\n if (!element) throw new Error(`assistant renderer is missing ${selector}`);\n return element;\n}\n\nconst styles = `<style>\n :host { color-scheme: light dark; font-family: var(--ns-assistant-font-family, var(--ns-assistant-default-font-family)); font-size: var(--ns-assistant-base-font-size, var(--ns-assistant-default-base-font-size)); line-height: var(--ns-assistant-line-height, var(--ns-assistant-default-line-height)); z-index: var(--ns-assistant-z-index, var(--ns-assistant-default-z-index)); }\n :host([data-mode=\"floating\"]) { position: fixed; bottom: 24px; right: 24px; }\n :host([data-mode=\"floating\"][data-position=\"bottom-left\"]) { right: auto; left: 24px; }\n .launcher { width: 54px; height: 54px; border: 0; border-radius: var(--ns-assistant-launcher-radius, var(--ns-assistant-default-launcher-radius)); color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); cursor: pointer; }\n .launcher img { width: 24px; height: 24px; object-fit: contain; }\n .panel { display: none; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 32px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 32px)); overflow: hidden; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); }\n :host([open]) .panel { display: grid; grid-template-rows: auto auto 1fr auto; }\n :host([open]) .launcher { display: none; }\n header { display: flex; gap: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); align-items: center; padding: calc(var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)) * 1.2); border-bottom: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); }\n header strong { flex: 1; }\n .brand-logo { display: block; max-width: 120px; max-height: 28px; object-fit: contain; }\n button { font: inherit; }\n .close, .send { border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); cursor: pointer; }\n .close { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; font-size: 24px; }\n .welcome { padding: calc(var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)) * 1.5); }\n .welcome h2 { margin: 0; font-size: 1.25em; }\n .welcome p { margin: 6px 0 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }\n .suggested-prompts { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); }\n .suggested-prompts:empty { display: none; }\n .suggested-prompts button { padding: 7px 10px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: transparent; border: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: 999px; cursor: pointer; }\n .messages { min-height: 120px; padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); overflow: auto; }\n .message { width: fit-content; max-width: 84%; margin: 8px 0; padding: 10px 12px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); white-space: pre-wrap; }\n .message .avatar { float: left; width: 24px; height: 24px; margin-right: 8px; border-radius: 50%; object-fit: cover; }\n .message time { display: block; margin-top: 4px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .75em; }\n .message.user { margin-left: auto; color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n .tool-proposal { display: grid; grid-template-columns: 1fr auto auto; gap: 8px; align-items: center; margin: 10px 0; padding: 12px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); }\n .tool-proposal button { padding: 8px 10px; border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); cursor: pointer; }\n .tool-proposal button:first-of-type { color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n form { display: flex; gap: 8px; align-items: end; padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); border-top: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); }\n textarea { flex: 1; resize: none; padding: 10px 12px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); border: 0; border-radius: var(--ns-assistant-input-radius, var(--ns-assistant-default-input-radius)); font: inherit; }\n textarea:focus-visible, button:focus-visible { outline: 3px solid var(--ns-assistant-focus, var(--ns-assistant-default-focus)); outline-offset: 2px; }\n .send { padding: 10px 14px; color: var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text)); background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }\n .legal { display: flex; gap: 12px; justify-content: center; padding: 0 12px 10px; font-size: .8em; }\n .legal:empty { display: none; }\n .legal a { color: var(--ns-assistant-link, var(--ns-assistant-default-link)); }\n :host([data-density=\"compact\"]) .welcome { padding: var(--ns-assistant-spacing, var(--ns-assistant-default-spacing)); }\n @media (max-width: 640px) { :host([mobile-fullscreen][open]) { inset: 0; } :host([mobile-fullscreen][open]) .panel { width: 100vw; min-height: 100vh; max-height: 100vh; border-radius: 0; } }\n @media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; } }\n @media (max-width: 560px) { :host([data-mode=\"floating\"]) { inset: auto 12px 12px; } :host([open]) .panel { width: calc(100vw - 24px); max-height: calc(100vh - 24px); } }\n</style>`;\n"],"mappings":"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","names":[]}