@meshmakers/shared-ui 3.4.1490 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/assets/octobot/lg/octo_blink.webp +0 -0
- package/assets/octobot/lg/octo_blink_still.png +0 -0
- package/assets/octobot/lg/octo_idle.webp +0 -0
- package/assets/octobot/lg/octo_idle_still.png +0 -0
- package/assets/octobot/lg/octo_look.webp +0 -0
- package/assets/octobot/lg/octo_look_still.png +0 -0
- package/assets/octobot/lg/octo_swim.webp +0 -0
- package/assets/octobot/lg/octo_swim_still.png +0 -0
- package/assets/octobot/lg/octo_thinking.webp +0 -0
- package/assets/octobot/lg/octo_thinking_still.png +0 -0
- package/assets/octobot/lg/octo_wave.webp +0 -0
- package/assets/octobot/lg/octo_wave_still.png +0 -0
- package/assets/octobot/md/octo_blink.webp +0 -0
- package/assets/octobot/md/octo_blink_still.png +0 -0
- package/assets/octobot/md/octo_idle.webp +0 -0
- package/assets/octobot/md/octo_idle_still.png +0 -0
- package/assets/octobot/md/octo_look.webp +0 -0
- package/assets/octobot/md/octo_look_still.png +0 -0
- package/assets/octobot/md/octo_swim.webp +0 -0
- package/assets/octobot/md/octo_swim_still.png +0 -0
- package/assets/octobot/md/octo_thinking.webp +0 -0
- package/assets/octobot/md/octo_thinking_still.png +0 -0
- package/assets/octobot/md/octo_wave.webp +0 -0
- package/assets/octobot/md/octo_wave_still.png +0 -0
- package/assets/octobot/sm/octo_blink.webp +0 -0
- package/assets/octobot/sm/octo_blink_still.png +0 -0
- package/assets/octobot/sm/octo_idle.webp +0 -0
- package/assets/octobot/sm/octo_idle_still.png +0 -0
- package/assets/octobot/sm/octo_look.webp +0 -0
- package/assets/octobot/sm/octo_look_still.png +0 -0
- package/assets/octobot/sm/octo_swim.webp +0 -0
- package/assets/octobot/sm/octo_swim_still.png +0 -0
- package/assets/octobot/sm/octo_thinking.webp +0 -0
- package/assets/octobot/sm/octo_thinking_still.png +0 -0
- package/assets/octobot/sm/octo_wave.webp +0 -0
- package/assets/octobot/sm/octo_wave_still.png +0 -0
- package/fesm2022/meshmakers-shared-ui-assistant-core.mjs +2 -0
- package/fesm2022/meshmakers-shared-ui-assistant-core.mjs.map +1 -1
- package/fesm2022/meshmakers-shared-ui-assistant.mjs +28 -5
- package/fesm2022/meshmakers-shared-ui-assistant.mjs.map +1 -1
- package/fesm2022/meshmakers-shared-ui.mjs +402 -21
- package/fesm2022/meshmakers-shared-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/meshmakers-shared-ui-assistant-core.d.ts +4 -0
- package/types/meshmakers-shared-ui-assistant.d.ts +11 -0
- package/types/meshmakers-shared-ui.d.ts +270 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meshmakers-shared-ui-assistant.mjs","sources":["../../../../projects/meshmakers/shared-ui/assistant/src/assistant-markdown.ts","../../../../projects/meshmakers/shared-ui/assistant/src/composer/assistant-composer.component.ts","../../../../projects/meshmakers/shared-ui/assistant/src/composer/assistant-composer.component.html","../../../../projects/meshmakers/shared-ui/assistant/src/proposal-card/assistant-proposal-card.component.ts","../../../../projects/meshmakers/shared-ui/assistant/src/proposal-card/assistant-proposal-card.component.html","../../../../projects/meshmakers/shared-ui/assistant/src/thread/assistant-thread.component.ts","../../../../projects/meshmakers/shared-ui/assistant/src/thread/assistant-thread.component.html","../../../../projects/meshmakers/shared-ui/assistant/src/panel/assistant-panel.component.ts","../../../../projects/meshmakers/shared-ui/assistant/src/panel/assistant-panel.component.html","../../../../projects/meshmakers/shared-ui/assistant/src/public-api.ts","../../../../projects/meshmakers/shared-ui/assistant/src/meshmakers-shared-ui-assistant.ts"],"sourcesContent":["import { Pipe, PipeTransform } from '@angular/core';\nimport { Marked, Tokens } from 'marked';\n\n/** Protocols an assistant link may use; everything else (javascript:, data:, vbscript: …) renders as text. */\nconst SAFE_PROTOCOLS = new Set(['http:', 'https:', 'mailto:']);\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/** Classifies a link target: external (http/https/mailto), relative (same origin) or unsafe. */\nexport function classifyAssistantHref(href: string | null | undefined): 'external' | 'relative' | 'unsafe' {\n const value = (href ?? '').trim();\n if (!value) {\n return 'unsafe';\n }\n // Strip control characters and whitespace browsers ignore inside a scheme (\"java\\nscript:\").\n // eslint-disable-next-line no-control-regex\n const compact = value.replace(/[\\u0000- \\u007f]/g, '');\n const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(compact);\n if (scheme) {\n return SAFE_PROTOCOLS.has(`${scheme[1].toLowerCase()}:`) ? 'external' : 'unsafe';\n }\n // Protocol-relative URLs leave the origin. Browsers treat a backslash like \"/\" in http(s)\n // URLs, so \"/\\evil.example\" and \"\\\\evil.example\" leave it as well.\n if (compact.replace(/\\\\/g, '/').startsWith('//')) {\n return 'unsafe';\n }\n return 'relative';\n}\n\nfunction safeLink(href: string, labelHtml: string, title?: string | null): string {\n const kind = classifyAssistantHref(href);\n if (kind === 'unsafe') {\n return labelHtml;\n }\n const titleAttr = title ? ` title=\"${escapeHtml(title)}\"` : '';\n const external = kind === 'external' ? ' target=\"_blank\" rel=\"noopener noreferrer\"' : '';\n return `<a href=\"${escapeHtml(href.trim())}\"${titleAttr}${external}>${labelHtml}</a>`;\n}\n\n/**\n * Markdown renderer for assistant turns. Model output is untrusted, so:\n * raw HTML is shown as text, images never load (they become their alt text,\n * linked when the source is a safe URL), links only keep http(s)/mailto and\n * relative targets — external ones open in a new tab with\n * `rel=\"noopener noreferrer\"` — and anything else renders as its label.\n * The result is bound with `[innerHTML]`, so Angular's sanitizer runs as a\n * second layer.\n */\nconst assistantMarked = new Marked({\n async: false,\n gfm: true,\n renderer: {\n html({ text }: Tokens.HTML | Tokens.Tag): string {\n return escapeHtml(text);\n },\n link(token: Tokens.Link): string {\n return safeLink(token.href, this.parser.parseInline(token.tokens), token.title);\n },\n image({ href, text }: Tokens.Image): string {\n const label = escapeHtml(text || 'image');\n return classifyAssistantHref(href) === 'unsafe' ? label : safeLink(href, label);\n }\n }\n});\n\n/** Renders untrusted assistant markdown to HTML with the rules above. */\nexport function renderAssistantMarkdown(markdown: string): string {\n return assistantMarked.parse(markdown ?? '', { async: false });\n}\n\n/** `{{ text | assistantMarkdown }}` for `[innerHTML]` bindings. */\n@Pipe({ name: 'assistantMarkdown' })\nexport class AssistantMarkdownPipe implements PipeTransform {\n transform(markdown: string): string {\n return renderAssistantMarkdown(markdown);\n }\n}\n","import { ChangeDetectionStrategy, Component, ElementRef, computed, inject, input, model, output, signal, viewChild } from '@angular/core';\nimport {\n ASSISTANT_SLASH_COMMANDS,\n AssistantAttachmentOptions,\n AssistantSlashCommand,\n AssistantMessages,\n assistantMessages,\n formatAssistantMessage,\n selectAssistantAttachments\n} from '@meshmakers/shared-ui/assistant-core';\nimport { SVGIconComponent } from '@progress/kendo-angular-icons';\nimport { paperclipIcon, xIcon } from '@progress/kendo-svg-icons';\n\nlet nextComposerId = 0;\n\n/**\n * Composer (ui-concept §5.3): multi-line, Enter sends, Shift+Enter is a newline,\n * typing `/` at the start lists the slash commands (`ASSISTANT_SLASH_COMMANDS`, by default\n * `/explain`, `/query`, `/summarise`, `/draft-pipeline`). The suggestion list follows the combobox\n * pattern: focus stays in the textarea, ↑/↓ move, Enter/Tab pick, Esc closes the\n * list (and only then lets Esc reach the panel).\n *\n * With {@link attachments} set (the transport accepts files, AB#5621) an \"Attach file\" button opens\n * a file picker limited to `accept`; files are checked against `maxFiles` / `maxFileSizeBytes`,\n * rejected ones are announced in an alert, attached ones are listed with a remove button, and a\n * message may then be sent without text. Without it there is no attachment UI.\n */\n@Component({\n selector: 'mm-assistant-composer',\n imports: [SVGIconComponent],\n templateUrl: './assistant-composer.component.html',\n styleUrl: './assistant-composer.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AssistantComposerComponent {\n /** The composer text (two-way). */\n readonly text = model('');\n /** Whether Enter may send; false while the transport is not ready. */\n readonly canSend = input(false);\n /** A turn is running: the send button becomes a stop button. */\n readonly sending = input(false);\n\n /** Accepted attachments; `null` (default) = no attachment UI. */\n readonly attachments = input<AssistantAttachmentOptions | null>(null);\n /** The attached files (two-way); sent with the next message by the host. */\n readonly files = model<readonly File[]>([]);\n\n readonly send = output<string>();\n readonly stop = output<void>();\n /** Translations; members left out fall back to {@link ASSISTANT_MESSAGES}, then English. */\n readonly messages = input<Partial<AssistantMessages> | null>(null);\n protected readonly m = assistantMessages(this.messages);\n\n private readonly textarea = viewChild.required<ElementRef<HTMLTextAreaElement>>('input');\n private readonly fileInput = viewChild<ElementRef<HTMLInputElement>>('fileInput');\n\n /** Messages about rejected files of the last pick. */\n protected readonly attachmentErrors = signal<readonly string[]>([]);\n /** Something to send: text, or (with attachments) at least one file. */\n protected readonly hasContent = computed(() => this.text().trim().length > 0 || (!!this.attachments() && this.files().length > 0));\n protected readonly multiple = computed(() => (this.attachments()?.maxFiles ?? 1) > 1);\n protected readonly xIcon = xIcon;\n protected readonly paperclipIcon = paperclipIcon;\n protected readonly commands: readonly AssistantSlashCommand[] = inject(ASSISTANT_SLASH_COMMANDS);\n\n protected readonly listId = `assistant-slash-${nextComposerId++}`;\n protected readonly activeIndex = signal(0);\n private readonly dismissedFor = signal<string | null>(null);\n\n /** Slash commands matching what was typed, while the text is a bare `/word`. */\n protected readonly suggestions = computed<readonly AssistantSlashCommand[]>(() => {\n const text = this.text();\n if (!/^\\/[\\w-]*$/.test(text) || this.dismissedFor() === text) {\n return [];\n }\n return this.commands.filter(command => command.command.startsWith(text.toLowerCase()));\n });\n\n protected readonly activeOptionId = computed(() =>\n this.suggestions().length ? `${this.listId}-${Math.min(this.activeIndex(), this.suggestions().length - 1)}` : null);\n\n /** Focuses the textarea with the caret at the end (entry points prefill it). */\n focus(): void {\n const element = this.textarea().nativeElement;\n element.focus();\n element.setSelectionRange(element.value.length, element.value.length);\n }\n\n protected onInput(value: string): void {\n this.text.set(value);\n this.activeIndex.set(0);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (event.isComposing) {\n return;\n }\n const suggestions = this.suggestions();\n if (suggestions.length) {\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.activeIndex.update(index => (index + 1) % suggestions.length);\n return;\n case 'ArrowUp':\n event.preventDefault();\n this.activeIndex.update(index => (index - 1 + suggestions.length) % suggestions.length);\n return;\n case 'Enter':\n case 'Tab':\n if (!event.shiftKey) {\n event.preventDefault();\n this.pick(suggestions[Math.min(this.activeIndex(), suggestions.length - 1)]);\n return;\n }\n break;\n case 'Escape':\n event.preventDefault();\n event.stopPropagation();\n this.dismissedFor.set(this.text());\n return;\n }\n }\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n this.submit();\n }\n }\n\n protected pick(command: AssistantSlashCommand): void {\n this.text.set(`${command.command} `);\n this.activeIndex.set(0);\n this.focus();\n }\n\n protected submit(): void {\n if (this.canSend() && this.hasContent()) {\n this.attachmentErrors.set([]);\n this.send.emit(this.text());\n }\n }\n\n protected openFilePicker(): void {\n this.fileInput()?.nativeElement.click();\n }\n\n protected onFilesPicked(input: HTMLInputElement): void {\n const options = this.attachments();\n const picked = Array.from(input.files ?? []);\n // Reset so picking the same file again fires `change`.\n input.value = '';\n if (!options || !picked.length) {\n return;\n }\n const selection = selectAssistantAttachments(this.files(), picked, options, this.m());\n this.files.set(selection.files);\n this.attachmentErrors.set(selection.errors);\n }\n\n protected removeFile(index: number): void {\n this.files.update(files => files.filter((_, i) => i !== index));\n this.attachmentErrors.set([]);\n this.focus();\n }\n\n protected format(message: string, values: Record<string, string>): string {\n return formatAssistantMessage(message, values);\n }\n}\n","<div class=\"composer\">\n @if (suggestions().length) {\n <ul class=\"suggestions\" role=\"listbox\" [id]=\"listId\" [attr.aria-label]=\"m().commandsLabel\">\n @for (command of suggestions(); track command.command; let i = $index) {\n <li role=\"option\" [id]=\"listId + '-' + i\" [attr.aria-selected]=\"activeOptionId() === listId + '-' + i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"pick(command)\">\n <span class=\"cmd\">{{ command.command }}</span>\n <span class=\"cmd-desc\">{{ command.description }}</span>\n </li>\n }\n </ul>\n }\n @if (attachments(); as options) {\n @if (files().length) {\n <ul class=\"files\" [attr.aria-label]=\"m().attachmentsLabel\">\n @for (file of files(); track $index; let i = $index) {\n <li class=\"file\">\n <span class=\"file-name\" [title]=\"file.name\">{{ file.name }}</span>\n <button type=\"button\" [attr.aria-label]=\"format(m().removeAttachment, { name: file.name })\" [title]=\"format(m().removeAttachment, { name: file.name })\" (click)=\"removeFile(i)\"><kendo-svg-icon [icon]=\"xIcon\" size=\"small\"></kendo-svg-icon></button>\n </li>\n }\n </ul>\n }\n @if (attachmentErrors().length) {\n <div class=\"file-errors\" role=\"alert\">\n @for (error of attachmentErrors(); track $index) {\n <p>{{ error }}</p>\n }\n </div>\n }\n <input #fileInput class=\"file-input\" type=\"file\" tabindex=\"-1\" aria-hidden=\"true\"\n [attr.accept]=\"options.accept || null\" [multiple]=\"multiple()\"\n (change)=\"onFilesPicked($any($event.target))\">\n }\n <div class=\"box\">\n @if (attachments()) {\n <button type=\"button\" class=\"attach\" [attr.aria-label]=\"m().attachFile\" [title]=\"m().attachFile\" (click)=\"openFilePicker()\">\n <kendo-svg-icon [icon]=\"paperclipIcon\"></kendo-svg-icon>\n </button>\n }\n <textarea #input\n rows=\"2\"\n [attr.aria-label]=\"m().composerLabel\"\n [placeholder]=\"m().composerPlaceholder\"\n aria-autocomplete=\"list\"\n [attr.aria-controls]=\"suggestions().length ? listId : null\"\n [attr.aria-expanded]=\"suggestions().length > 0\"\n [attr.aria-activedescendant]=\"activeOptionId()\"\n [value]=\"text()\"\n (input)=\"onInput($any($event.target).value)\"\n (keydown)=\"onKeydown($event)\"></textarea>\n @if (sending()) {\n <button type=\"button\" class=\"send\" (click)=\"stop.emit()\">{{ m().stop }}</button>\n } @else {\n <button type=\"button\" class=\"send\" [disabled]=\"!canSend() || !hasContent()\" (click)=\"submit()\">{{ m().send }}</button>\n }\n </div>\n <div class=\"hint\" aria-hidden=\"true\">\n @for (command of commands; track command.command) {\n <kbd>{{ command.command }}</kbd>\n }\n </div>\n</div>\n","import { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';\nimport { AssistantProposal, AssistantProposalDecisionKind, AssistantMessages, assistantMessages, formatAssistantMessage, proposalDecisionLabel } from '@meshmakers/shared-ui/assistant-core';\n\n/**\n * A write the assistant proposes (ui-concept §5.3/§5.6, wireframe screen 6):\n * violet card with a parameter table and Run / Edit / Discard. The buttons only\n * emit — the card never executes anything; the host forwards the decision.\n */\n@Component({\n selector: 'mm-assistant-proposal-card',\n templateUrl: './assistant-proposal-card.component.html',\n styleUrl: './assistant-proposal-card.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AssistantProposalCardComponent {\n readonly proposal = input.required<AssistantProposal>();\n /** Set once the person ran or discarded the proposal; disables the buttons. */\n readonly decision = input<AssistantProposalDecisionKind | null>(null);\n\n readonly run = output<AssistantProposal>();\n readonly edit = output<AssistantProposal>();\n readonly discard = output<AssistantProposal>();\n /** Translations; members left out fall back to {@link ASSISTANT_MESSAGES}, then English. */\n readonly messages = input<Partial<AssistantMessages> | null>(null);\n protected readonly m = assistantMessages(this.messages);\n protected readonly cardLabel = computed(() => formatAssistantMessage(this.m().proposalLabel, { title: this.proposal().title }));\n\n protected readonly decisionLabel = computed(() => {\n const decision = this.decision();\n return decision ? proposalDecisionLabel(decision, this.m()) : null;\n });\n}\n","<article class=\"proposal\" [class.settled]=\"decision() !== null\" [attr.aria-label]=\"cardLabel()\">\n <header class=\"proposal-head\">\n <span aria-hidden=\"true\">✦</span> {{ m().proposal }}@if (proposal().writes) { · {{ m().writesToTenant }} }\n </header>\n <div class=\"proposal-body\">\n <p class=\"proposal-title\">{{ proposal().title }}</p>\n @if (proposal().description) {\n <p class=\"proposal-description\">{{ proposal().description }}</p>\n }\n @if (proposal().parameters.length) {\n <dl class=\"proposal-params\">\n @for (param of proposal().parameters; track param.name) {\n <dt>{{ param.name }}</dt>\n <dd>{{ param.value }}</dd>\n }\n </dl>\n }\n <p class=\"proposal-meta\">{{ m().tool }} <span class=\"mono\">{{ proposal().toolName }}</span> · {{ m().runsAfterConfirm }}</p>\n </div>\n <footer class=\"proposal-foot\">\n @if (decisionLabel(); as label) {\n <span class=\"proposal-decision\" role=\"status\">{{ label }}</span>\n } @else {\n <button type=\"button\" class=\"btn primary\" (click)=\"run.emit(proposal())\">{{ m().run }}</button>\n <button type=\"button\" class=\"btn\" (click)=\"edit.emit(proposal())\">{{ m().edit }}</button>\n <button type=\"button\" class=\"btn\" (click)=\"discard.emit(proposal())\">{{ m().discard }}</button>\n }\n </footer>\n</article>\n","import { ChangeDetectionStrategy, Component, ElementRef, computed, effect, inject, input, output } from '@angular/core';\nimport { NgComponentOutlet } from '@angular/common';\nimport { AssistantMarkdownPipe } from '../assistant-markdown';\nimport { AssistantProposalCardComponent } from '../proposal-card/assistant-proposal-card.component';\nimport { ASSISTANT_TOOL_CALL_COMPONENT, AssistantProposalDecision, AssistantThreadItem, AssistantMessages, assistantMessages } from '@meshmakers/shared-ui/assistant-core';\n\n/**\n * The conversation (wireframe screen 6): user turns, assistant turns (markdown\n * via `renderAssistantMarkdown`: no images, safe links only; violet edge), tool-call rows and proposal cards. Tool calls\n * render with the `ASSISTANT_TOOL_CALL_COMPONENT` (an OctoMesh host passes `mm-ai-tool-call` from\n * `@meshmakers/octo-ai-console`, ui-concept §5.1 \"do not rebuild\"); proposals are emitted, never executed.\n *\n * A user turn sent through a slash command's `expand` (AB#5621) shows the expanded prompt with the\n * typed command (`slashCommand`) as a small label above it.\n *\n * The list is an `aria-live` log; it is `aria-busy` while a turn streams so a\n * screen reader announces finished messages instead of every token. Nothing\n * inside it carries its own live role, so each addition is announced once.\n */\n@Component({\n selector: 'mm-assistant-thread',\n imports: [NgComponentOutlet, AssistantMarkdownPipe, AssistantProposalCardComponent],\n templateUrl: './assistant-thread.component.html',\n styleUrl: './assistant-thread.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AssistantThreadComponent {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n readonly items = input<AssistantThreadItem[]>([]);\n readonly proposalDecision = output<AssistantProposalDecision>();\n /** Translations; members left out fall back to {@link ASSISTANT_MESSAGES}, then English. */\n readonly messages = input<Partial<AssistantMessages> | null>(null);\n protected readonly m = assistantMessages(this.messages);\n protected readonly toolCallComponent = inject(ASSISTANT_TOOL_CALL_COMPONENT);\n\n protected readonly streaming = computed(() => this.items().some(item => item.kind === 'assistant' && item.streaming));\n\n constructor() {\n // Keep the newest turn in view.\n effect(() => {\n this.items();\n queueMicrotask(() => {\n const element = this.host.nativeElement;\n element.scrollTop = element.scrollHeight;\n });\n });\n }\n}\n","<ol class=\"thread\" role=\"log\" aria-live=\"polite\" aria-relevant=\"additions text\" [attr.aria-label]=\"m().conversationLabel\"\n [attr.aria-busy]=\"streaming()\">\n @for (item of items(); track item.id) {\n @switch (item.kind) {\n @case ('user') {\n <li class=\"msg user\"><span class=\"sr-only\">{{ m().youPrefix }}</span>@if (item.slashCommand) {<span class=\"slash-command\"><span class=\"sr-only\">{{ m().slashCommandPrefix }}</span>{{ item.slashCommand }}</span>}{{ item.text }}@if (item.attachments?.length) {<ul class=\"attachments\" [attr.aria-label]=\"m().attachmentsLabel\">@for (file of item.attachments; track $index) {<li class=\"attachment\">{{ file.name }}</li>}</ul>}</li>\n }\n @case ('assistant') {\n <li class=\"msg bot\">\n <span class=\"sr-only\">{{ m().assistantPrefix }}</span>\n <div class=\"md\" [innerHTML]=\"item.markdown | assistantMarkdown\"></div>\n @if (item.streaming) {\n <span class=\"streaming\" aria-hidden=\"true\">●</span>\n }\n </li>\n }\n @case ('tool-call') {\n <li class=\"msg tool\"><ng-container *ngComponentOutlet=\"toolCallComponent; inputs: { call: item.call }\"></ng-container></li>\n }\n @case ('proposal') {\n <li class=\"msg\">\n <mm-assistant-proposal-card\n [messages]=\"messages()\"\n [proposal]=\"item.proposal\"\n [decision]=\"item.decision\"\n (run)=\"proposalDecision.emit({ kind: 'run', proposal: $event })\"\n (edit)=\"proposalDecision.emit({ kind: 'edit', proposal: $event })\"\n (discard)=\"proposalDecision.emit({ kind: 'discard', proposal: $event })\">\n </mm-assistant-proposal-card>\n </li>\n }\n @case ('error') {\n <li class=\"msg error\"><span class=\"sr-only\">{{ m().errorPrefix }}</span>{{ item.text }}</li>\n }\n }\n }\n</ol>\n","import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, Injector, afterNextRender, computed, effect, inject, input, signal, untracked, viewChild } from '@angular/core';\nimport {\n ASSISTANT_PANEL_OPTIONS,\n AssistantMessages,\n AssistantPanelMode,\n AssistantProposalDecision,\n AssistantService,\n AssistantSessionSummary,\n DEFAULT_ASSISTANT_PANEL_MAX_WIDTH,\n DEFAULT_ASSISTANT_PANEL_MIN_WIDTH,\n DEFAULT_ASSISTANT_PANEL_STORAGE_KEY,\n assistantMessages,\n formatAssistantMessage\n} from '@meshmakers/shared-ui/assistant-core';\nimport { SVGIconComponent } from '@progress/kendo-angular-icons';\nimport { clockArrowRotateIcon, plusIcon, trashIcon, xIcon } from '@progress/kendo-svg-icons';\nimport { AssistantComposerComponent } from '../composer/assistant-composer.component';\nimport { AssistantThreadComponent } from '../thread/assistant-thread.component';\n\n/** Width of the panel before anyone resized it (CSS: 400 px, 340 px ≤ 1180 px), used until measured. */\nconst FALLBACK_WIDTH = 400;\n/** Window width the handle always leaves to the content. */\nconst MIN_CONTENT_WIDTH = 240;\n/** Keyboard step of the resize handle in px (Shift: four times). */\nconst RESIZE_STEP = 16;\n\n/** The persisted width, or null when absent, invalid or storage is unavailable. */\nfunction readStoredWidth(key: string | null): number | null {\n if (!key) {\n return null;\n }\n try {\n const raw = globalThis.localStorage?.getItem(key);\n const width = raw === null || raw === undefined ? NaN : Number(raw);\n return Number.isFinite(width) && width > 0 ? width : null;\n } catch {\n return null;\n }\n}\n\n/** Best effort: storage may be missing, full or blocked. */\nfunction writeStoredWidth(key: string | null, width: number | null): void {\n if (!key) {\n return;\n }\n try {\n if (width === null) {\n globalThis.localStorage?.removeItem(key);\n } else {\n globalThis.localStorage?.setItem(key, String(Math.round(width)));\n }\n } catch {\n // Persistence is best effort.\n }\n}\n\n/**\n * Right-side assistant panel (ui-concept §5.3, wireframe screen 6): header,\n * removable context chips, thread, composer. Non-modal: the page stays usable.\n * Opening focuses the composer, Esc closes and focus returns to where it was\n * (AssistantService). Below 640 px it covers the screen under the top bar and\n * becomes a modal dialog (`aria-modal`, Tab trapped) so the page behind is out\n * of reach. Removing a context chip moves focus to the next chip, else the composer.\n *\n * Host it only while {@link AssistantService.enabled} is set and the panel is open\n * (`@if (assistant.enabled && assistant.isOpen()) { <mm-assistant-panel /> }`); the thread\n * lives in the service, so closing and navigating keep it.\n *\n * Optional transport capabilities (AB#5621) add UI only when the transport has them:\n * - **sessions** — \"New chat\" and \"Chats\" in the header; the chat list replaces the thread\n * (open a chat, delete with an inline confirmation; Esc returns to the chat);\n * - **starter questions** — shown as buttons on an empty thread; clicking one sends it;\n * - **attachments** — the composer's \"Attach file\" button (see `mm-assistant-composer`).\n *\n * Header actions (\"New chat\", \"Chats\", close) are icon buttons with tooltip and `aria-label` from\n * the messages, so they never wrap in a narrow panel (AB#5621).\n *\n * **Layout (AB#5621)** — inputs, else {@link ASSISTANT_PANEL_OPTIONS}, else the defaults:\n * - `resizable` (default `false`, so no handle and no extra tab stop; opt in per input or token):\n * a handle on the left edge (`role=\"separator\"`) changes the width by dragging or with ←/→\n * (Shift: bigger steps), Home/End (min/max); a double click forgets the chosen width. The width\n * stays within `minWidth`..`maxWidth` (320..720 px, and at least 240 px of the window stay free)\n * and is kept in `localStorage` under `storageKey` (`mm-assistant-panel-width`; `null` = not\n * kept). Without `resizable`, or until someone resizes it, the panel keeps its CSS width (400 px,\n * 340 px ≤ 1180 px). Unavailable storage only means the width is not kept.\n * - `mode`: `docked` (default, pushes the content) or `overlay` (floats over it, `position: fixed`\n * at the right edge below `--mm-assistant-overlay-top`, default 48 px; stacking via\n * `--mm-assistant-overlay-z-index`, default 20).\n * On phones neither applies: the panel is the full-screen dialog.\n */\n@Component({\n selector: 'mm-assistant-panel',\n imports: [AssistantThreadComponent, AssistantComposerComponent, SVGIconComponent],\n templateUrl: './assistant-panel.component.html',\n styleUrl: './assistant-panel.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[attr.role]': 'isPhone() ? \"dialog\" : \"complementary\"',\n '[attr.aria-modal]': 'isPhone() ? \"true\" : null',\n 'aria-labelledby': 'assistant-panel-title',\n id: 'assistant-panel',\n '[class.mm-assistant-overlay]': 'overlay()',\n '[class.mm-assistant-resizing]': 'resizing()',\n '[attr.data-mode]': 'effectiveMode()',\n '[style.width.px]': 'isPhone() ? null : appliedWidth()',\n '(keydown.escape)': 'onEscape($event)',\n '(keydown.tab)': 'onTab($event)',\n '(keydown.shift.tab)': 'onTab($event)'\n }\n})\nexport class AssistantPanelComponent {\n protected readonly assistant = inject(AssistantService);\n private readonly injector = inject(Injector);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly composer = viewChild(AssistantComposerComponent);\n\n /** Translations; members left out fall back to {@link ASSISTANT_MESSAGES}, then English. */\n readonly messages = input<Partial<AssistantMessages> | null>(null);\n protected readonly m = assistantMessages(this.messages);\n\n /** `docked` pushes the content, `overlay` floats over it (default: options token, else `docked`). */\n readonly mode = input<AssistantPanelMode | null>(null);\n /** Shows the resize handle (default: options token, else `false`). */\n readonly resizable = input<boolean | null>(null);\n /** Smallest width in px of the resize handle (default: options token, else 320). */\n readonly minWidth = input<number | null>(null);\n /** Largest width in px of the resize handle (default: options token, else 720). */\n readonly maxWidth = input<number | null>(null);\n /**\n * `localStorage` key of the chosen width; `null` = not kept. Left out (`undefined`): options\n * token, else `mm-assistant-panel-width`.\n */\n readonly storageKey = input<string | null | undefined>(undefined);\n\n protected readonly xIcon = xIcon;\n protected readonly plusIcon = plusIcon;\n protected readonly historyIcon = clockArrowRotateIcon;\n protected readonly trashIcon = trashIcon;\n\n private readonly options = inject(ASSISTANT_PANEL_OPTIONS, { optional: true });\n\n protected readonly effectiveMode = computed<AssistantPanelMode>(() => this.mode() ?? this.options?.mode ?? 'docked');\n protected readonly overlay = computed(() => this.effectiveMode() === 'overlay' && !this.isPhone());\n private readonly effectiveStorageKey = computed(() => {\n const key = this.storageKey();\n if (key !== undefined) {\n return key;\n }\n return this.options?.storageKey !== undefined ? this.options.storageKey : DEFAULT_ASSISTANT_PANEL_STORAGE_KEY;\n });\n protected readonly effectiveMin = computed(() =>\n Math.max(0, Math.round(this.minWidth() ?? this.options?.minWidth ?? DEFAULT_ASSISTANT_PANEL_MIN_WIDTH)));\n protected readonly effectiveMax = computed(() => {\n const configured = this.maxWidth() ?? this.options?.maxWidth ?? DEFAULT_ASSISTANT_PANEL_MAX_WIDTH;\n const viewport = typeof window !== 'undefined' && window.innerWidth > 0 ? window.innerWidth - MIN_CONTENT_WIDTH : Infinity;\n return Math.round(Math.max(this.effectiveMin(), Math.min(configured, viewport)));\n });\n /** The handle is shown (never on phones). */\n protected readonly canResize = computed(() => (this.resizable() ?? this.options?.resizable ?? false) && !this.isPhone());\n\n /** Width chosen in this panel instance; `undefined` = not touched yet (stored width applies). */\n private readonly chosenWidth = signal<number | null | undefined>(undefined);\n private readonly storedWidth = computed(() => readStoredWidth(this.effectiveStorageKey()));\n /** The inline width in px, or null for the CSS default. */\n protected readonly appliedWidth = computed(() => {\n const chosen = this.chosenWidth();\n const width = chosen === undefined ? this.storedWidth() : chosen;\n return width === null || !this.canResize() ? null : this.clampWidth(width);\n });\n /** CSS width as rendered, for `aria-valuenow` before the first resize. */\n private readonly measuredWidth = signal(FALLBACK_WIDTH);\n protected readonly currentWidth = computed(() => this.appliedWidth() ?? this.clampWidth(this.measuredWidth()));\n protected readonly resizing = signal(false);\n private stopDrag: (() => void) | null = null;\n\n /** Phone layout (≤ 640 px, the shell's breakpoint): the panel is a modal dialog. */\n protected readonly isPhone = signal(false);\n\n protected readonly connected = computed(() => this.assistant.transportStatus() !== 'unavailable');\n\n /** `chat` = thread + composer; `sessions` = the saved chats list (session-capable transports only). */\n protected readonly view = signal<'chat' | 'sessions'>('chat');\n /** Session whose deletion waits for confirmation. */\n protected readonly confirmingDelete = signal<string | null>(null);\n /** Session being opened or deleted (its buttons are disabled meanwhile). */\n protected readonly busySession = signal<string | null>(null);\n\n /** Starter questions on an empty thread (transports with `starterQuestions` only). */\n protected readonly showStarters = computed(() =>\n this.view() === 'chat' && this.assistant.thread().length === 0 && this.assistant.starterQuestions().length > 0);\n\n constructor() {\n const query = typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia('(max-width: 640px)')\n : null;\n if (query) {\n this.isPhone.set(query.matches);\n const listener = (event: MediaQueryListEvent): void => this.isPhone.set(event.matches);\n query.addEventListener('change', listener);\n inject(DestroyRef).onDestroy(() => query.removeEventListener('change', listener));\n }\n\n this.assistant.loadStarterQuestions();\n\n afterNextRender(() => this.measure());\n inject(DestroyRef).onDestroy(() => this.stopDrag?.());\n\n // Every entry point bumps focusRequest; the composer gets focus once rendered.\n effect(() => {\n this.assistant.focusRequest();\n untracked(() => {\n this.view.set('chat');\n this.focusComposer();\n });\n });\n }\n\n /** Pointer drag on the handle: the panel sits on the right, so moving left widens it. */\n protected startResize(event: PointerEvent): void {\n if (event.button !== 0 || !this.canResize()) {\n return;\n }\n event.preventDefault();\n this.stopDrag?.();\n const startX = event.clientX;\n const startWidth = this.currentWidth();\n const move = (moveEvent: PointerEvent): void => this.setWidth(startWidth + startX - moveEvent.clientX, false);\n const end = (): void => {\n this.stopDrag?.();\n const width = this.chosenWidth();\n if (width !== undefined) {\n writeStoredWidth(this.effectiveStorageKey(), width);\n }\n };\n document.addEventListener('pointermove', move);\n document.addEventListener('pointerup', end);\n document.addEventListener('pointercancel', end);\n this.resizing.set(true);\n this.stopDrag = () => {\n document.removeEventListener('pointermove', move);\n document.removeEventListener('pointerup', end);\n document.removeEventListener('pointercancel', end);\n this.resizing.set(false);\n this.stopDrag = null;\n };\n }\n\n /** ←/→ resize (Shift: ×4), Home/End jump to min/max; the width is kept right away. */\n protected onResizeKey(event: KeyboardEvent): void {\n const step = event.shiftKey ? RESIZE_STEP * 4 : RESIZE_STEP;\n let width: number;\n switch (event.key) {\n case 'ArrowLeft': width = this.currentWidth() + step; break;\n case 'ArrowRight': width = this.currentWidth() - step; break;\n case 'Home': width = this.effectiveMin(); break;\n case 'End': width = this.effectiveMax(); break;\n default: return;\n }\n event.preventDefault();\n this.setWidth(width, true);\n }\n\n /** Double click on the handle: back to the default width, forgetting the kept one. */\n protected resetWidth(): void {\n this.chosenWidth.set(null);\n writeStoredWidth(this.effectiveStorageKey(), null);\n afterNextRender(() => this.measure(), { injector: this.injector });\n }\n\n private setWidth(width: number, persist: boolean): void {\n const clamped = this.clampWidth(width);\n this.chosenWidth.set(clamped);\n if (persist) {\n writeStoredWidth(this.effectiveStorageKey(), clamped);\n }\n }\n\n private clampWidth(width: number): number {\n return Math.round(Math.min(this.effectiveMax(), Math.max(this.effectiveMin(), width)));\n }\n\n private measure(): void {\n const width = this.host.nativeElement.getBoundingClientRect().width;\n if (width > 0) {\n this.measuredWidth.set(width);\n }\n }\n\n protected onEscape(event: Event): void {\n if (event.defaultPrevented) {\n return;\n }\n event.preventDefault();\n if (this.confirmingDelete()) {\n this.cancelDelete();\n } else if (this.view() === 'sessions') {\n this.backToChat();\n } else {\n this.assistant.close();\n }\n }\n\n /** Shows the saved chats and reloads them. */\n protected showSessions(): void {\n this.confirmingDelete.set(null);\n this.view.set('sessions');\n void this.assistant.refreshSessions();\n this.focusSessionList();\n }\n\n protected backToChat(): void {\n this.confirmingDelete.set(null);\n this.view.set('chat');\n this.focusComposer();\n }\n\n protected newChat(): void {\n this.assistant.newThread();\n this.backToChat();\n }\n\n protected async openSession(session: AssistantSessionSummary): Promise<void> {\n this.busySession.set(session.id);\n try {\n await this.assistant.openSession(session.id);\n } finally {\n this.busySession.set(null);\n }\n this.backToChat();\n }\n\n protected askDelete(session: AssistantSessionSummary): void {\n this.confirmingDelete.set(session.id);\n afterNextRender(() => this.host.nativeElement.querySelector<HTMLElement>('.session-confirm .confirm-delete')?.focus(),\n { injector: this.injector });\n }\n\n protected cancelDelete(): void {\n const id = this.confirmingDelete();\n this.confirmingDelete.set(null);\n afterNextRender(() => Array.from(this.host.nativeElement.querySelectorAll<HTMLElement>('.session-row'))\n .find(row => row.dataset['sessionId'] === id)?.querySelector<HTMLElement>('.session-delete')?.focus(),\n { injector: this.injector });\n }\n\n protected async confirmDelete(session: AssistantSessionSummary): Promise<void> {\n this.busySession.set(session.id);\n let deleted: boolean;\n try {\n deleted = await this.assistant.deleteSession(session.id);\n } finally {\n this.busySession.set(null);\n this.confirmingDelete.set(null);\n }\n if (deleted) {\n await this.assistant.refreshSessions();\n this.focusSessionList();\n } else {\n // The error row lives in the thread.\n this.backToChat();\n }\n }\n\n protected sendStarter(question: string): void {\n this.assistant.send(question);\n }\n\n /** Locale date + time of a session, or '' when absent or unparsable. */\n protected sessionDate(session: AssistantSessionSummary): string {\n if (!session.createdAt) {\n return '';\n }\n const date = new Date(session.createdAt);\n return Number.isNaN(date.getTime()) ? '' : date.toLocaleString(undefined, { dateStyle: 'short', timeStyle: 'short' });\n }\n\n /** First chat of the list, else the back button. */\n private focusSessionList(): void {\n afterNextRender(() => {\n const root = this.host.nativeElement;\n (root.querySelector<HTMLElement>('.session-open') ?? root.querySelector<HTMLElement>('.back'))?.focus();\n }, { injector: this.injector });\n }\n\n private focusComposer(): void {\n afterNextRender(() => this.composer()?.focus(), { injector: this.injector });\n }\n\n /** Phone dialog: Tab and Shift+Tab cycle inside the panel. */\n protected onTab(event: Event): void {\n if (!this.isPhone() || event.defaultPrevented) {\n return;\n }\n const focusable = Array.from(this.host.nativeElement.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), textarea:not([disabled]), input:not([disabled]), a[href], [tabindex]:not([tabindex=\"-1\"])'));\n if (!focusable.length) {\n return;\n }\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const active = document.activeElement;\n const backwards = (event as KeyboardEvent).shiftKey;\n if (backwards && (active === first || !this.host.nativeElement.contains(active))) {\n event.preventDefault();\n last.focus();\n } else if (!backwards && (active === last || !this.host.nativeElement.contains(active))) {\n event.preventDefault();\n first.focus();\n }\n }\n\n /** Drops a chip and keeps keyboard users in the row: next chip, else the composer. */\n protected removeChip(id: string, index: number): void {\n this.assistant.removeChip(id);\n afterNextRender(() => {\n const buttons = this.host.nativeElement.querySelectorAll<HTMLButtonElement>('.ctx-chip button');\n const next = buttons[Math.min(index, buttons.length - 1)];\n if (next) {\n next.focus();\n } else {\n this.composer()?.focus();\n }\n }, { injector: this.injector });\n }\n\n protected format(message: string, values: Record<string, string>): string {\n return formatAssistantMessage(message, values);\n }\n\n protected onDecision(decision: AssistantProposalDecision): void {\n this.assistant.decideProposal(decision.kind, decision.proposal);\n }\n}\n","@if (canResize()) {\n <div class=\"resize-handle\" role=\"separator\" tabindex=\"0\" aria-orientation=\"vertical\" aria-controls=\"assistant-panel\"\n [attr.aria-label]=\"m().resizePanel\" [title]=\"m().resizePanel\"\n [attr.aria-valuenow]=\"currentWidth()\" [attr.aria-valuemin]=\"effectiveMin()\" [attr.aria-valuemax]=\"effectiveMax()\"\n (pointerdown)=\"startResize($event)\" (keydown)=\"onResizeKey($event)\" (dblclick)=\"resetWidth()\"></div>\n}\n\n<header class=\"head\">\n <span class=\"sparkle\" aria-hidden=\"true\">✦</span>\n <h2 class=\"title\" id=\"assistant-panel-title\">{{ m().title }}</h2>\n @if (connected()) {\n <span class=\"chip-neutral\" [title]=\"m().readsWithYourPermissions\">{{ m().readsWithYourPermissions }}</span>\n }\n @if (assistant.sessionsSupported) {\n <div class=\"head-actions\">\n <button type=\"button\" class=\"icon-btn new-chat\" [attr.aria-label]=\"m().newChat\" [title]=\"m().newChat\" (click)=\"newChat()\">\n <kendo-svg-icon [icon]=\"plusIcon\"></kendo-svg-icon>\n </button>\n <button type=\"button\" class=\"icon-btn sessions-toggle\" aria-controls=\"assistant-sessions\"\n [attr.aria-label]=\"m().sessions\" [title]=\"m().sessions\"\n [attr.aria-expanded]=\"view() === 'sessions'\"\n (click)=\"view() === 'sessions' ? backToChat() : showSessions()\">\n <kendo-svg-icon [icon]=\"historyIcon\"></kendo-svg-icon>\n </button>\n </div>\n }\n <button type=\"button\" class=\"icon-btn close\" [attr.aria-label]=\"m().closeAssistant\" [title]=\"m().closeAssistant\" (click)=\"assistant.close()\">\n <kendo-svg-icon [icon]=\"xIcon\"></kendo-svg-icon>\n </button>\n</header>\n\n@if (assistant.contextChips().length) {\n <ul class=\"ctx\" [attr.aria-label]=\"m().contextLabel\">\n @for (chip of assistant.contextChips(); track chip.id; let i = $index) {\n <li class=\"ctx-chip\" [attr.data-kind]=\"chip.kind\" [title]=\"chip.value\">\n <span class=\"ctx-label\">{{ chip.label }}</span>\n <button type=\"button\" [attr.aria-label]=\"format(m().removeContext, { label: chip.label })\" [title]=\"format(m().removeContext, { label: chip.label })\" (click)=\"removeChip(chip.id, i)\"><kendo-svg-icon [icon]=\"xIcon\" size=\"small\"></kendo-svg-icon></button>\n </li>\n }\n </ul>\n}\n\n@if (view() === 'sessions') {\n <section class=\"sessions\" id=\"assistant-sessions\" [attr.aria-label]=\"m().sessionsLabel\">\n <button type=\"button\" class=\"text-btn back\" (click)=\"backToChat()\">← {{ m().backToChat }}</button>\n <ul class=\"session-list\">\n @for (session of assistant.sessions(); track session.id) {\n <li class=\"session-row\" [attr.data-session-id]=\"session.id\"\n [class.active]=\"session.id === assistant.activeSessionId()\">\n @if (confirmingDelete() === session.id) {\n <div class=\"session-confirm\" role=\"group\" [attr.aria-label]=\"format(m().deleteSessionConfirm, { title: session.title })\">\n <span class=\"confirm-text\">{{ format(m().deleteSessionConfirm, { title: session.title }) }}</span>\n <button type=\"button\" class=\"text-btn danger confirm-delete\" [disabled]=\"busySession() === session.id\"\n (click)=\"confirmDelete(session)\">{{ m().delete }}</button>\n <button type=\"button\" class=\"text-btn cancel-delete\" (click)=\"cancelDelete()\">{{ m().cancel }}</button>\n </div>\n } @else {\n <button type=\"button\" class=\"session-open\" [title]=\"session.title\"\n [attr.aria-current]=\"session.id === assistant.activeSessionId() ? 'true' : null\"\n [disabled]=\"busySession() === session.id\"\n (click)=\"openSession(session)\">\n <span class=\"session-title\">{{ session.title }}</span>\n @if (sessionDate(session); as date) {\n <span class=\"session-date\">{{ date }}</span>\n }\n </button>\n @if (assistant.sessionDeleteSupported) {\n <button type=\"button\" class=\"icon-btn session-delete\"\n [attr.aria-label]=\"format(m().deleteSession, { title: session.title })\"\n [title]=\"format(m().deleteSession, { title: session.title })\"\n [disabled]=\"busySession() === session.id\"\n (click)=\"askDelete(session)\">\n <kendo-svg-icon [icon]=\"trashIcon\" size=\"small\"></kendo-svg-icon>\n </button>\n }\n }\n </li>\n } @empty {\n <li class=\"session-empty\">{{ m().noSessions }}</li>\n }\n </ul>\n </section>\n} @else {\n @if (showStarters()) {\n <section class=\"starters\" aria-labelledby=\"assistant-starters-title\">\n <h3 class=\"starters-title\" id=\"assistant-starters-title\">{{ m().startersTitle }}</h3>\n <ul class=\"starter-list\">\n @for (question of assistant.starterQuestions(); track $index) {\n <li><button type=\"button\" class=\"starter\" [disabled]=\"!assistant.canSend()\" (click)=\"sendStarter(question)\">{{ question }}</button></li>\n }\n </ul>\n </section>\n }\n\n <mm-assistant-thread class=\"thread\" [items]=\"assistant.thread()\" [messages]=\"messages()\" (proposalDecision)=\"onDecision($event)\"></mm-assistant-thread>\n\n @if (!connected() || assistant.transportStatus() === 'error') {\n <div class=\"unavailable\" role=\"status\">\n <span class=\"sparkle\" aria-hidden=\"true\">✦</span>\n <p>{{ assistant.transportMessage() ?? m().notAvailable }}</p>\n </div>\n }\n\n <mm-assistant-composer\n [messages]=\"messages()\"\n [text]=\"assistant.draft()\"\n (textChange)=\"assistant.setDraft($event)\"\n [attachments]=\"assistant.attachments\"\n [files]=\"assistant.draftFiles()\"\n (filesChange)=\"assistant.setDraftFiles($event)\"\n [canSend]=\"assistant.canSend()\"\n [sending]=\"assistant.sending()\"\n (send)=\"assistant.send($event)\"\n (stop)=\"assistant.stop()\">\n </mm-assistant-composer>\n}\n","/*\n * Public API Surface of @meshmakers/shared-ui/assistant (AB#5621)\n */\n\n/**\n * The assistant side panel of the OctoMesh Refinery Studio as an app-agnostic building block:\n * panel (header, removable context chips, thread, composer with slash commands), proposal cards,\n * \"✦ Explain\" directives and the {@link AssistantService} state. It never answers by itself —\n * turns come from an {@link AssistantTransport} the host provides.\n *\n * Usage:\n *\n * ```ts\n * import { AssistantPanelComponent, AssistantService, ASSISTANT_ENABLED, ASSISTANT_TRANSPORT,\n * assistantHotkey } from '@meshmakers/shared-ui/assistant';\n *\n * // app.config.ts — off by default; without a transport the panel says \"backend not available\"\n * providers: [\n * { provide: ASSISTANT_ENABLED, useValue: true },\n * { provide: ASSISTANT_TRANSPORT, useExisting: MyChatTransport },\n * ]\n *\n * // AppComponent\n * template: `@if (assistant.enabled && assistant.isOpen()) { <mm-assistant-panel /> }`\n * @HostListener('document:keydown', ['$event'])\n * onKeydown(event: KeyboardEvent): void {\n * if (this.assistant.enabled && assistantHotkey(event)) { event.preventDefault(); this.assistant.toggle(); }\n * }\n * ```\n *\n * Wire the top bar toggle of `@meshmakers/shared-ui/shell` with\n * `[assistantAvailable]=\"assistant.enabled\" [assistantOpen]=\"assistant.isOpen()\" (assistantToggle)=\"assistant.toggle()\"`.\n * Proposal decisions (Run / Edit / Discard) are only published on `AssistantService.proposalDecisions$`.\n *\n * Tokens:\n * - `ASSISTANT_ENABLED` (default `false`) — the single feature flag;\n * - `ASSISTANT_TRANSPORT` (default {@link NotConnectedAssistantTransport}) — where turns come from;\n * - `ASSISTANT_PAGE_CONTEXT` (optional) — area/tab labels for the page chip;\n * - `ASSISTANT_TOOL_CALL_COMPONENT` (default {@link AssistantToolCallRowComponent}) — tool-call renderer\n * (OctoMesh hosts: `AiToolCallComponent` of `@meshmakers/octo-ai-console`);\n * - `ASSISTANT_SLASH_COMMANDS` (default {@link DEFAULT_ASSISTANT_SLASH_COMMANDS}) — composer commands; a\n * command with `expand(command, args)` is sent (and shown) as the prompt it returns (AB#5621);\n * - `ASSISTANT_PANEL_OPTIONS` (optional) — panel layout: `mode` (`docked` | `overlay`), `resizable` (off by default),\n * `minWidth` / `maxWidth`, `storageKey` of the persisted width (AB#5621);\n * - `ASSISTANT_MESSAGES` — translations (`Partial<AssistantMessages>`; component `messages` inputs win).\n *\n * Requires the `marked` package (markdown of assistant turns).\n *\n * The startup-needed, `marked`-free part (service, hotkey, tokens, transports, models, messages,\n * Explain directives) lives in `@meshmakers/shared-ui/assistant-core` and is re-exported here with\n * the same identity. Import from `assistant-core` in eagerly loaded code and load the panel lazily.\n * {@link FakeAssistantTransport} is a scriptable transport for host specs.\n *\n * Optional transport capabilities (AB#5621) — the panel adds UI only for what the transport has:\n * `sessions` + `loadSession` (+ `refreshSessions`, `deleteSession`, `newSession`, `activeSessionId`)\n * → \"New chat\" / \"Chats\" list; `attachments` → composer file picker, files on\n * `AssistantSendRequest.files`; `starterQuestions()` → clickable questions on an empty thread.\n */\n\n// Startup part — re-exported from assistant-core so tokens and classes keep a single identity.\nexport {\n ASSISTANT_ENABLED,\n ASSISTANT_TRANSPORT,\n ASSISTANT_PAGE_CONTEXT,\n ASSISTANT_TOOL_CALL_COMPONENT,\n ASSISTANT_SLASH_COMMANDS,\n DEFAULT_ASSISTANT_SLASH_COMMANDS,\n ASSISTANT_PANEL_OPTIONS,\n DEFAULT_ASSISTANT_PANEL_MIN_WIDTH,\n DEFAULT_ASSISTANT_PANEL_MAX_WIDTH,\n DEFAULT_ASSISTANT_PANEL_STORAGE_KEY,\n DEFAULT_ASSISTANT_MESSAGES,\n ASSISTANT_MESSAGES,\n resolveAssistantMessages,\n formatAssistantMessage,\n proposalDecisionLabel,\n AssistantService,\n assistantHotkey,\n NotConnectedAssistantTransport,\n ASSISTANT_NOT_CONNECTED_MESSAGE,\n FakeAssistantTransport,\n deriveAssistantContext,\n selectAssistantAttachments,\n assistantFileAccepted,\n formatAssistantFileSize,\n AssistantToolCallRowComponent,\n IfAssistantDirective,\n AssistantExplainDirective,\n} from '@meshmakers/shared-ui/assistant-core';\nexport type {\n AssistantTransportStatus,\n AssistantContextKind,\n AssistantContextChip,\n AssistantExplainTarget,\n AssistantOpenRequest,\n AssistantProposal,\n AssistantToolCall,\n AssistantPageContext,\n AssistantThreadItem,\n AssistantProposalDecisionKind,\n AssistantProposalDecision,\n AssistantSendRequest,\n AssistantStreamEvent,\n AssistantTransport,\n AssistantSlashCommand,\n AssistantMessages,\n AssistantContextSource,\n AssistantAttachmentRef,\n AssistantAttachmentOptions,\n AssistantSessionSummary,\n AssistantStarterQuestions,\n AssistantAsyncResult,\n AssistantAttachmentSelection,\n AssistantPanelOptions,\n AssistantPanelMode,\n} from '@meshmakers/shared-ui/assistant-core';\n\n// --- Markdown (needs `marked`) ---\nexport { renderAssistantMarkdown, classifyAssistantHref, AssistantMarkdownPipe } from './assistant-markdown';\n\n// --- Panel components ---\nexport { AssistantPanelComponent } from './panel/assistant-panel.component';\nexport { AssistantComposerComponent } from './composer/assistant-composer.component';\nexport { AssistantThreadComponent } from './thread/assistant-thread.component';\nexport { AssistantProposalCardComponent } from './proposal-card/assistant-proposal-card.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"meshmakers-shared-ui-assistant.mjs","sources":["../../../../projects/meshmakers/shared-ui/assistant/src/assistant-markdown.ts","../../../../projects/meshmakers/shared-ui/assistant/src/composer/assistant-composer.component.ts","../../../../projects/meshmakers/shared-ui/assistant/src/composer/assistant-composer.component.html","../../../../projects/meshmakers/shared-ui/assistant/src/proposal-card/assistant-proposal-card.component.ts","../../../../projects/meshmakers/shared-ui/assistant/src/proposal-card/assistant-proposal-card.component.html","../../../../projects/meshmakers/shared-ui/assistant/src/thread/assistant-thread.component.ts","../../../../projects/meshmakers/shared-ui/assistant/src/thread/assistant-thread.component.html","../../../../projects/meshmakers/shared-ui/assistant/src/panel/assistant-panel.component.ts","../../../../projects/meshmakers/shared-ui/assistant/src/panel/assistant-panel.component.html","../../../../projects/meshmakers/shared-ui/assistant/src/public-api.ts","../../../../projects/meshmakers/shared-ui/assistant/src/meshmakers-shared-ui-assistant.ts"],"sourcesContent":["import { Pipe, PipeTransform } from '@angular/core';\nimport { Marked, Tokens } from 'marked';\n\n/** Protocols an assistant link may use; everything else (javascript:, data:, vbscript: …) renders as text. */\nconst SAFE_PROTOCOLS = new Set(['http:', 'https:', 'mailto:']);\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/** Classifies a link target: external (http/https/mailto), relative (same origin) or unsafe. */\nexport function classifyAssistantHref(href: string | null | undefined): 'external' | 'relative' | 'unsafe' {\n const value = (href ?? '').trim();\n if (!value) {\n return 'unsafe';\n }\n // Strip control characters and whitespace browsers ignore inside a scheme (\"java\\nscript:\").\n // eslint-disable-next-line no-control-regex\n const compact = value.replace(/[\\u0000- \\u007f]/g, '');\n const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(compact);\n if (scheme) {\n return SAFE_PROTOCOLS.has(`${scheme[1].toLowerCase()}:`) ? 'external' : 'unsafe';\n }\n // Protocol-relative URLs leave the origin. Browsers treat a backslash like \"/\" in http(s)\n // URLs, so \"/\\evil.example\" and \"\\\\evil.example\" leave it as well.\n if (compact.replace(/\\\\/g, '/').startsWith('//')) {\n return 'unsafe';\n }\n return 'relative';\n}\n\nfunction safeLink(href: string, labelHtml: string, title?: string | null): string {\n const kind = classifyAssistantHref(href);\n if (kind === 'unsafe') {\n return labelHtml;\n }\n const titleAttr = title ? ` title=\"${escapeHtml(title)}\"` : '';\n const external = kind === 'external' ? ' target=\"_blank\" rel=\"noopener noreferrer\"' : '';\n return `<a href=\"${escapeHtml(href.trim())}\"${titleAttr}${external}>${labelHtml}</a>`;\n}\n\n/**\n * Markdown renderer for assistant turns. Model output is untrusted, so:\n * raw HTML is shown as text, images never load (they become their alt text,\n * linked when the source is a safe URL), links only keep http(s)/mailto and\n * relative targets — external ones open in a new tab with\n * `rel=\"noopener noreferrer\"` — and anything else renders as its label.\n * The result is bound with `[innerHTML]`, so Angular's sanitizer runs as a\n * second layer.\n */\nconst assistantMarked = new Marked({\n async: false,\n gfm: true,\n renderer: {\n html({ text }: Tokens.HTML | Tokens.Tag): string {\n return escapeHtml(text);\n },\n link(token: Tokens.Link): string {\n return safeLink(token.href, this.parser.parseInline(token.tokens), token.title);\n },\n image({ href, text }: Tokens.Image): string {\n const label = escapeHtml(text || 'image');\n return classifyAssistantHref(href) === 'unsafe' ? label : safeLink(href, label);\n }\n }\n});\n\n/** Renders untrusted assistant markdown to HTML with the rules above. */\nexport function renderAssistantMarkdown(markdown: string): string {\n return assistantMarked.parse(markdown ?? '', { async: false });\n}\n\n/** `{{ text | assistantMarkdown }}` for `[innerHTML]` bindings. */\n@Pipe({ name: 'assistantMarkdown' })\nexport class AssistantMarkdownPipe implements PipeTransform {\n transform(markdown: string): string {\n return renderAssistantMarkdown(markdown);\n }\n}\n","import { ChangeDetectionStrategy, Component, ElementRef, computed, inject, input, model, output, signal, viewChild } from '@angular/core';\nimport {\n ASSISTANT_SLASH_COMMANDS,\n AssistantAttachmentOptions,\n AssistantSlashCommand,\n AssistantMessages,\n assistantMessages,\n formatAssistantMessage,\n selectAssistantAttachments\n} from '@meshmakers/shared-ui/assistant-core';\nimport { SVGIconComponent } from '@progress/kendo-angular-icons';\nimport { paperclipIcon, xIcon } from '@progress/kendo-svg-icons';\n\nlet nextComposerId = 0;\n\n/**\n * Composer (ui-concept §5.3): multi-line, Enter sends, Shift+Enter is a newline,\n * typing `/` at the start lists the slash commands (`ASSISTANT_SLASH_COMMANDS`, by default\n * `/explain`, `/query`, `/summarise`, `/draft-pipeline`). The suggestion list follows the combobox\n * pattern: focus stays in the textarea, ↑/↓ move, Enter/Tab pick, Esc closes the\n * list (and only then lets Esc reach the panel).\n *\n * With {@link attachments} set (the transport accepts files, AB#5621) an \"Attach file\" button opens\n * a file picker limited to `accept`; files are checked against `maxFiles` / `maxFileSizeBytes`,\n * rejected ones are announced in an alert, attached ones are listed with a remove button, and a\n * message may then be sent without text. Without it there is no attachment UI.\n */\n@Component({\n selector: 'mm-assistant-composer',\n imports: [SVGIconComponent],\n templateUrl: './assistant-composer.component.html',\n styleUrl: './assistant-composer.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AssistantComposerComponent {\n /** The composer text (two-way). */\n readonly text = model('');\n /** Whether Enter may send; false while the transport is not ready. */\n readonly canSend = input(false);\n /** A turn is running: the send button becomes a stop button. */\n readonly sending = input(false);\n\n /** Accepted attachments; `null` (default) = no attachment UI. */\n readonly attachments = input<AssistantAttachmentOptions | null>(null);\n /** The attached files (two-way); sent with the next message by the host. */\n readonly files = model<readonly File[]>([]);\n\n readonly send = output<string>();\n readonly stop = output<void>();\n /** Translations; members left out fall back to {@link ASSISTANT_MESSAGES}, then English. */\n readonly messages = input<Partial<AssistantMessages> | null>(null);\n protected readonly m = assistantMessages(this.messages);\n\n private readonly textarea = viewChild.required<ElementRef<HTMLTextAreaElement>>('input');\n private readonly fileInput = viewChild<ElementRef<HTMLInputElement>>('fileInput');\n\n /** Messages about rejected files of the last pick. */\n protected readonly attachmentErrors = signal<readonly string[]>([]);\n /** Something to send: text, or (with attachments) at least one file. */\n protected readonly hasContent = computed(() => this.text().trim().length > 0 || (!!this.attachments() && this.files().length > 0));\n protected readonly multiple = computed(() => (this.attachments()?.maxFiles ?? 1) > 1);\n protected readonly xIcon = xIcon;\n protected readonly paperclipIcon = paperclipIcon;\n protected readonly commands: readonly AssistantSlashCommand[] = inject(ASSISTANT_SLASH_COMMANDS);\n\n protected readonly listId = `assistant-slash-${nextComposerId++}`;\n protected readonly activeIndex = signal(0);\n private readonly dismissedFor = signal<string | null>(null);\n\n /** Slash commands matching what was typed, while the text is a bare `/word`. */\n protected readonly suggestions = computed<readonly AssistantSlashCommand[]>(() => {\n const text = this.text();\n if (!/^\\/[\\w-]*$/.test(text) || this.dismissedFor() === text) {\n return [];\n }\n return this.commands.filter(command => command.command.startsWith(text.toLowerCase()));\n });\n\n protected readonly activeOptionId = computed(() =>\n this.suggestions().length ? `${this.listId}-${Math.min(this.activeIndex(), this.suggestions().length - 1)}` : null);\n\n /** Focuses the textarea with the caret at the end (entry points prefill it). */\n focus(): void {\n const element = this.textarea().nativeElement;\n element.focus();\n element.setSelectionRange(element.value.length, element.value.length);\n }\n\n protected onInput(value: string): void {\n this.text.set(value);\n this.activeIndex.set(0);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (event.isComposing) {\n return;\n }\n const suggestions = this.suggestions();\n if (suggestions.length) {\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.activeIndex.update(index => (index + 1) % suggestions.length);\n return;\n case 'ArrowUp':\n event.preventDefault();\n this.activeIndex.update(index => (index - 1 + suggestions.length) % suggestions.length);\n return;\n case 'Enter':\n case 'Tab':\n if (!event.shiftKey) {\n event.preventDefault();\n this.pick(suggestions[Math.min(this.activeIndex(), suggestions.length - 1)]);\n return;\n }\n break;\n case 'Escape':\n event.preventDefault();\n event.stopPropagation();\n this.dismissedFor.set(this.text());\n return;\n }\n }\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n this.submit();\n }\n }\n\n protected pick(command: AssistantSlashCommand): void {\n this.text.set(`${command.command} `);\n this.activeIndex.set(0);\n this.focus();\n }\n\n protected submit(): void {\n if (this.canSend() && this.hasContent()) {\n this.attachmentErrors.set([]);\n this.send.emit(this.text());\n }\n }\n\n protected openFilePicker(): void {\n this.fileInput()?.nativeElement.click();\n }\n\n protected onFilesPicked(input: HTMLInputElement): void {\n const options = this.attachments();\n const picked = Array.from(input.files ?? []);\n // Reset so picking the same file again fires `change`.\n input.value = '';\n if (!options || !picked.length) {\n return;\n }\n const selection = selectAssistantAttachments(this.files(), picked, options, this.m());\n this.files.set(selection.files);\n this.attachmentErrors.set(selection.errors);\n }\n\n protected removeFile(index: number): void {\n this.files.update(files => files.filter((_, i) => i !== index));\n this.attachmentErrors.set([]);\n this.focus();\n }\n\n protected format(message: string, values: Record<string, string>): string {\n return formatAssistantMessage(message, values);\n }\n}\n","<div class=\"composer\">\n @if (suggestions().length) {\n <ul class=\"suggestions\" role=\"listbox\" [id]=\"listId\" [attr.aria-label]=\"m().commandsLabel\">\n @for (command of suggestions(); track command.command; let i = $index) {\n <li role=\"option\" [id]=\"listId + '-' + i\" [attr.aria-selected]=\"activeOptionId() === listId + '-' + i\"\n (mousedown)=\"$event.preventDefault()\" (click)=\"pick(command)\">\n <span class=\"cmd\">{{ command.command }}</span>\n <span class=\"cmd-desc\">{{ command.description }}</span>\n </li>\n }\n </ul>\n }\n @if (attachments(); as options) {\n @if (files().length) {\n <ul class=\"files\" [attr.aria-label]=\"m().attachmentsLabel\">\n @for (file of files(); track $index; let i = $index) {\n <li class=\"file\">\n <span class=\"file-name\" [title]=\"file.name\">{{ file.name }}</span>\n <button type=\"button\" [attr.aria-label]=\"format(m().removeAttachment, { name: file.name })\" [title]=\"format(m().removeAttachment, { name: file.name })\" (click)=\"removeFile(i)\"><kendo-svg-icon [icon]=\"xIcon\" size=\"small\"></kendo-svg-icon></button>\n </li>\n }\n </ul>\n }\n @if (attachmentErrors().length) {\n <div class=\"file-errors\" role=\"alert\">\n @for (error of attachmentErrors(); track $index) {\n <p>{{ error }}</p>\n }\n </div>\n }\n <input #fileInput class=\"file-input\" type=\"file\" tabindex=\"-1\" aria-hidden=\"true\"\n [attr.accept]=\"options.accept || null\" [multiple]=\"multiple()\"\n (change)=\"onFilesPicked($any($event.target))\">\n }\n <div class=\"box\">\n @if (attachments()) {\n <button type=\"button\" class=\"attach\" [attr.aria-label]=\"m().attachFile\" [title]=\"m().attachFile\" (click)=\"openFilePicker()\">\n <kendo-svg-icon [icon]=\"paperclipIcon\"></kendo-svg-icon>\n </button>\n }\n <textarea #input\n rows=\"2\"\n [attr.aria-label]=\"m().composerLabel\"\n [placeholder]=\"m().composerPlaceholder\"\n aria-autocomplete=\"list\"\n [attr.aria-controls]=\"suggestions().length ? listId : null\"\n [attr.aria-expanded]=\"suggestions().length > 0\"\n [attr.aria-activedescendant]=\"activeOptionId()\"\n [value]=\"text()\"\n (input)=\"onInput($any($event.target).value)\"\n (keydown)=\"onKeydown($event)\"></textarea>\n @if (sending()) {\n <button type=\"button\" class=\"send\" (click)=\"stop.emit()\">{{ m().stop }}</button>\n } @else {\n <button type=\"button\" class=\"send\" [disabled]=\"!canSend() || !hasContent()\" (click)=\"submit()\">{{ m().send }}</button>\n }\n </div>\n <div class=\"hint\" aria-hidden=\"true\">\n @for (command of commands; track command.command) {\n <kbd>{{ command.command }}</kbd>\n }\n </div>\n</div>\n","import { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';\nimport { AssistantProposal, AssistantProposalDecisionKind, AssistantMessages, assistantMessages, formatAssistantMessage, proposalDecisionLabel } from '@meshmakers/shared-ui/assistant-core';\n\n/**\n * A write the assistant proposes (ui-concept §5.3/§5.6, wireframe screen 6):\n * violet card with a parameter table and Run / Edit / Discard. The buttons only\n * emit — the card never executes anything; the host forwards the decision.\n */\n@Component({\n selector: 'mm-assistant-proposal-card',\n templateUrl: './assistant-proposal-card.component.html',\n styleUrl: './assistant-proposal-card.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AssistantProposalCardComponent {\n readonly proposal = input.required<AssistantProposal>();\n /** Set once the person ran or discarded the proposal; disables the buttons. */\n readonly decision = input<AssistantProposalDecisionKind | null>(null);\n\n readonly run = output<AssistantProposal>();\n readonly edit = output<AssistantProposal>();\n readonly discard = output<AssistantProposal>();\n /** Translations; members left out fall back to {@link ASSISTANT_MESSAGES}, then English. */\n readonly messages = input<Partial<AssistantMessages> | null>(null);\n protected readonly m = assistantMessages(this.messages);\n protected readonly cardLabel = computed(() => formatAssistantMessage(this.m().proposalLabel, { title: this.proposal().title }));\n\n protected readonly decisionLabel = computed(() => {\n const decision = this.decision();\n return decision ? proposalDecisionLabel(decision, this.m()) : null;\n });\n}\n","<article class=\"proposal\" [class.settled]=\"decision() !== null\" [attr.aria-label]=\"cardLabel()\">\n <header class=\"proposal-head\">\n <span aria-hidden=\"true\">✦</span> {{ m().proposal }}@if (proposal().writes) { · {{ m().writesToTenant }} }\n </header>\n <div class=\"proposal-body\">\n <p class=\"proposal-title\">{{ proposal().title }}</p>\n @if (proposal().description) {\n <p class=\"proposal-description\">{{ proposal().description }}</p>\n }\n @if (proposal().parameters.length) {\n <dl class=\"proposal-params\">\n @for (param of proposal().parameters; track param.name) {\n <dt>{{ param.name }}</dt>\n <dd>{{ param.value }}</dd>\n }\n </dl>\n }\n <p class=\"proposal-meta\">{{ m().tool }} <span class=\"mono\">{{ proposal().toolName }}</span> · {{ m().runsAfterConfirm }}</p>\n </div>\n <footer class=\"proposal-foot\">\n @if (decisionLabel(); as label) {\n <span class=\"proposal-decision\" role=\"status\">{{ label }}</span>\n } @else {\n <button type=\"button\" class=\"btn primary\" (click)=\"run.emit(proposal())\">{{ m().run }}</button>\n <button type=\"button\" class=\"btn\" (click)=\"edit.emit(proposal())\">{{ m().edit }}</button>\n <button type=\"button\" class=\"btn\" (click)=\"discard.emit(proposal())\">{{ m().discard }}</button>\n }\n </footer>\n</article>\n","import { ChangeDetectionStrategy, Component, ElementRef, computed, effect, inject, input, output } from '@angular/core';\nimport { NgComponentOutlet } from '@angular/common';\nimport { AssistantMarkdownPipe } from '../assistant-markdown';\nimport { AssistantProposalCardComponent } from '../proposal-card/assistant-proposal-card.component';\nimport { OctoBotComponent } from '@meshmakers/shared-ui';\nimport { ASSISTANT_TOOL_CALL_COMPONENT, AssistantProposalDecision, AssistantThreadItem, AssistantMessages, assistantMessages } from '@meshmakers/shared-ui/assistant-core';\n\n/**\n * The conversation (wireframe screen 6): user turns, assistant turns (markdown\n * via `renderAssistantMarkdown`: no images, safe links only; violet edge), tool-call rows and proposal cards. Tool calls\n * render with the `ASSISTANT_TOOL_CALL_COMPONENT` (an OctoMesh host passes `mm-ai-tool-call` from\n * `@meshmakers/octo-ai-console`, ui-concept §5.1 \"do not rebuild\"); proposals are emitted, never executed.\n *\n * A user turn sent through a slash command's `expand` (AB#5621) shows the expanded prompt with the\n * typed command (`slashCommand`) as a small label above it.\n *\n * While an assistant turn streams it shows the OctoBot `thinking` with \"Thinking…\" (AB#3444);\n * once the reply is complete the newest assistant turn keeps the OctoBot as a still frame. The\n * figure is decorative — the text carries the meaning — and appears at most once in the thread.\n *\n * The list is an `aria-live` log; it is `aria-busy` while a turn streams so a\n * screen reader announces finished messages instead of every token. Nothing\n * inside it carries its own live role, so each addition is announced once.\n */\n@Component({\n selector: 'mm-assistant-thread',\n imports: [NgComponentOutlet, AssistantMarkdownPipe, AssistantProposalCardComponent, OctoBotComponent],\n templateUrl: './assistant-thread.component.html',\n styleUrl: './assistant-thread.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AssistantThreadComponent {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n readonly items = input<AssistantThreadItem[]>([]);\n readonly proposalDecision = output<AssistantProposalDecision>();\n /** Translations; members left out fall back to {@link ASSISTANT_MESSAGES}, then English. */\n readonly messages = input<Partial<AssistantMessages> | null>(null);\n protected readonly m = assistantMessages(this.messages);\n protected readonly toolCallComponent = inject(ASSISTANT_TOOL_CALL_COMPONENT);\n\n /** Id of the newest assistant turn: the only one that shows the resting OctoBot. */\n protected readonly lastAssistantId = computed(() => {\n const items = this.items();\n for (let i = items.length - 1; i >= 0; i--) {\n if (items[i].kind === 'assistant') {\n return items[i].id;\n }\n }\n return null;\n });\n\n protected readonly streaming = computed(() => this.items().some(item => item.kind === 'assistant' && item.streaming));\n\n constructor() {\n // Keep the newest turn in view.\n effect(() => {\n this.items();\n queueMicrotask(() => {\n const element = this.host.nativeElement;\n element.scrollTop = element.scrollHeight;\n });\n });\n }\n}\n","<ol class=\"thread\" role=\"log\" aria-live=\"polite\" aria-relevant=\"additions text\" [attr.aria-label]=\"m().conversationLabel\"\n [attr.aria-busy]=\"streaming()\">\n @for (item of items(); track item.id) {\n @switch (item.kind) {\n @case ('user') {\n <li class=\"msg user\"><span class=\"sr-only\">{{ m().youPrefix }}</span>@if (item.slashCommand) {<span class=\"slash-command\"><span class=\"sr-only\">{{ m().slashCommandPrefix }}</span>{{ item.slashCommand }}</span>}{{ item.text }}@if (item.attachments?.length) {<ul class=\"attachments\" [attr.aria-label]=\"m().attachmentsLabel\">@for (file of item.attachments; track $index) {<li class=\"attachment\">{{ file.name }}</li>}</ul>}</li>\n }\n @case ('assistant') {\n <li class=\"msg bot\">\n <span class=\"sr-only\">{{ m().assistantPrefix }}</span>\n <div class=\"md\" [innerHTML]=\"item.markdown | assistantMarkdown\"></div>\n @if (item.streaming) {\n <span class=\"streaming\" data-testid=\"assistant-thinking\">\n <mm-octobot animation=\"thinking\" size=\"sm\" />\n <span class=\"streaming-text\">{{ m().thinking }}</span>\n </span>\n } @else if (item.id === lastAssistantId()) {\n <mm-octobot class=\"settled\" animation=\"thinking\" size=\"sm\" still data-testid=\"assistant-settled\" />\n }\n </li>\n }\n @case ('tool-call') {\n <li class=\"msg tool\"><ng-container *ngComponentOutlet=\"toolCallComponent; inputs: { call: item.call }\"></ng-container></li>\n }\n @case ('proposal') {\n <li class=\"msg\">\n <mm-assistant-proposal-card\n [messages]=\"messages()\"\n [proposal]=\"item.proposal\"\n [decision]=\"item.decision\"\n (run)=\"proposalDecision.emit({ kind: 'run', proposal: $event })\"\n (edit)=\"proposalDecision.emit({ kind: 'edit', proposal: $event })\"\n (discard)=\"proposalDecision.emit({ kind: 'discard', proposal: $event })\">\n </mm-assistant-proposal-card>\n </li>\n }\n @case ('error') {\n <li class=\"msg error\"><span class=\"sr-only\">{{ m().errorPrefix }}</span>{{ item.text }}</li>\n }\n }\n }\n</ol>\n","import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, Injector, afterNextRender, computed, effect, inject, input, signal, untracked, viewChild } from '@angular/core';\nimport {\n ASSISTANT_PANEL_OPTIONS,\n AssistantMessages,\n AssistantPanelMode,\n AssistantProposalDecision,\n AssistantService,\n AssistantSessionSummary,\n DEFAULT_ASSISTANT_PANEL_MAX_WIDTH,\n DEFAULT_ASSISTANT_PANEL_MIN_WIDTH,\n DEFAULT_ASSISTANT_PANEL_STORAGE_KEY,\n assistantMessages,\n formatAssistantMessage\n} from '@meshmakers/shared-ui/assistant-core';\nimport { SVGIconComponent } from '@progress/kendo-angular-icons';\nimport { clockArrowRotateIcon, plusIcon, trashIcon, xIcon } from '@progress/kendo-svg-icons';\nimport { AssistantComposerComponent } from '../composer/assistant-composer.component';\nimport { AssistantThreadComponent } from '../thread/assistant-thread.component';\nimport { OctoBotComponent } from '@meshmakers/shared-ui';\n\n/** Width of the panel before anyone resized it (CSS: 400 px, 340 px ≤ 1180 px), used until measured. */\nconst FALLBACK_WIDTH = 400;\n/** Window width the handle always leaves to the content. */\nconst MIN_CONTENT_WIDTH = 240;\n/** Keyboard step of the resize handle in px (Shift: four times). */\nconst RESIZE_STEP = 16;\n\n/** The persisted width, or null when absent, invalid or storage is unavailable. */\nfunction readStoredWidth(key: string | null): number | null {\n if (!key) {\n return null;\n }\n try {\n const raw = globalThis.localStorage?.getItem(key);\n const width = raw === null || raw === undefined ? NaN : Number(raw);\n return Number.isFinite(width) && width > 0 ? width : null;\n } catch {\n return null;\n }\n}\n\n/** Best effort: storage may be missing, full or blocked. */\nfunction writeStoredWidth(key: string | null, width: number | null): void {\n if (!key) {\n return;\n }\n try {\n if (width === null) {\n globalThis.localStorage?.removeItem(key);\n } else {\n globalThis.localStorage?.setItem(key, String(Math.round(width)));\n }\n } catch {\n // Persistence is best effort.\n }\n}\n\n/**\n * Right-side assistant panel (ui-concept §5.3, wireframe screen 6): header,\n * removable context chips, thread, composer. Non-modal: the page stays usable.\n * Opening focuses the composer, Esc closes and focus returns to where it was\n * (AssistantService). Below 640 px it covers the screen under the top bar and\n * becomes a modal dialog (`aria-modal`, Tab trapped) so the page behind is out\n * of reach. Removing a context chip moves focus to the next chip, else the composer.\n *\n * Host it only while {@link AssistantService.enabled} is set and the panel is open\n * (`@if (assistant.enabled && assistant.isOpen()) { <mm-assistant-panel /> }`); the thread\n * lives in the service, so closing and navigating keep it.\n *\n * Optional transport capabilities (AB#5621) add UI only when the transport has them:\n * - **sessions** — \"New chat\" and \"Chats\" in the header; the chat list replaces the thread\n * (open a chat, delete with an inline confirmation; Esc returns to the chat);\n * - **starter questions** — shown as buttons on an empty thread; clicking one sends it;\n * - **attachments** — the composer's \"Attach file\" button (see `mm-assistant-composer`).\n *\n * Header actions (\"New chat\", \"Chats\", close) are icon buttons with tooltip and `aria-label` from\n * the messages, so they never wrap in a narrow panel (AB#5621).\n *\n * **Layout (AB#5621)** — inputs, else {@link ASSISTANT_PANEL_OPTIONS}, else the defaults:\n * - `resizable` (default `false`, so no handle and no extra tab stop; opt in per input or token):\n * a handle on the left edge (`role=\"separator\"`) changes the width by dragging or with ←/→\n * (Shift: bigger steps), Home/End (min/max); a double click forgets the chosen width. The width\n * stays within `minWidth`..`maxWidth` (320..720 px, and at least 240 px of the window stay free)\n * and is kept in `localStorage` under `storageKey` (`mm-assistant-panel-width`; `null` = not\n * kept). Without `resizable`, or until someone resizes it, the panel keeps its CSS width (400 px,\n * 340 px ≤ 1180 px). Unavailable storage only means the width is not kept.\n * - `mode`: `docked` (default, pushes the content) or `overlay` (floats over it, `position: fixed`\n * at the right edge below `--mm-assistant-overlay-top`, default 48 px; stacking via\n * `--mm-assistant-overlay-z-index`, default 20).\n * On phones neither applies: the panel is the full-screen dialog.\n */\n@Component({\n selector: 'mm-assistant-panel',\n imports: [AssistantThreadComponent, AssistantComposerComponent, SVGIconComponent, OctoBotComponent],\n templateUrl: './assistant-panel.component.html',\n styleUrl: './assistant-panel.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[attr.role]': 'isPhone() ? \"dialog\" : \"complementary\"',\n '[attr.aria-modal]': 'isPhone() ? \"true\" : null',\n 'aria-labelledby': 'assistant-panel-title',\n id: 'assistant-panel',\n '[class.mm-assistant-overlay]': 'overlay()',\n '[class.mm-assistant-resizing]': 'resizing()',\n '[attr.data-mode]': 'effectiveMode()',\n '[style.width.px]': 'isPhone() ? null : appliedWidth()',\n '(keydown.escape)': 'onEscape($event)',\n '(keydown.tab)': 'onTab($event)',\n '(keydown.shift.tab)': 'onTab($event)'\n }\n})\nexport class AssistantPanelComponent {\n protected readonly assistant = inject(AssistantService);\n private readonly injector = inject(Injector);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly composer = viewChild(AssistantComposerComponent);\n\n /** Translations; members left out fall back to {@link ASSISTANT_MESSAGES}, then English. */\n readonly messages = input<Partial<AssistantMessages> | null>(null);\n protected readonly m = assistantMessages(this.messages);\n\n /** `docked` pushes the content, `overlay` floats over it (default: options token, else `docked`). */\n readonly mode = input<AssistantPanelMode | null>(null);\n /** Shows the resize handle (default: options token, else `false`). */\n readonly resizable = input<boolean | null>(null);\n /** Smallest width in px of the resize handle (default: options token, else 320). */\n readonly minWidth = input<number | null>(null);\n /** Largest width in px of the resize handle (default: options token, else 720). */\n readonly maxWidth = input<number | null>(null);\n /**\n * `localStorage` key of the chosen width; `null` = not kept. Left out (`undefined`): options\n * token, else `mm-assistant-panel-width`.\n */\n readonly storageKey = input<string | null | undefined>(undefined);\n\n protected readonly xIcon = xIcon;\n protected readonly plusIcon = plusIcon;\n protected readonly historyIcon = clockArrowRotateIcon;\n protected readonly trashIcon = trashIcon;\n\n private readonly options = inject(ASSISTANT_PANEL_OPTIONS, { optional: true });\n\n protected readonly effectiveMode = computed<AssistantPanelMode>(() => this.mode() ?? this.options?.mode ?? 'docked');\n protected readonly overlay = computed(() => this.effectiveMode() === 'overlay' && !this.isPhone());\n private readonly effectiveStorageKey = computed(() => {\n const key = this.storageKey();\n if (key !== undefined) {\n return key;\n }\n return this.options?.storageKey !== undefined ? this.options.storageKey : DEFAULT_ASSISTANT_PANEL_STORAGE_KEY;\n });\n protected readonly effectiveMin = computed(() =>\n Math.max(0, Math.round(this.minWidth() ?? this.options?.minWidth ?? DEFAULT_ASSISTANT_PANEL_MIN_WIDTH)));\n protected readonly effectiveMax = computed(() => {\n const configured = this.maxWidth() ?? this.options?.maxWidth ?? DEFAULT_ASSISTANT_PANEL_MAX_WIDTH;\n const viewport = typeof window !== 'undefined' && window.innerWidth > 0 ? window.innerWidth - MIN_CONTENT_WIDTH : Infinity;\n return Math.round(Math.max(this.effectiveMin(), Math.min(configured, viewport)));\n });\n /** The handle is shown (never on phones). */\n protected readonly canResize = computed(() => (this.resizable() ?? this.options?.resizable ?? false) && !this.isPhone());\n\n /** Width chosen in this panel instance; `undefined` = not touched yet (stored width applies). */\n private readonly chosenWidth = signal<number | null | undefined>(undefined);\n private readonly storedWidth = computed(() => readStoredWidth(this.effectiveStorageKey()));\n /** The inline width in px, or null for the CSS default. */\n protected readonly appliedWidth = computed(() => {\n const chosen = this.chosenWidth();\n const width = chosen === undefined ? this.storedWidth() : chosen;\n return width === null || !this.canResize() ? null : this.clampWidth(width);\n });\n /** CSS width as rendered, for `aria-valuenow` before the first resize. */\n private readonly measuredWidth = signal(FALLBACK_WIDTH);\n protected readonly currentWidth = computed(() => this.appliedWidth() ?? this.clampWidth(this.measuredWidth()));\n protected readonly resizing = signal(false);\n private stopDrag: (() => void) | null = null;\n\n /** Phone layout (≤ 640 px, the shell's breakpoint): the panel is a modal dialog. */\n protected readonly isPhone = signal(false);\n\n protected readonly connected = computed(() => this.assistant.transportStatus() !== 'unavailable');\n\n /** `chat` = thread + composer; `sessions` = the saved chats list (session-capable transports only). */\n protected readonly view = signal<'chat' | 'sessions'>('chat');\n /** Session whose deletion waits for confirmation. */\n protected readonly confirmingDelete = signal<string | null>(null);\n /** Session being opened or deleted (its buttons are disabled meanwhile). */\n protected readonly busySession = signal<string | null>(null);\n\n /**\n * Greeting of an empty chat (AB#3444): the OctoBot waves once, then rests on its still frame.\n * Not shown while the assistant is unavailable (the panel says so instead).\n */\n protected readonly showGreeting = computed(() =>\n this.view() === 'chat' && this.assistant.thread().length === 0 && this.connected()\n && this.assistant.transportStatus() !== 'error');\n\n /** Starter questions on an empty thread (transports with `starterQuestions` only). */\n protected readonly showStarters = computed(() =>\n this.view() === 'chat' && this.assistant.thread().length === 0 && this.assistant.starterQuestions().length > 0);\n\n constructor() {\n const query = typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia('(max-width: 640px)')\n : null;\n if (query) {\n this.isPhone.set(query.matches);\n const listener = (event: MediaQueryListEvent): void => this.isPhone.set(event.matches);\n query.addEventListener('change', listener);\n inject(DestroyRef).onDestroy(() => query.removeEventListener('change', listener));\n }\n\n this.assistant.loadStarterQuestions();\n\n afterNextRender(() => this.measure());\n inject(DestroyRef).onDestroy(() => this.stopDrag?.());\n\n // Every entry point bumps focusRequest; the composer gets focus once rendered.\n effect(() => {\n this.assistant.focusRequest();\n untracked(() => {\n this.view.set('chat');\n this.focusComposer();\n });\n });\n }\n\n /** Pointer drag on the handle: the panel sits on the right, so moving left widens it. */\n protected startResize(event: PointerEvent): void {\n if (event.button !== 0 || !this.canResize()) {\n return;\n }\n event.preventDefault();\n this.stopDrag?.();\n const startX = event.clientX;\n const startWidth = this.currentWidth();\n const move = (moveEvent: PointerEvent): void => this.setWidth(startWidth + startX - moveEvent.clientX, false);\n const end = (): void => {\n this.stopDrag?.();\n const width = this.chosenWidth();\n if (width !== undefined) {\n writeStoredWidth(this.effectiveStorageKey(), width);\n }\n };\n document.addEventListener('pointermove', move);\n document.addEventListener('pointerup', end);\n document.addEventListener('pointercancel', end);\n this.resizing.set(true);\n this.stopDrag = () => {\n document.removeEventListener('pointermove', move);\n document.removeEventListener('pointerup', end);\n document.removeEventListener('pointercancel', end);\n this.resizing.set(false);\n this.stopDrag = null;\n };\n }\n\n /** ←/→ resize (Shift: ×4), Home/End jump to min/max; the width is kept right away. */\n protected onResizeKey(event: KeyboardEvent): void {\n const step = event.shiftKey ? RESIZE_STEP * 4 : RESIZE_STEP;\n let width: number;\n switch (event.key) {\n case 'ArrowLeft': width = this.currentWidth() + step; break;\n case 'ArrowRight': width = this.currentWidth() - step; break;\n case 'Home': width = this.effectiveMin(); break;\n case 'End': width = this.effectiveMax(); break;\n default: return;\n }\n event.preventDefault();\n this.setWidth(width, true);\n }\n\n /** Double click on the handle: back to the default width, forgetting the kept one. */\n protected resetWidth(): void {\n this.chosenWidth.set(null);\n writeStoredWidth(this.effectiveStorageKey(), null);\n afterNextRender(() => this.measure(), { injector: this.injector });\n }\n\n private setWidth(width: number, persist: boolean): void {\n const clamped = this.clampWidth(width);\n this.chosenWidth.set(clamped);\n if (persist) {\n writeStoredWidth(this.effectiveStorageKey(), clamped);\n }\n }\n\n private clampWidth(width: number): number {\n return Math.round(Math.min(this.effectiveMax(), Math.max(this.effectiveMin(), width)));\n }\n\n private measure(): void {\n const width = this.host.nativeElement.getBoundingClientRect().width;\n if (width > 0) {\n this.measuredWidth.set(width);\n }\n }\n\n protected onEscape(event: Event): void {\n if (event.defaultPrevented) {\n return;\n }\n event.preventDefault();\n if (this.confirmingDelete()) {\n this.cancelDelete();\n } else if (this.view() === 'sessions') {\n this.backToChat();\n } else {\n this.assistant.close();\n }\n }\n\n /** Shows the saved chats and reloads them. */\n protected showSessions(): void {\n this.confirmingDelete.set(null);\n this.view.set('sessions');\n void this.assistant.refreshSessions();\n this.focusSessionList();\n }\n\n protected backToChat(): void {\n this.confirmingDelete.set(null);\n this.view.set('chat');\n this.focusComposer();\n }\n\n protected newChat(): void {\n this.assistant.newThread();\n this.backToChat();\n }\n\n protected async openSession(session: AssistantSessionSummary): Promise<void> {\n this.busySession.set(session.id);\n try {\n await this.assistant.openSession(session.id);\n } finally {\n this.busySession.set(null);\n }\n this.backToChat();\n }\n\n protected askDelete(session: AssistantSessionSummary): void {\n this.confirmingDelete.set(session.id);\n afterNextRender(() => this.host.nativeElement.querySelector<HTMLElement>('.session-confirm .confirm-delete')?.focus(),\n { injector: this.injector });\n }\n\n protected cancelDelete(): void {\n const id = this.confirmingDelete();\n this.confirmingDelete.set(null);\n afterNextRender(() => Array.from(this.host.nativeElement.querySelectorAll<HTMLElement>('.session-row'))\n .find(row => row.dataset['sessionId'] === id)?.querySelector<HTMLElement>('.session-delete')?.focus(),\n { injector: this.injector });\n }\n\n protected async confirmDelete(session: AssistantSessionSummary): Promise<void> {\n this.busySession.set(session.id);\n let deleted: boolean;\n try {\n deleted = await this.assistant.deleteSession(session.id);\n } finally {\n this.busySession.set(null);\n this.confirmingDelete.set(null);\n }\n if (deleted) {\n await this.assistant.refreshSessions();\n this.focusSessionList();\n } else {\n // The error row lives in the thread.\n this.backToChat();\n }\n }\n\n protected sendStarter(question: string): void {\n this.assistant.send(question);\n }\n\n /** Locale date + time of a session, or '' when absent or unparsable. */\n protected sessionDate(session: AssistantSessionSummary): string {\n if (!session.createdAt) {\n return '';\n }\n const date = new Date(session.createdAt);\n return Number.isNaN(date.getTime()) ? '' : date.toLocaleString(undefined, { dateStyle: 'short', timeStyle: 'short' });\n }\n\n /** First chat of the list, else the back button. */\n private focusSessionList(): void {\n afterNextRender(() => {\n const root = this.host.nativeElement;\n (root.querySelector<HTMLElement>('.session-open') ?? root.querySelector<HTMLElement>('.back'))?.focus();\n }, { injector: this.injector });\n }\n\n private focusComposer(): void {\n afterNextRender(() => this.composer()?.focus(), { injector: this.injector });\n }\n\n /** Phone dialog: Tab and Shift+Tab cycle inside the panel. */\n protected onTab(event: Event): void {\n if (!this.isPhone() || event.defaultPrevented) {\n return;\n }\n const focusable = Array.from(this.host.nativeElement.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), textarea:not([disabled]), input:not([disabled]), a[href], [tabindex]:not([tabindex=\"-1\"])'));\n if (!focusable.length) {\n return;\n }\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const active = document.activeElement;\n const backwards = (event as KeyboardEvent).shiftKey;\n if (backwards && (active === first || !this.host.nativeElement.contains(active))) {\n event.preventDefault();\n last.focus();\n } else if (!backwards && (active === last || !this.host.nativeElement.contains(active))) {\n event.preventDefault();\n first.focus();\n }\n }\n\n /** Drops a chip and keeps keyboard users in the row: next chip, else the composer. */\n protected removeChip(id: string, index: number): void {\n this.assistant.removeChip(id);\n afterNextRender(() => {\n const buttons = this.host.nativeElement.querySelectorAll<HTMLButtonElement>('.ctx-chip button');\n const next = buttons[Math.min(index, buttons.length - 1)];\n if (next) {\n next.focus();\n } else {\n this.composer()?.focus();\n }\n }, { injector: this.injector });\n }\n\n protected format(message: string, values: Record<string, string>): string {\n return formatAssistantMessage(message, values);\n }\n\n protected onDecision(decision: AssistantProposalDecision): void {\n this.assistant.decideProposal(decision.kind, decision.proposal);\n }\n}\n","@if (canResize()) {\n <div class=\"resize-handle\" role=\"separator\" tabindex=\"0\" aria-orientation=\"vertical\" aria-controls=\"assistant-panel\"\n [attr.aria-label]=\"m().resizePanel\" [title]=\"m().resizePanel\"\n [attr.aria-valuenow]=\"currentWidth()\" [attr.aria-valuemin]=\"effectiveMin()\" [attr.aria-valuemax]=\"effectiveMax()\"\n (pointerdown)=\"startResize($event)\" (keydown)=\"onResizeKey($event)\" (dblclick)=\"resetWidth()\"></div>\n}\n\n<header class=\"head\">\n <span class=\"sparkle\" aria-hidden=\"true\">✦</span>\n <h2 class=\"title\" id=\"assistant-panel-title\">{{ m().title }}</h2>\n @if (connected()) {\n <span class=\"chip-neutral\" [title]=\"m().readsWithYourPermissions\">{{ m().readsWithYourPermissions }}</span>\n }\n @if (assistant.sessionsSupported) {\n <div class=\"head-actions\">\n <button type=\"button\" class=\"icon-btn new-chat\" [attr.aria-label]=\"m().newChat\" [title]=\"m().newChat\" (click)=\"newChat()\">\n <kendo-svg-icon [icon]=\"plusIcon\"></kendo-svg-icon>\n </button>\n <button type=\"button\" class=\"icon-btn sessions-toggle\" aria-controls=\"assistant-sessions\"\n [attr.aria-label]=\"m().sessions\" [title]=\"m().sessions\"\n [attr.aria-expanded]=\"view() === 'sessions'\"\n (click)=\"view() === 'sessions' ? backToChat() : showSessions()\">\n <kendo-svg-icon [icon]=\"historyIcon\"></kendo-svg-icon>\n </button>\n </div>\n }\n <button type=\"button\" class=\"icon-btn close\" [attr.aria-label]=\"m().closeAssistant\" [title]=\"m().closeAssistant\" (click)=\"assistant.close()\">\n <kendo-svg-icon [icon]=\"xIcon\"></kendo-svg-icon>\n </button>\n</header>\n\n@if (assistant.contextChips().length) {\n <ul class=\"ctx\" [attr.aria-label]=\"m().contextLabel\">\n @for (chip of assistant.contextChips(); track chip.id; let i = $index) {\n <li class=\"ctx-chip\" [attr.data-kind]=\"chip.kind\" [title]=\"chip.value\">\n <span class=\"ctx-label\">{{ chip.label }}</span>\n <button type=\"button\" [attr.aria-label]=\"format(m().removeContext, { label: chip.label })\" [title]=\"format(m().removeContext, { label: chip.label })\" (click)=\"removeChip(chip.id, i)\"><kendo-svg-icon [icon]=\"xIcon\" size=\"small\"></kendo-svg-icon></button>\n </li>\n }\n </ul>\n}\n\n@if (view() === 'sessions') {\n <section class=\"sessions\" id=\"assistant-sessions\" [attr.aria-label]=\"m().sessionsLabel\">\n <button type=\"button\" class=\"text-btn back\" (click)=\"backToChat()\">← {{ m().backToChat }}</button>\n <ul class=\"session-list\">\n @for (session of assistant.sessions(); track session.id) {\n <li class=\"session-row\" [attr.data-session-id]=\"session.id\"\n [class.active]=\"session.id === assistant.activeSessionId()\">\n @if (confirmingDelete() === session.id) {\n <div class=\"session-confirm\" role=\"group\" [attr.aria-label]=\"format(m().deleteSessionConfirm, { title: session.title })\">\n <span class=\"confirm-text\">{{ format(m().deleteSessionConfirm, { title: session.title }) }}</span>\n <button type=\"button\" class=\"text-btn danger confirm-delete\" [disabled]=\"busySession() === session.id\"\n (click)=\"confirmDelete(session)\">{{ m().delete }}</button>\n <button type=\"button\" class=\"text-btn cancel-delete\" (click)=\"cancelDelete()\">{{ m().cancel }}</button>\n </div>\n } @else {\n <button type=\"button\" class=\"session-open\" [title]=\"session.title\"\n [attr.aria-current]=\"session.id === assistant.activeSessionId() ? 'true' : null\"\n [disabled]=\"busySession() === session.id\"\n (click)=\"openSession(session)\">\n <span class=\"session-title\">{{ session.title }}</span>\n @if (sessionDate(session); as date) {\n <span class=\"session-date\">{{ date }}</span>\n }\n </button>\n @if (assistant.sessionDeleteSupported) {\n <button type=\"button\" class=\"icon-btn session-delete\"\n [attr.aria-label]=\"format(m().deleteSession, { title: session.title })\"\n [title]=\"format(m().deleteSession, { title: session.title })\"\n [disabled]=\"busySession() === session.id\"\n (click)=\"askDelete(session)\">\n <kendo-svg-icon [icon]=\"trashIcon\" size=\"small\"></kendo-svg-icon>\n </button>\n }\n }\n </li>\n } @empty {\n <li class=\"session-empty\">{{ m().noSessions }}</li>\n }\n </ul>\n </section>\n} @else {\n @if (showGreeting()) {\n <div class=\"greeting\" data-testid=\"assistant-greeting\">\n <mm-octobot animation=\"wave\" size=\"md\" playOnce />\n <p class=\"greeting-text\">{{ m().greeting }}</p>\n </div>\n }\n @if (showStarters()) {\n <section class=\"starters\" aria-labelledby=\"assistant-starters-title\">\n <h3 class=\"starters-title\" id=\"assistant-starters-title\">{{ m().startersTitle }}</h3>\n <ul class=\"starter-list\">\n @for (question of assistant.starterQuestions(); track $index) {\n <li><button type=\"button\" class=\"starter\" [disabled]=\"!assistant.canSend()\" (click)=\"sendStarter(question)\">{{ question }}</button></li>\n }\n </ul>\n </section>\n }\n\n <mm-assistant-thread class=\"thread\" [items]=\"assistant.thread()\" [messages]=\"messages()\" (proposalDecision)=\"onDecision($event)\"></mm-assistant-thread>\n\n @if (!connected() || assistant.transportStatus() === 'error') {\n <div class=\"unavailable\" role=\"status\">\n <span class=\"sparkle\" aria-hidden=\"true\">✦</span>\n <p>{{ assistant.transportMessage() ?? m().notAvailable }}</p>\n </div>\n }\n\n <mm-assistant-composer\n [messages]=\"messages()\"\n [text]=\"assistant.draft()\"\n (textChange)=\"assistant.setDraft($event)\"\n [attachments]=\"assistant.attachments\"\n [files]=\"assistant.draftFiles()\"\n (filesChange)=\"assistant.setDraftFiles($event)\"\n [canSend]=\"assistant.canSend()\"\n [sending]=\"assistant.sending()\"\n (send)=\"assistant.send($event)\"\n (stop)=\"assistant.stop()\">\n </mm-assistant-composer>\n}\n","/*\n * Public API Surface of @meshmakers/shared-ui/assistant (AB#5621)\n */\n\n/**\n * The assistant side panel of the OctoMesh Refinery Studio as an app-agnostic building block:\n * panel (header, removable context chips, thread, composer with slash commands), proposal cards,\n * \"✦ Explain\" directives and the {@link AssistantService} state. It never answers by itself —\n * turns come from an {@link AssistantTransport} the host provides.\n *\n * Usage:\n *\n * ```ts\n * import { AssistantPanelComponent, AssistantService, ASSISTANT_ENABLED, ASSISTANT_TRANSPORT,\n * assistantHotkey } from '@meshmakers/shared-ui/assistant';\n *\n * // app.config.ts — off by default; without a transport the panel says \"backend not available\"\n * providers: [\n * { provide: ASSISTANT_ENABLED, useValue: true },\n * { provide: ASSISTANT_TRANSPORT, useExisting: MyChatTransport },\n * ]\n *\n * // AppComponent\n * template: `@if (assistant.enabled && assistant.isOpen()) { <mm-assistant-panel /> }`\n * @HostListener('document:keydown', ['$event'])\n * onKeydown(event: KeyboardEvent): void {\n * if (this.assistant.enabled && assistantHotkey(event)) { event.preventDefault(); this.assistant.toggle(); }\n * }\n * ```\n *\n * Wire the top bar toggle of `@meshmakers/shared-ui/shell` with\n * `[assistantAvailable]=\"assistant.enabled\" [assistantOpen]=\"assistant.isOpen()\" (assistantToggle)=\"assistant.toggle()\"`.\n * Proposal decisions (Run / Edit / Discard) are only published on `AssistantService.proposalDecisions$`.\n *\n * Tokens:\n * - `ASSISTANT_ENABLED` (default `false`) — the single feature flag;\n * - `ASSISTANT_TRANSPORT` (default {@link NotConnectedAssistantTransport}) — where turns come from;\n * - `ASSISTANT_PAGE_CONTEXT` (optional) — area/tab labels for the page chip;\n * - `ASSISTANT_TOOL_CALL_COMPONENT` (default {@link AssistantToolCallRowComponent}) — tool-call renderer\n * (OctoMesh hosts: `AiToolCallComponent` of `@meshmakers/octo-ai-console`);\n * - `ASSISTANT_SLASH_COMMANDS` (default {@link DEFAULT_ASSISTANT_SLASH_COMMANDS}) — composer commands; a\n * command with `expand(command, args)` is sent (and shown) as the prompt it returns (AB#5621);\n * - `ASSISTANT_PANEL_OPTIONS` (optional) — panel layout: `mode` (`docked` | `overlay`), `resizable` (off by default),\n * `minWidth` / `maxWidth`, `storageKey` of the persisted width (AB#5621);\n * - `ASSISTANT_MESSAGES` — translations (`Partial<AssistantMessages>`; component `messages` inputs win).\n *\n * Requires the `marked` package (markdown of assistant turns).\n *\n * The startup-needed, `marked`-free part (service, hotkey, tokens, transports, models, messages,\n * Explain directives) lives in `@meshmakers/shared-ui/assistant-core` and is re-exported here with\n * the same identity. Import from `assistant-core` in eagerly loaded code and load the panel lazily.\n * {@link FakeAssistantTransport} is a scriptable transport for host specs.\n *\n * Optional transport capabilities (AB#5621) — the panel adds UI only for what the transport has:\n * `sessions` + `loadSession` (+ `refreshSessions`, `deleteSession`, `newSession`, `activeSessionId`)\n * → \"New chat\" / \"Chats\" list; `attachments` → composer file picker, files on\n * `AssistantSendRequest.files`; `starterQuestions()` → clickable questions on an empty thread.\n */\n\n// Startup part — re-exported from assistant-core so tokens and classes keep a single identity.\nexport {\n ASSISTANT_ENABLED,\n ASSISTANT_TRANSPORT,\n ASSISTANT_PAGE_CONTEXT,\n ASSISTANT_TOOL_CALL_COMPONENT,\n ASSISTANT_SLASH_COMMANDS,\n DEFAULT_ASSISTANT_SLASH_COMMANDS,\n ASSISTANT_PANEL_OPTIONS,\n DEFAULT_ASSISTANT_PANEL_MIN_WIDTH,\n DEFAULT_ASSISTANT_PANEL_MAX_WIDTH,\n DEFAULT_ASSISTANT_PANEL_STORAGE_KEY,\n DEFAULT_ASSISTANT_MESSAGES,\n ASSISTANT_MESSAGES,\n resolveAssistantMessages,\n formatAssistantMessage,\n proposalDecisionLabel,\n AssistantService,\n assistantHotkey,\n NotConnectedAssistantTransport,\n ASSISTANT_NOT_CONNECTED_MESSAGE,\n FakeAssistantTransport,\n deriveAssistantContext,\n selectAssistantAttachments,\n assistantFileAccepted,\n formatAssistantFileSize,\n AssistantToolCallRowComponent,\n IfAssistantDirective,\n AssistantExplainDirective,\n} from '@meshmakers/shared-ui/assistant-core';\nexport type {\n AssistantTransportStatus,\n AssistantContextKind,\n AssistantContextChip,\n AssistantExplainTarget,\n AssistantOpenRequest,\n AssistantProposal,\n AssistantToolCall,\n AssistantPageContext,\n AssistantThreadItem,\n AssistantProposalDecisionKind,\n AssistantProposalDecision,\n AssistantSendRequest,\n AssistantStreamEvent,\n AssistantTransport,\n AssistantSlashCommand,\n AssistantMessages,\n AssistantContextSource,\n AssistantAttachmentRef,\n AssistantAttachmentOptions,\n AssistantSessionSummary,\n AssistantStarterQuestions,\n AssistantAsyncResult,\n AssistantAttachmentSelection,\n AssistantPanelOptions,\n AssistantPanelMode,\n} from '@meshmakers/shared-ui/assistant-core';\n\n// --- Markdown (needs `marked`) ---\nexport { renderAssistantMarkdown, classifyAssistantHref, AssistantMarkdownPipe } from './assistant-markdown';\n\n// --- Panel components ---\nexport { AssistantPanelComponent } from './panel/assistant-panel.component';\nexport { AssistantComposerComponent } from './composer/assistant-composer.component';\nexport { AssistantThreadComponent } from './thread/assistant-thread.component';\nexport { AssistantProposalCardComponent } from './proposal-card/assistant-proposal-card.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|