@c8y/ngx-components 1023.79.1 → 1023.80.2

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.
Files changed (34) hide show
  1. package/ai/agent-chat/index.d.ts +22 -11
  2. package/ai/agent-chat/index.d.ts.map +1 -1
  3. package/ai/ai-chat/index.d.ts +30 -9
  4. package/ai/ai-chat/index.d.ts.map +1 -1
  5. package/ai/index.d.ts +64 -49
  6. package/ai/index.d.ts.map +1 -1
  7. package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs +235 -127
  8. package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs.map +1 -1
  9. package/fesm2022/c8y-ngx-components-ai-ai-chat.mjs +104 -44
  10. package/fesm2022/c8y-ngx-components-ai-ai-chat.mjs.map +1 -1
  11. package/fesm2022/c8y-ngx-components-ai.mjs +92 -61
  12. package/fesm2022/c8y-ngx-components-ai.mjs.map +1 -1
  13. package/fesm2022/c8y-ngx-components-global-context.mjs +23 -3
  14. package/fesm2022/c8y-ngx-components-global-context.mjs.map +1 -1
  15. package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget-ai-config.mjs +31 -29
  16. package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget-ai-config.mjs.map +1 -1
  17. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-list.mjs +47 -8
  18. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-list.mjs.map +1 -1
  19. package/global-context/index.d.ts +17 -2
  20. package/global-context/index.d.ts.map +1 -1
  21. package/locales/de.po +3 -0
  22. package/locales/es.po +3 -0
  23. package/locales/fr.po +3 -0
  24. package/locales/ja_JP.po +3 -0
  25. package/locales/ko.po +3 -0
  26. package/locales/locales.pot +3 -0
  27. package/locales/nl.po +3 -0
  28. package/locales/pl.po +3 -0
  29. package/locales/pt_BR.po +3 -0
  30. package/locales/zh_CN.po +3 -0
  31. package/locales/zh_TW.po +3 -0
  32. package/package.json +1 -1
  33. package/widgets/implementations/datapoints-list/index.d.ts +5 -0
  34. package/widgets/implementations/datapoints-list/index.d.ts.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"c8y-ngx-components-ai-ai-chat.mjs","sources":["../../ai/ai-chat/ai-chat-tool-call.component.ts","../../ai/ai-chat/ai-chat-tool-call.component.html","../../ai/ai-chat/ai-chat-assistant-part.component.ts","../../ai/ai-chat/ai-chat-assistant-part.component.html","../../ai/ai-chat/ai-chat-assistant-message.component.ts","../../ai/ai-chat/ai-chat-assistant-message.component.html","../../ai/ai-chat/ai-chat-message-action.component.ts","../../ai/ai-chat/ai-chat-message-action.component.html","../../ai/ai-chat/ai-chat-message.component.ts","../../ai/ai-chat/ai-chat-message.component.html","../../ai/ai-chat/ai-chat-suggestion.component.ts","../../ai/ai-chat/ai-chat-suggestion.component.html","../../ai/ai-chat/ai-chat.component.ts","../../ai/ai-chat/ai-chat.component.html","../../ai/ai-chat/c8y-ngx-components-ai-ai-chat.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, input, signal, Type } from '@angular/core';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { ToolCallConfig, ToolCallPart } from '@c8y/ngx-components/ai';\nimport { C8yTranslateModule, C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport { JsonPipe, NgComponentOutlet } from '@angular/common';\nimport { TranslateService } from '@ngx-translate/core';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\n\n@Component({\n selector: 'c8y-ai-chat-tool-call',\n templateUrl: './ai-chat-tool-call.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n NgComponentOutlet,\n JsonPipe,\n C8yTranslatePipe,\n IconDirective,\n CollapseModule,\n C8yTranslateModule\n ]\n})\nexport class AiChatToolCallComponent {\n /**\n * The tool call part to render. This includes all information about the tool call, including the name of the tool,\n * the input provided and (once available) the output from the tool.\n */\n readonly tool = input.required<ToolCallPart>();\n\n /**\n * Whether the tool call is still in progress.\n */\n readonly isExecuting = input.required<boolean>();\n\n /**\n * A custom component to render the details of the tool call. If not provided, the default details section will be shown.\n */\n readonly toolDetailsComponent = input<Type<unknown> | undefined>(undefined);\n\n /**\n * Shows the default details section for a tool call.\n */\n readonly showDefaultToolDetails = input<boolean>(false);\n\n /**\n * The label to show while the tool is executing. If not provided, a default label will be generated based on the tool name.\n */\n readonly executingLabel = input<string | undefined>(undefined);\n /**\n * The label to show once the tool has completed. If not provided, a default label will be generated based on the tool name and whether the tool call was successful or resulted in an error.\n */\n readonly completedLabel = input<string | undefined>(undefined);\n\n /**\n * A function that can generate a label for this tool call based on the tool call data.\n */\n readonly labelProvider = input<ToolCallConfig['labelProvider']>();\n\n protected readonly expanded = signal(false);\n protected readonly everExpanded = signal(false);\n\n private readonly translateService = inject(TranslateService);\n\n getToolLabel(tool: ToolCallPart): string {\n const isExecuting = tool.type !== 'tool-result';\n if (this.labelProvider()) {\n try {\n const dynamicLabel = this.labelProvider()(tool, this.translateService);\n if (dynamicLabel) return dynamicLabel;\n } catch (err) {\n // Should never happen, report it then fall back to default logic\n console.error(`Error in labelProvider for tool ${tool.toolName}:`, err);\n }\n }\n\n if (isExecuting && this.executingLabel()) {\n return this.executingLabel();\n }\n if (!isExecuting && this.completedLabel()) {\n return this.completedLabel();\n }\n\n return this.translateService.instant(\n isExecuting ? gettext('Calling tool {{toolName}}') : gettext('Used tool {{toolName}}'),\n { toolName: tool.toolName }\n );\n }\n\n protected toggleExpanded(): void {\n const willExpand = !this.expanded();\n this.expanded.set(willExpand);\n if (willExpand) {\n this.everExpanded.set(true);\n }\n }\n}\n","@let _tool = tool();\n@let showDetails = showDefaultToolDetails();\n@let isToolExpanded = expanded();\n\n<fieldset\n class=\"c8y-fieldset p-b-4 ai-tool-call__fieldset\"\n [attr.aria-label]=\"'Tool call: ' + _tool.toolName\"\n>\n <button\n class=\"btn-clean ai-tool-call__btn\"\n [attr.aria-expanded]=\"showDetails ? isToolExpanded : null\"\n [attr.aria-controls]=\"showDetails ? 'tool-call-' + _tool.toolCallId : null\"\n type=\"button\"\n [attr.data-cy]=\"'tool-call-' + _tool.toolName\"\n [disabled]=\"!showDetails || null\"\n (click)=\"toggleExpanded()\"\n >\n @if (isExecuting()) {\n <i\n class=\"icon-spin icon-14 text-primary m-r-4\"\n c8yIcon=\"spinner\"\n aria-hidden=\"true\"\n ></i>\n } @else {\n <!-- Treat it as an error if a tool still thinks its executing when the message containing it is not -->\n @if (_tool.error || isExecuting()) {\n <i\n class=\"icon-14 text-danger m-r-4\"\n [c8yIcon]=\"'exclamation-circle'\"\n aria-hidden=\"true\"\n ></i>\n } @else {\n <i\n class=\"icon-14 text-success m-r-4\"\n [c8yIcon]=\"'check'\"\n aria-hidden=\"true\"\n ></i>\n }\n }\n <span class=\"small\">{{ getToolLabel(_tool) | translate }}</span>\n\n @if (showDetails) {\n <i\n class=\"m-l-4 icon-12\"\n [c8yIcon]=\"isToolExpanded ? 'collapse-arrow' : 'expand-arrow'\"\n aria-hidden=\"true\"\n ></i>\n }\n </button>\n\n <!-- If this is an artifact tool, render it - but do so lazily only on first open,\n since these components could be heavyweight (e.g. Monaco)\n -->\n @if (showDetails && (isToolExpanded || everExpanded())) {\n <div\n class=\"collapse tool-details m-t-8 p-8 b-r-4\"\n [attr.aria-label]=\"'Tool details for message latest tool: ' + _tool.toolName\"\n role=\"region\"\n [collapse]=\"!isToolExpanded\"\n [id]=\"'tool-call-' + _tool.toolCallId\"\n [isAnimated]=\"true\"\n data-cy=\"ai-tool-component\"\n >\n @if (toolDetailsComponent()) {\n <ng-container\n [ngComponentOutlet]=\"toolDetailsComponent()\"\n [ngComponentOutletInputs]=\"{ tool: _tool }\"\n ></ng-container>\n } @else {\n @let noneLabel = '(no data)' | translate;\n\n <p class=\"text-label-small\">{{ 'Tool input' | translate }}</p>\n <pre class=\"fit-w small\">{{ _tool.input || noneLabel | json }}</pre>\n\n @if (_tool.type === 'tool-result') {\n <p class=\"text-label-small\">{{ 'Tool output' | translate }}</p>\n @if (\n typeof _tool.output === 'string' || _tool.output === undefined || _tool.output === null\n ) {\n <pre class=\"fit-w small\">{{ _tool.output || noneLabel }}</pre>\n } @else {\n <pre class=\"fit-w small\">{{ _tool.output | json }}</pre>\n }\n }\n }\n </div>\n }\n</fieldset>\n","import { ChangeDetectionStrategy, Component, input, signal } from '@angular/core';\nimport { AIMessagePart } from '@c8y/ngx-components/ai';\nimport {\n C8yTranslateDirective,\n C8yTranslatePipe,\n IconDirective,\n MarkdownToHtmlPipe\n} from '@c8y/ngx-components';\nimport { AsyncPipe, NgComponentOutlet } from '@angular/common';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\nimport { AssistantMessageContext } from './ai-chat-assistant-message.component';\nimport { AiChatToolCallComponent } from './ai-chat-tool-call.component';\n\n/** This renders a part of an assistant message. Currently only ToolCallPart is supported, but later we can expand this to deal with all part types. */\n@Component({\n selector: 'c8y-ai-chat-assistant-part',\n templateUrl: './ai-chat-assistant-part.component.html',\n standalone: true,\n imports: [\n NgComponentOutlet,\n C8yTranslateDirective,\n C8yTranslatePipe,\n IconDirective,\n CollapseModule,\n MarkdownToHtmlPipe,\n AsyncPipe,\n AiChatToolCallComponent\n ],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AiChatAssistantPartComponent {\n readonly part = input.required<AIMessagePart>();\n\n /** Whether this part is rendered as part of the main answer, or is an intermediate step with more muted rendering. */\n readonly displayAsPartOfMainAnswer = input(true);\n\n /**\n * The context needed to render a message.\n * This is a single input so we can extend in future without breaking people who have a custom rendering implementation.\n */\n readonly assistantMessageContext = input.required<AssistantMessageContext>();\n\n /** Tracks whether this is currently expanded (used for reasoning section). */\n protected readonly expanded = signal(false);\n\n protected toggleExpanded(): void {\n this.expanded.update(v => !v);\n }\n}\n","@let ctx = assistantMessageContext();\n@let _config = ctx.config;\n@let toolCallConfig = _config.toolCallConfig || {};\n@let _part = part();\n\n@if (_part.type === 'text') {\n <p\n [class.text-muted]=\"!displayAsPartOfMainAnswer()\"\n [innerHTML]=\"_part.text | markdownToHtml | async\"\n ></p>\n} @else if (_part.type === 'reasoning') {\n @let reasoningExpanded = expanded();\n\n <fieldset\n class=\"c8y-fieldset p-b-4 ai-tool-call__fieldset\"\n data-cy=\"ai-reasoning\"\n >\n <button\n class=\"btn-clean ai-tool-call__btn\"\n aria-label=\"{{ 'Toggle display of the reasoning section' | translate }}\"\n [attr.aria-expanded]=\"reasoningExpanded\"\n [attr.aria-controls]=\"'reasoning-content-message' + ctx.messageDisplayIndex\"\n type=\"button\"\n (click)=\"toggleExpanded()\"\n >\n <i\n class=\"m-r-4\"\n [c8yIcon]=\"'ai-sparkles'\"\n ></i>\n @let hideReasoning = 'Hide reasoning' | translate;\n @let showReasoning = 'Show reasoning' | translate;\n <span class=\"small\">{{ reasoningExpanded ? hideReasoning : showReasoning }}</span>\n <i\n class=\"m-l-4 icon-12 text-muted\"\n [c8yIcon]=\"reasoningExpanded ? 'collapse-arrow' : 'expand-arrow'\"\n ></i>\n </button>\n\n @let ariaLabel =\n 'Reasoning for message number {{ number }}' | translate: { number: ctx.messageDisplayIndex };\n <div\n class=\"collapse reasoning-content\"\n [attr.aria-label]=\"ariaLabel\"\n role=\"region\"\n [collapse]=\"!reasoningExpanded\"\n [id]=\"'reasoning-content-message' + ctx.messageDisplayIndex\"\n [isAnimated]=\"true\"\n data-cy=\"ai-reasoning-content\"\n >\n <div\n class=\"m-t-8 p-b-4 text-muted\"\n [innerHTML]=\"_part.text | markdownToHtml | async\"\n ></div>\n </div>\n </fieldset>\n} @else if (_part.type === 'step-start') {\n <!-- Visually hidden label included when users copy-paste from the chat, e.g. to report issues -->\n <span\n class=\"ai-step-start hidden-copy-label\"\n aria-hidden=\"true\"\n data-cy=\"ai-step-start-separator\"\n translate\n >--- (step separator) ---</span\n >\n} @else if (_part.type.startsWith('tool')) {\n @let tool = $any(_part);\n @let toolDisplay = toolCallConfig[tool.toolName];\n\n <!-- Visually hidden label included when users copy-paste from the chat, e.g. to report issues -->\n <span\n class=\"hidden-copy-label\"\n aria-hidden=\"true\"\n translate\n [translateParams]=\"{ toolName: tool.toolName }\"\n ngNonBindable\n >--- Tool call: {{ toolName }} ---</span\n >\n\n @if (toolDisplay?.component) {\n <div data-cy=\"ai-tool-with-custom-component\">\n <ng-container\n [ngComponentOutlet]=\"toolDisplay.component\"\n [ngComponentOutletInputs]=\"{\n tool: tool,\n ctx: ctx\n }\"\n ></ng-container>\n </div>\n } @else if (!toolDisplay?.isHidden) {\n <!-- Don't allow expanding while tool call is in progress - it's unlikely to have anything worth rendering,\n and complicates implementation for the client to have to check for the isExecuting case.\n -->\n <c8y-ai-chat-tool-call\n [tool]=\"tool\"\n [isExecuting]=\"tool.type !== 'tool-result' && ctx.isMessageLoading\"\n [toolDetailsComponent]=\"_config.toolDetailsComponent?.(tool)\"\n [showDefaultToolDetails]=\"_config.showDefaultToolDetails === 'all'\"\n [executingLabel]=\"toolDisplay?.executingLabel\"\n [completedLabel]=\"toolDisplay?.completedLabel\"\n [labelProvider]=\"toolDisplay?.labelProvider\"\n ></c8y-ai-chat-tool-call>\n }\n}\n","import { Component, effect, inject, input, signal } from '@angular/core';\nimport { C8yTranslateModule, C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport {\n AgentStep,\n AIMessage,\n AssistantMessageDisplayConfig,\n ToolCallPart\n} from '@c8y/ngx-components/ai';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { TranslateService } from '@ngx-translate/core';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\nimport { AiChatAssistantPartComponent } from './ai-chat-assistant-part.component';\n\n/**\n * Context object which includes the inputs needed for assistant message rendering.\n * If creating a custom component for assistant message rendering, you will receive this as an input.\n */\nexport interface AssistantMessageContext {\n message: AIMessage;\n config: AssistantMessageDisplayConfig;\n\n /** The message response is currently streaming in (not yet complete). */\n isMessageLoading: boolean;\n\n /** A number identifying this message in the chat history numbered from the latest - 0 is the latest, -1 is the previous, etc. */\n messageDisplayIndex: number;\n}\n\n/**\n * This is the default component used to render the contents of a message from the AI assistant, including\n * the main answer text, text from earlier steps, reasoning text and tool calls.\n */\n@Component({\n selector: 'c8y-ai-chat-assistant-message',\n templateUrl: './ai-chat-assistant-message.component.html',\n standalone: true,\n imports: [\n C8yTranslatePipe,\n IconDirective,\n CollapseModule,\n C8yTranslateModule,\n AiChatAssistantPartComponent\n ]\n})\nexport class AiChatAssistantMessageComponent {\n /**\n * The context needed to render a message.\n * This is a single input so we can extend in future without breaking people who have a custom rendering implementation.\n */\n readonly assistantMessageContext = input.required<AssistantMessageContext>();\n\n /**\n * By default this component will render a \"Working...\" indicator while streaming results. This input can turn that off if required.\n */\n readonly showWorkingIndicator = input(true);\n\n /**\n * Whether the thinking section is expanded. Initialized to false unless the message is still loading.\n * Call setThinkingExpanded() via viewChild to control this programmatically. Does nothing if appearance does not distinguish thinking steps.\n */\n protected readonly thinkingExpanded = signal(false);\n\n /**\n * Tracks which reasoning sections are expanded, keyed by step index.\n */\n protected readonly expandedReasoningStepIndices = signal(new Set<number>());\n\n private readonly translateService = inject(TranslateService);\n\n /**\n * For now be conservative with the old behaviour, but hope to change this once we've got working really smoothly.\n */\n protected readonly defaultNonFinalStepTextDisplay: AssistantMessageDisplayConfig['experimental_nonFinalStepTextDisplay'] =\n 'main-answer';\n\n constructor() {\n // Expand when we initially set the message loading flag, without overwriting the value\n // any other time\n effect(() => {\n if (this.assistantMessageContext().isMessageLoading) {\n this.thinkingExpanded.set(true);\n }\n });\n }\n\n /**\n * This is public and exists for agent-chat to collapse older messages.\n * @param expanded Whether the thinking section should be expanded or not.\n */\n setThinkingExpanded(expanded: boolean): void {\n this.thinkingExpanded.set(expanded);\n }\n\n /**\n * Get a translated/translateable label for the specified tool.\n * @param tool The tool call part to get the label for.\n * @return The label to show for this tool call.\n */\n getToolLabel(tool: ToolCallPart): string {\n const isExecuting = tool.type !== 'tool-result';\n const config = this.assistantMessageContext().config;\n const toolCallConfig = config?.toolCallConfig?.[tool.toolName];\n if (toolCallConfig?.labelProvider) {\n try {\n const dynamicLabel = toolCallConfig.labelProvider(tool, this.translateService);\n // Run it through translate in case it contains gettext values\n if (dynamicLabel) return dynamicLabel;\n } catch (err) {\n // Should never happen, so report this - then fallback to default logic\n console.warn(`Error in labelProvider for tool ${tool.toolName}:`, err);\n }\n }\n\n if (isExecuting && toolCallConfig?.executingLabel) {\n return toolCallConfig.executingLabel;\n }\n if (!isExecuting && toolCallConfig?.completedLabel) {\n return toolCallConfig.completedLabel;\n }\n\n // If we have no specific label configured, use the default\n return this.translateService.instant(\n isExecuting ? gettext('Calling tool {{toolName}}') : gettext('Used tool {{toolName}}'),\n // Have to use the tool id since that's all we have\n { toolName: tool.toolName }\n );\n }\n\n protected getToolParts(step: AgentStep): ToolCallPart[] {\n // This method only exists because of the current structure of AIMessage; can remove this when we refactor\n return [...(step.toolCalls || []), ...(step.toolResults || [])];\n }\n\n protected toggleReasoningExpanded(stepIndex: number): void {\n this.expandedReasoningStepIndices.update(s => {\n const next = new Set(s);\n s.has(stepIndex) ? next.delete(stepIndex) : next.add(stepIndex);\n return next;\n });\n }\n\n /**\n * Note: ctx is passed as a parameter rather than reading the signal in the template to ensure\n * it's totally aligned with what the template is rendering.\n * @param ctx The context for the assistant message.\n * @return The label to display for the reasoning section.\n */\n protected getThinkingLabel(ctx: AssistantMessageContext): string {\n return ctx.isMessageLoading\n ? gettext('Reasoning')\n : this.thinkingExpanded()\n ? gettext('Hide reasoning')\n : gettext('Show reasoning');\n }\n\n protected getMainAnswerText(ctx: AssistantMessageContext): string {\n // If it's a simple plain message, do nothing\n if (!ctx.message.steps) return ctx.message.content;\n\n // Get the latest (non-empty) step text (the final one can occasionally be empty it seems)\n const lastStepWithText = ctx.message.steps.filter(step => step?.text && step.text !== '').pop();\n const lastStepText = lastStepWithText?.text || '';\n\n // The final step text goes in the main answer area if there are no pending tool calls (since otherwise the tools would show below it), and\n // message has finished loading, or we're expecting more steps than this.\n // Note that we check all steps for toolCalls not just the current one, for the sake of \"fake\" tool calls created by preprocessAgentMessage\n // where additional step boundaries may be added to simplify parsing.\n if (\n lastStepText &&\n !ctx.message.steps.some(step => step.toolCalls) &&\n !lastStepWithText?.toolResults &&\n (!ctx.isMessageLoading ||\n ctx.message.steps.length >= (ctx.config?.experimental_expectedStepCount || 2))\n ) {\n return lastStepText;\n }\n return '';\n }\n\n protected hasThinkingContent(ctx: AssistantMessageContext, mainAnswer: string): boolean {\n // This logic matches the rendering in the template to ensure we don't show an empty thinking section\n if (!ctx.message?.steps) return false;\n\n const result = ctx.message.steps.some(\n step =>\n (step.text && step.text !== mainAnswer) ||\n step.reasoning ||\n [...(step.toolResults || []), ...(step.toolCalls || [])].some(\n tool =>\n !ctx.config?.toolCallConfig ||\n (!ctx.config?.toolCallConfig[tool.toolName]?.isHidden &&\n !ctx.config?.toolCallConfig[tool.toolName]?.isShownWithMainAnswer)\n )\n );\n return result;\n }\n}\n","@let ctx = assistantMessageContext();\n@let steps = ctx.message.steps ?? [{ type: 'text', text: ctx.message.content }];\n@let _config = ctx.config;\n\n<!-- NB: be sure to update hasThinkingContent() if changing the anything that affects what content \nis rendered in the thinking area.\n-->\n\n<!-- \nWe show the assistant message in (up to) 3 slots:\n- collapsible thinking block (for intermediate step text, standard tool calls, etc)\n- special \"artifact\" tools that update user artifacts and need prominent display (e.g. for code edits made by the AI)\n- the main answer (typically from the final step)\n\nThis is a standard approach for AI chats - step text and tools from an LLM are treated as a work log, i.e. useful to \ndisplay progress while streaming the response, but only the text from the last step after all tool calls gives the main answer of the AI to the user. \n\nDepending on configuration, we have an experimental option (if we need it) to style the thinking block the same as the main answer. \n\nOnce the message finishes loading we know the final step IS the main content, but if it's still steaming \nwe don't know for sure which step has the final/main answer until the LLM has actually finished so have to take a heuistic guess \n(and minimize jumping in the UI). \n\nFor applications where we expect tool calls in most responses, assume the 2nd step is probably the final text; \nfor applications where tool calls are less ubiquitous, assume the first step is main answer until proved otherwise. \nThis minimizes jumping (except when there are >2 steps, which is rare).\n\n-->\n\n@let mainAnswer = getMainAnswerText(ctx);\n\n<!-- Thinking steps section - holds reasoning, text from non-final steps, and standard/non-artifact tool calls -->\n\n@if (hasThinkingContent(ctx, mainAnswer)) {\n @let nonFinalStepTextDisplay =\n _config?.experimental_nonFinalStepTextDisplay || defaultNonFinalStepTextDisplay;\n <div\n class=\"m-b-8\"\n [class.thinking-block]=\"nonFinalStepTextDisplay === 'collapsible-thinking-block'\"\n [class.text-muted]=\"nonFinalStepTextDisplay !== 'main-answer'\"\n [class.small]=\"nonFinalStepTextDisplay === 'muted-main-answer'\"\n [class.thinking-steps-appearance]=\"nonFinalStepTextDisplay\"\n data-cy=\"thinking-steps\"\n >\n @if (nonFinalStepTextDisplay === 'collapsible-thinking-block') {\n <button\n class=\"btn btn-clean btn-xs text-muted p-l-0\"\n aria-label=\"{{ 'Toggle collapse of the reasoning section' | translate }}\"\n [attr.aria-expanded]=\"thinkingExpanded()\"\n [attr.aria-controls]=\"'thinking-content-' + ctx.messageDisplayIndex\"\n type=\"button\"\n (click)=\"thinkingExpanded.set(!thinkingExpanded())\"\n >\n <span class=\"small\">{{ getThinkingLabel(ctx) }}</span>\n <i\n class=\"m-l-4 icon-12\"\n [c8yIcon]=\"thinkingExpanded() ? 'collapse-arrow' : 'expand-arrow'\"\n ></i>\n </button>\n }\n\n @let ariaLabel =\n 'Reasoning for message number {{ number }}' | translate: { number: ctx.messageDisplayIndex };\n <div\n class=\"collapse\"\n [attr.aria-label]=\"ariaLabel\"\n role=\"region\"\n [collapse]=\"nonFinalStepTextDisplay === 'collapsible-thinking-block' && !thinkingExpanded()\"\n [id]=\"'thinking-content-' + ctx.messageDisplayIndex\"\n [isAnimated]=\"true\"\n >\n <div\n [class]=\"\n nonFinalStepTextDisplay === 'collapsible-thinking-block'\n ? 'thinking-content bg-level-1 m-t-8 p-8 b-r-4 border-left-accent small m-b-0 text-muted'\n : ''\n \"\n >\n @for (step of steps; track $index) {\n <c8y-ai-chat-assistant-part\n [part]=\"{ type: 'step-start' }\"\n [assistantMessageContext]=\"ctx\"\n ></c8y-ai-chat-assistant-part>\n\n <!-- Non-final step text: avoid duplicating the final message content since we show that below -->\n @if (step.text && step.text !== mainAnswer) {\n <c8y-ai-chat-assistant-part\n [part]=\"{ type: 'text', text: step.text }\"\n [assistantMessageContext]=\"ctx\"\n [displayAsPartOfMainAnswer]=\"nonFinalStepTextDisplay !== 'muted-main-answer'\"\n ></c8y-ai-chat-assistant-part>\n }\n\n <!-- Expandable section for reasoning (only some models provide this). Collapse by default. -->\n @if (step.reasoning) {\n <c8y-ai-chat-assistant-part\n [part]=\"{ type: 'reasoning', text: step.reasoning }\"\n [assistantMessageContext]=\"ctx\"\n [displayAsPartOfMainAnswer]=\"nonFinalStepTextDisplay !== 'muted-main-answer'\"\n ></c8y-ai-chat-assistant-part>\n }\n\n @for (tool of getToolParts(step); track tool.toolCallId) {\n @if (!ctx.config.toolCallConfig?.[tool.toolName]?.isShownWithMainAnswer) {\n <c8y-ai-chat-assistant-part\n [part]=\"tool\"\n [assistantMessageContext]=\"ctx\"\n ></c8y-ai-chat-assistant-part>\n }\n }\n }\n </div>\n </div>\n </div>\n}\n\n<c8y-ai-chat-assistant-part\n [part]=\"{ type: 'step-start' }\"\n [assistantMessageContext]=\"ctx\"\n></c8y-ai-chat-assistant-part>\n\n<!-- Show tools which generate artifacts/outputs the user cares about in a dedicated area (outside the thinking section, never muted) -->\n\n<span data-cy=\"ai-tools-with-main-answer\">\n @for (step of steps; track $index) {\n @for (tool of getToolParts(step); track tool.toolCallId) {\n @if (ctx.config.toolCallConfig?.[tool.toolName]?.isShownWithMainAnswer) {\n <c8y-ai-chat-assistant-part\n [part]=\"tool\"\n [assistantMessageContext]=\"ctx\"\n ></c8y-ai-chat-assistant-part>\n }\n }\n }\n</span>\n\n<!-- Main/final text from the final step goes here -->\n@if (mainAnswer) {\n <div\n class=\"message-content m-t-8 text-default ai-main-answer-content\"\n data-cy=\"ai-main-message-content\"\n >\n <c8y-ai-chat-assistant-part\n [part]=\"{ type: 'text', text: mainAnswer }\"\n [assistantMessageContext]=\"ctx\"\n [displayAsPartOfMainAnswer]=\"true\"\n ></c8y-ai-chat-assistant-part>\n </div>\n}\n\n@if (ctx.isMessageLoading && showWorkingIndicator()) {\n <!-- Once the message starts to stream, show a small/low-key thinking indicator -->\n <div\n class=\"text-muted text-12 fade-in-out d-flex j-c-end\"\n aria-live=\"polite\"\n role=\"status\"\n data-cy=\"working-indicator\"\n >\n {{ 'Working…' | translate }}\n </div>\n}\n","import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport { SupportedIconsSuggestions } from '@c8y/ngx-components/icon-selector/icons';\nimport { TooltipModule } from 'ngx-bootstrap/tooltip';\n\n/**\n * An action button that can be added to chat messages.\n * Typically used for actions like copying, regenerating, or providing feedback on messages.\n */\n@Component({\n selector: 'c8y-ai-chat-message-action',\n templateUrl: './ai-chat-message-action.component.html',\n standalone: true,\n imports: [TooltipModule, C8yTranslatePipe, IconDirective]\n})\nexport class AiChatMessageActionComponent {\n /**\n * Set to true to use content projection for custom action button content.\n */\n @Input()\n custom = false;\n\n /**\n * Disables the action button when true.\n */\n @Input()\n disabled = false;\n\n /**\n * Tooltip text displayed when hovering over the action button.\n */\n @Input()\n tooltip = '';\n\n /**\n * Icon to display in the action button.\n */\n @Input()\n icon: SupportedIconsSuggestions = 'cog';\n\n /**\n * Emitted when the action button is clicked.\n */\n @Output()\n actionClicked = new EventEmitter<void>();\n}\n","@if (!custom) {\n <button\n class=\"btn btn-dot text-muted\"\n [attr.aria-label]=\"tooltip | translate\"\n [tooltip]=\"tooltip | translate\"\n [adaptivePosition]=\"true\"\n [delay]=\"500\"\n (click)=\"actionClicked.emit()\"\n [disabled]=\"disabled\"\n >\n <i\n class=\"text-12\"\n [c8yIcon]=\"icon\"\n ></i>\n </button>\n} @else {\n <ng-content></ng-content>\n}\n","import { Component, computed, input, inject } from '@angular/core';\n\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { AIMessage } from '@c8y/ngx-components/ai';\nimport { C8yTranslatePipe, DatePipe } from '@c8y/ngx-components';\nimport { NgClass } from '@angular/common';\nimport { TooltipModule } from 'ngx-bootstrap/tooltip';\nimport { TranslateService } from '@ngx-translate/core';\n\n/**\n * A container for content and actions that should be rendered for each chat message.\n *\n * Project content into this component to display the message, for example add an `<ai-chat-assistant-message>`\n * for assistant messages, and a simple `markdownToHtml | async` rendering of the content for user messages.\n */\n@Component({\n selector: 'c8y-ai-chat-message',\n templateUrl: './ai-chat-message.component.html',\n styleUrl: './ai-chat-message.component.scss',\n standalone: true,\n imports: [NgClass, TooltipModule, C8yTranslatePipe, DatePipe]\n})\nexport class AiChatMessageComponent {\n readonly role = input<AIMessage['role']>();\n readonly message = input<AIMessage>();\n\n private readonly translateService = inject(TranslateService);\n\n private readonly roleResolved = computed(() => {\n return this.message()?.role || this.role();\n });\n\n /**\n * Generates an accessible label for the message container.\n * Includes the role (user or assistant) and timestamp if available.\n * @returns The aria-label string for screen readers\n */\n readonly ariaLabel = computed(() => {\n const tpl =\n this.roleResolved() === 'user'\n ? gettext('You said: \"{{ message }}\"')\n : gettext('Assistant said: \"{{ message }}\"');\n const msg = this.message();\n return this.translateService.instant(tpl, { message: msg?.content || gettext('No response.') });\n });\n\n /**\n * Generates an accessible label for the message content.\n * Prefixes the content with contextual information about who sent it.\n * @returns The aria-label string with prefixed role information\n */\n readonly messageContentAriaLabel = computed(() => {\n const msg = this.message();\n const time = msg?.timestamp ? new Date(msg.timestamp).toLocaleTimeString() : '';\n let tpl: string;\n if (time) {\n tpl =\n this.roleResolved() === 'user'\n ? gettext('User message at {{ time }}')\n : gettext('Assistant message at {{ time }}');\n } else {\n tpl = this.roleResolved() === 'user' ? gettext('User message') : gettext('Assistant message');\n }\n return this.translateService.instant(tpl, { time });\n });\n}\n","<div\n class=\"d-col p-t-16\"\n [attr.aria-label]=\"ariaLabel()\"\n role=\"article\"\n>\n <div\n class=\"chat-message text-break-word\"\n [ngClass]=\"{\n 'user-message': message()?.role === 'user' || role() === 'user',\n 'agent-message': message()?.role === 'assistant' || role() === 'assistant'\n }\"\n >\n <!-- Visually hidden label included when users copy-paste from the chat, e.g. to report issues -->\n <span\n class=\"hidden-copy-label\"\n aria-hidden=\"true\"\n >\n {{ `====== ${messageContentAriaLabel()} ======` }}</span\n >\n\n <!-- Apply the class and aria-label to both the main content and whatever is projected, so we get the same styling by default -->\n <div\n class=\"message-content\"\n [attr.aria-label]=\"messageContentAriaLabel()\"\n >\n <div style=\"display: contents\">\n <ng-content select=\":not(c8y-ai-chat-message-action)\"></ng-content>\n </div>\n </div>\n @if (message()?.timestamp) {\n <div class=\"message-timestamp\">\n <span [tooltip]=\"message()?.timestamp | c8yDate\">\n {{ message()?.timestamp | c8yDate: 'adaptiveDate' }}\n </span>\n </div>\n }\n </div>\n <div\n class=\"message-action\"\n [attr.aria-label]=\"'Message actions' | translate\"\n role=\"toolbar\"\n [ngClass]=\"{\n 'user-action showOnHover': message()?.role === 'user' || role() === 'user',\n 'agent-action p-l-16': message()?.role === 'assistant' || role() === 'assistant'\n }\"\n >\n <ng-content select=\"c8y-ai-chat-message-action\"></ng-content>\n </div>\n</div>\n","import { Component, input, output } from '@angular/core';\nimport { C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport { AIMessage } from '@c8y/ngx-components/ai';\nimport { SupportedIconsSuggestions } from '@c8y/ngx-components/icon-selector/icons';\n\n/**\n * A suggestion chip that can be displayed in the chat interface.\n * When clicked, it automatically populates and sends a predefined prompt.\n */\n@Component({\n selector: 'c8y-ai-chat-suggestion',\n templateUrl: './ai-chat-suggestion.component.html',\n host: { class: 'd-contents' },\n standalone: true,\n imports: [IconDirective, C8yTranslatePipe]\n})\nexport class AiChatSuggestionComponent {\n /**\n * The visible label text displayed on the suggestion chip.\n */\n readonly label = input.required<string>();\n\n /**\n * The prompt text that will be sent when the suggestion is clicked.\n */\n readonly prompt = input.required<string>();\n\n /**\n * Icon to display alongside the suggestion label.\n */\n readonly icon = input<SupportedIconsSuggestions>('c8y-bulb');\n\n /**\n * When true, uses AI-styled buttons instead of default styling.\n */\n readonly useAiButtons = input(false);\n\n /**\n * Disables the suggestion chip when true.\n */\n readonly disabled = input(false);\n\n /**\n * Emitted when the suggestion is clicked, providing the prompt as an AIMessage.\n */\n readonly suggestionClicked = output<AIMessage>();\n\n /**\n * Handles suggestion click and emits the prompt as a user message.\n */\n suggest() {\n this.suggestionClicked.emit({\n content: this.prompt(),\n role: 'user',\n timestamp: new Date().toISOString()\n });\n }\n}\n","@if (!useAiButtons()) {\n <button\n class=\"btn btn-default btn-sm\"\n [title]=\"prompt() | translate\"\n (click)=\"suggest()\"\n [disabled]=\"disabled()\"\n >\n <i [c8yIcon]=\"icon()\"></i>\n {{ label() | translate }}\n </button>\n} @else {\n <button\n class=\"btn btn-sm btn-ai\"\n [title]=\"prompt() | translate\"\n (click)=\"suggest()\"\n [disabled]=\"disabled()\"\n >\n <span>{{ label() | translate }}</span>\n </button>\n}\n","import { AsyncPipe, NgClass, NgTemplateOutlet } from '@angular/common';\nimport {\n Component,\n contentChildren,\n effect,\n ElementRef,\n EventEmitter,\n Input,\n Output,\n TemplateRef,\n viewChild\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n C8yTranslatePipe,\n IconDirective,\n MarkdownToHtmlPipe,\n TextareaAutoresizeDirective\n} from '@c8y/ngx-components';\nimport { AIMessage, ChatConfig } from '@c8y/ngx-components/ai';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { AiChatMessageComponent } from './ai-chat-message.component';\n\n/**\n * An interactive chat interface component for AI-powered conversations.\n * Displays messages in a conversation format with support for loading states,\n * custom configuration, and markdown formatting.\n */\n@Component({\n selector: 'c8y-ai-chat',\n templateUrl: './ai-chat.component.html',\n imports: [\n C8yTranslatePipe,\n FormsModule,\n TextareaAutoresizeDirective,\n IconDirective,\n NgClass,\n NgTemplateOutlet,\n MarkdownToHtmlPipe,\n AsyncPipe\n ],\n standalone: true,\n host: { class: 'd-contents' }\n})\nexport class AiChatComponent {\n /**\n * Indicates whether the chat is currently processing a request.\n * When true, displays a cancel button instead of send button and disables the input.\n */\n @Input()\n isLoading = false;\n\n /**\n * Disables the chat input and send button when true.\n */\n @Input()\n disabled = false;\n\n /**\n * The current text in the chat input field. Supports two-way binding.\n */\n @Input()\n prompt = '';\n\n /**\n * Template for rendering custom suggestions below the input field. Can be used to provide predefined prompts or actions\n * from a dynamic source such as the AI. To use this, wrap your suggestion components in an `<ng-template #suggestionsRef>`\n * (where `suggestionsRef` matches the suggestionsTemplate reference);\n */\n @Input()\n suggestionsTemplate?: TemplateRef<any>;\n\n /** Template for customizing the welcome view using `<ng-template>`. */\n @Input() welcomeTemplate?: TemplateRef<any>;\n\n /**\n * Emitted when the user sends a message.\n * Provides an AIMessage object with role, content, and timestamp.\n */\n @Output()\n onMessage = new EventEmitter<AIMessage>();\n\n /**\n * Emitted when the user cancels an ongoing operation during loading state.\n */\n @Output()\n onCancel = new EventEmitter<void>();\n\n /**\n * Child message components displayed in the chat.\n */\n readonly messages = contentChildren(AiChatMessageComponent);\n\n /**\n * Reference to the scroll container for the chat messages.\n */\n private readonly scrollContainer = viewChild<ElementRef<HTMLDivElement>>('chatScrollContainer');\n\n readonly componentId = `chat-${crypto.randomUUID()}`;\n\n private _config: ChatConfig = {\n headline: gettext('Welcome!'),\n welcomeText: '',\n welcomePosition: 'top',\n title: gettext('What can I help you with?'),\n placeholder: gettext('Type your message here...'),\n scrollbarOnlyOnHover: false,\n sendButtonText: gettext('Send'),\n cancelButtonText: gettext('Cancel'),\n disclaimerText: gettext(\n 'AI-generated responses can contain errors. Verify the details before use.'\n ),\n userInterfaceIcons: {\n send: 'arrow-circle-up',\n cancel: 'stop-circle'\n }\n };\n\n constructor() {\n // Auto-scroll to bottom when messages change\n effect(() => {\n this.messages(); // track changes\n const container = this.scrollContainer()?.nativeElement;\n if (!container) return;\n // In column-reverse, scrollTop=0 IS the visual bottom.\n // Only snap back if user is already near the bottom (wasn't scrolled up).\n if (container.scrollTop < 50) {\n container.scrollTop = 0;\n }\n });\n }\n\n /**\n * Configuration object for customizing labels, placeholders, and icons.\n * Accepts partial configuration to override defaults.\n * @param value Partial configuration to merge with defaults.\n * @returns The complete configuration object.\n */\n @Input()\n set config(value: Partial<ChatConfig>) {\n this._config = { ...this._config, ...value };\n }\n get config(): ChatConfig {\n return this._config;\n }\n\n /**\n * Handles message submission when the user sends a message.\n * Emits the onMessage event and clears the input.\n * @param $event The event object from the form submission\n */\n sendMessage($event: Event): void {\n $event.preventDefault();\n if (!this.prompt) return;\n this.onMessage.emit({\n role: 'user',\n content: this.prompt,\n timestamp: new Date().toISOString()\n });\n this.prompt = '';\n }\n\n /**\n * Handles cancellation of ongoing operations during loading state.\n * Emits the onCancel event.\n */\n cancel(): void {\n this.onCancel.emit();\n }\n}\n","<div\n class=\"d-col fit-h fit-w flex-grow\"\n [attr.aria-label]=\"config.headline | translate\"\n role=\"region\"\n>\n @if (messages().length > 0) {\n <div\n [attr.aria-label]=\"'Chat conversation' | translate\"\n aria-live=\"polite\"\n aria-atomic=\"false\"\n role=\"log\"\n #chatScrollContainer\n [ngClass]=\"{\n 'inner-scroll': true,\n 'd-col-reverse': true,\n 'scrollbar-only-on-hover': config.scrollbarOnlyOnHover,\n 'flex-grow': true,\n 'min-height-0': true,\n 'bg-level-0': true\n }\"\n >\n <div class=\"d-col p-l-16 p-r-16\">\n <ng-content select=\"[slot='before-messages']\"></ng-content>\n <ng-content select=\"c8y-ai-chat-message\"></ng-content>\n <ng-content select=\"[slot='after-messages']\"></ng-content>\n </div>\n </div>\n }\n <div\n [ngClass]=\"{\n 'd-col fit-h': messages().length === 0\n }\"\n >\n @if (messages().length === 0) {\n <div\n class=\"p-24 d-col fit-h inner-scroll\"\n aria-live=\"polite\"\n role=\"status\"\n [ngClass]=\"{\n 'j-c-start': config.welcomePosition === 'top',\n 'j-c-center': config.welcomePosition === 'center',\n 'j-c-end': config.welcomePosition === 'bottom'\n }\"\n >\n <h4 class=\"m-b-16 text-medium\">{{ config.headline | translate }}</h4>\n @if (config.title.length > 0) {\n <p class=\"p-b-8 text-balance\">{{ config.title | translate }}</p>\n }\n <div class=\"text-balance chat-message min-height-0\">\n <div\n class=\"text-muted\"\n [innerHTML]=\"config.welcomeText | translate | markdownToHtml | async\"\n ></div>\n @if (welcomeTemplate) {\n <ng-container *ngTemplateOutlet=\"welcomeTemplate\"></ng-container>\n }\n </div>\n </div>\n }\n <div\n class=\"chat-input\"\n [class.bg-level-1]=\"config.appearance !== 'flat'\"\n >\n <!-- For simple cases allow ng-content projection; however this doesn't seem to work with dynamic \n suggestion lists from a signal (e.g. returned from the AI) so also support `suggestionsTemplate` for that. \n -->\n @if (!isLoading) {\n <div\n [class]=\"\n 'd-flex inner-scroll gap-8 p-l-16 p-r-16 p-b-8 ' +\n (config.suggestionsLayout === 'vertical' ? 'flex-wrap' : 'a-i-center')\n \"\n >\n <ng-content select=\"c8y-ai-chat-suggestion\"></ng-content>\n\n @if (suggestionsTemplate) {\n <ng-container *ngTemplateOutlet=\"suggestionsTemplate\"></ng-container>\n }\n </div>\n }\n <div class=\"chat-input-group\">\n <label\n class=\"sr-only\"\n for=\"chat-input-{{ componentId }}\"\n >\n {{ config.placeholder | translate }}\n </label>\n <textarea\n class=\"form-control no-resize\"\n [class.text-muted]=\"isLoading\"\n style=\"max-height: 200px !important\"\n [attr.aria-label]=\"config.placeholder | translate\"\n id=\"chat-input-{{ componentId }}\"\n placeholder=\"{{ config.placeholder | translate }}\"\n [attr.aria-describedby]=\"config.disclaimerText ? 'chat-disclaimer-' + componentId : null\"\n [attr.aria-busy]=\"isLoading\"\n [(ngModel)]=\"prompt\"\n (keydown.enter)=\"!isLoading && sendMessage($event)\"\n [disabled]=\"disabled\"\n c8y-textarea-autoresize\n ></textarea>\n <div class=\"chat-input-group-btn\">\n @if (!isLoading) {\n <button\n class=\"btn btn-dot\"\n [attr.title]=\"config.sendButtonText || '' | translate\"\n [attr.aria-label]=\"config.sendButtonText || '' | translate\"\n type=\"button\"\n (click)=\"sendMessage($event)\"\n [disabled]=\"disabled || prompt.trim().length === 0\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.send || 'arrow-circle-right'\"></i>\n </button>\n } @else {\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.title]=\"config.cancelButtonText || '' | translate\"\n [attr.aria-label]=\"config.cancelButtonText || '' | translate\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.cancel || 'stop'\"></i>\n </button>\n }\n </div>\n </div>\n @if (config.disclaimerText) {\n <div\n class=\"text-muted m-b-8 text-10 p-l-16\"\n id=\"chat-disclaimer-{{ componentId }}\"\n role=\"note\"\n >\n {{ config.disclaimerText | translate }}\n </div>\n }\n </div>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1"],"mappings":"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"}
1
+ {"version":3,"file":"c8y-ngx-components-ai-ai-chat.mjs","sources":["../../ai/ai-chat/ai-chat-tool-call.component.ts","../../ai/ai-chat/ai-chat-tool-call.component.html","../../ai/ai-chat/ai-chat-assistant-part.component.ts","../../ai/ai-chat/ai-chat-assistant-part.component.html","../../ai/ai-chat/ai-chat-assistant-message.component.ts","../../ai/ai-chat/ai-chat-assistant-message.component.html","../../ai/ai-chat/ai-chat-message-action.component.ts","../../ai/ai-chat/ai-chat-message-action.component.html","../../ai/ai-chat/ai-chat-message.component.ts","../../ai/ai-chat/ai-chat-message.component.html","../../ai/ai-chat/ai-chat-suggestion.component.ts","../../ai/ai-chat/ai-chat-suggestion.component.html","../../ai/ai-chat/ai-chat.component.ts","../../ai/ai-chat/ai-chat.component.html","../../ai/ai-chat/c8y-ngx-components-ai-ai-chat.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, input, signal, Type } from '@angular/core';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { ToolCallConfig, ToolCallPart } from '@c8y/ngx-components/ai';\nimport { C8yTranslateModule, C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport { JsonPipe, NgComponentOutlet } from '@angular/common';\nimport { TranslateService } from '@ngx-translate/core';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\n\n@Component({\n selector: 'c8y-ai-chat-tool-call',\n templateUrl: './ai-chat-tool-call.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n NgComponentOutlet,\n JsonPipe,\n C8yTranslatePipe,\n IconDirective,\n CollapseModule,\n C8yTranslateModule\n ]\n})\nexport class AiChatToolCallComponent {\n /**\n * The tool call part to render. This includes all information about the tool call, including the name of the tool,\n * the input provided and (once available) the output from the tool.\n */\n readonly tool = input.required<ToolCallPart>();\n\n /**\n * Whether the tool call is still in progress.\n */\n readonly isExecuting = input.required<boolean>();\n\n /**\n * A custom component to render the details of the tool call. If not provided, the default details section will be shown.\n */\n readonly toolDetailsComponent = input<Type<unknown> | undefined>(undefined);\n\n /**\n * Shows the default details section for a tool call.\n */\n readonly showDefaultToolDetails = input<boolean>(false);\n\n /**\n * The label to show while the tool is executing. If not provided, a default label will be generated based on the tool name.\n */\n readonly executingLabel = input<string | undefined>(undefined);\n /**\n * The label to show once the tool has completed. If not provided, a default label will be generated based on the tool name and whether the tool call was successful or resulted in an error.\n */\n readonly completedLabel = input<string | undefined>(undefined);\n\n /**\n * A function that can generate a label for this tool call based on the tool call data.\n */\n readonly labelProvider = input<ToolCallConfig['labelProvider']>();\n\n protected readonly expanded = signal(false);\n protected readonly everExpanded = signal(false);\n\n private readonly translateService = inject(TranslateService);\n\n getToolLabel(tool: ToolCallPart): string {\n const isExecuting = tool.type !== 'tool-result';\n if (this.labelProvider()) {\n try {\n const dynamicLabel = this.labelProvider()(tool, this.translateService);\n if (dynamicLabel) return dynamicLabel;\n } catch (err) {\n // Should never happen, report it then fall back to default logic\n console.error(`Error in labelProvider for tool ${tool.toolName}:`, err);\n }\n }\n\n if (isExecuting && this.executingLabel()) {\n return this.executingLabel();\n }\n if (!isExecuting && this.completedLabel()) {\n return this.completedLabel();\n }\n\n return this.translateService.instant(\n isExecuting ? gettext('Calling tool {{toolName}}') : gettext('Used tool {{toolName}}'),\n { toolName: tool.toolName }\n );\n }\n\n protected toggleExpanded(): void {\n const willExpand = !this.expanded();\n this.expanded.set(willExpand);\n if (willExpand) {\n this.everExpanded.set(true);\n }\n }\n}\n","@let _tool = tool();\n@let showDetails = showDefaultToolDetails() || toolDetailsComponent() || _tool.error;\n@let isToolExpanded = expanded();\n\n<fieldset\n class=\"c8y-fieldset p-b-4 ai-tool-call__fieldset\"\n [attr.aria-label]=\"'Tool call: ' + _tool.toolName\"\n>\n <button\n class=\"btn-clean ai-tool-call__btn\"\n [attr.aria-expanded]=\"showDetails ? isToolExpanded : null\"\n [attr.aria-controls]=\"showDetails ? 'tool-call-' + _tool.toolCallId : null\"\n type=\"button\"\n [attr.data-cy]=\"'tool-call-' + _tool.toolName\"\n [disabled]=\"!showDetails || null\"\n (click)=\"toggleExpanded()\"\n >\n @if (isExecuting()) {\n <i\n class=\"icon-spin icon-14 text-primary m-r-4\"\n c8yIcon=\"spinner\"\n aria-hidden=\"true\"\n ></i>\n } @else {\n <!-- Treat it as an error if a tool still thinks its executing when the message containing it is not -->\n @if (_tool.error || isExecuting()) {\n <i\n class=\"icon-14 text-danger m-r-4\"\n [c8yIcon]=\"'exclamation-circle'\"\n aria-hidden=\"true\"\n ></i>\n } @else {\n <i\n class=\"icon-14 text-success m-r-4\"\n [c8yIcon]=\"'check'\"\n aria-hidden=\"true\"\n ></i>\n }\n }\n <span class=\"small\">{{ getToolLabel(_tool) | translate }}</span>\n\n @if (showDetails) {\n <i\n class=\"m-l-4 icon-12\"\n [c8yIcon]=\"isToolExpanded ? 'collapse-arrow' : 'expand-arrow'\"\n aria-hidden=\"true\"\n ></i>\n }\n </button>\n\n <!-- If this is an artifact tool, render it - but do so lazily only on first open,\n since these components could be heavyweight (e.g. Monaco)\n -->\n @if (showDetails && (isToolExpanded || everExpanded())) {\n <div\n class=\"collapse tool-details m-t-8 p-8 b-r-4\"\n [attr.aria-label]=\"'Tool details for message latest tool: ' + _tool.toolName\"\n role=\"region\"\n [collapse]=\"!isToolExpanded\"\n [id]=\"'tool-call-' + _tool.toolCallId\"\n [isAnimated]=\"true\"\n data-cy=\"ai-tool-component\"\n >\n @if (toolDetailsComponent()) {\n <ng-container\n [ngComponentOutlet]=\"toolDetailsComponent()\"\n [ngComponentOutletInputs]=\"{ tool: _tool }\"\n ></ng-container>\n } @else {\n @let noneLabel = '(no data)' | translate;\n\n <p class=\"text-label-small\">{{ 'Tool input' | translate }}</p>\n <pre class=\"fit-w small\">{{ _tool.input || noneLabel | json }}</pre>\n\n @if (_tool.type === 'tool-result') {\n <p class=\"text-label-small\">{{ 'Tool output' | translate }}</p>\n @if (\n typeof _tool.output === 'string' || _tool.output === undefined || _tool.output === null\n ) {\n <pre class=\"fit-w small\">{{ _tool.output || noneLabel }}</pre>\n } @else {\n <pre class=\"fit-w small\">{{ _tool.output | json }}</pre>\n }\n }\n }\n </div>\n }\n</fieldset>\n","import { ChangeDetectionStrategy, Component, input, signal } from '@angular/core';\nimport { AIMessagePart } from '@c8y/ngx-components/ai';\nimport {\n C8yTranslateDirective,\n C8yTranslatePipe,\n IconDirective,\n MarkdownToHtmlPipe\n} from '@c8y/ngx-components';\nimport { AsyncPipe, NgComponentOutlet } from '@angular/common';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\nimport { AssistantMessageContext } from './ai-chat-assistant-message.component';\nimport { AiChatToolCallComponent } from './ai-chat-tool-call.component';\n\n/** This renders a part of an assistant message. Currently only ToolCallPart is supported, but later we can expand this to deal with all part types. */\n@Component({\n selector: 'c8y-ai-chat-assistant-part',\n templateUrl: './ai-chat-assistant-part.component.html',\n standalone: true,\n imports: [\n NgComponentOutlet,\n C8yTranslateDirective,\n C8yTranslatePipe,\n IconDirective,\n CollapseModule,\n MarkdownToHtmlPipe,\n AsyncPipe,\n AiChatToolCallComponent\n ],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AiChatAssistantPartComponent {\n readonly part = input.required<AIMessagePart>();\n\n /** Whether this part is rendered as part of the main answer, or is an intermediate step with more muted rendering. */\n readonly displayAsPartOfMainAnswer = input(true);\n\n /**\n * The context needed to render a message.\n * This is a single input so we can extend in future without breaking people who have a custom rendering implementation.\n */\n readonly assistantMessageContext = input.required<AssistantMessageContext>();\n\n /** Tracks whether this is currently expanded (used for reasoning section). */\n protected readonly expanded = signal(false);\n\n protected toggleExpanded(): void {\n this.expanded.update(v => !v);\n }\n}\n","@let ctx = assistantMessageContext();\n@let _config = ctx.config;\n@let toolCallConfig = _config.toolCallConfig || {};\n@let _part = part();\n\n@if (_part.type === 'text') {\n <p\n [class.text-muted]=\"!displayAsPartOfMainAnswer()\"\n [innerHTML]=\"_part.text | markdownToHtml | async\"\n ></p>\n} @else if (_part.type === 'reasoning') {\n @let reasoningExpanded = expanded();\n\n <fieldset\n class=\"c8y-fieldset p-b-4 ai-tool-call__fieldset\"\n data-cy=\"ai-reasoning\"\n >\n <button\n class=\"btn-clean ai-tool-call__btn\"\n aria-label=\"{{ 'Toggle display of the reasoning section' | translate }}\"\n [attr.aria-expanded]=\"reasoningExpanded\"\n [attr.aria-controls]=\"'reasoning-content-message' + ctx.messageDisplayIndex\"\n type=\"button\"\n (click)=\"toggleExpanded()\"\n >\n <i\n class=\"m-r-4\"\n [c8yIcon]=\"'ai-sparkles'\"\n ></i>\n @let hideReasoning = 'Hide reasoning' | translate;\n @let showReasoning = 'Show reasoning' | translate;\n <span class=\"small\">{{ reasoningExpanded ? hideReasoning : showReasoning }}</span>\n <i\n class=\"m-l-4 icon-12 text-muted\"\n [c8yIcon]=\"reasoningExpanded ? 'collapse-arrow' : 'expand-arrow'\"\n ></i>\n </button>\n\n @let ariaLabel =\n 'Reasoning for message number {{ number }}' | translate: { number: ctx.messageDisplayIndex };\n <div\n class=\"collapse reasoning-content\"\n [attr.aria-label]=\"ariaLabel\"\n role=\"region\"\n [collapse]=\"!reasoningExpanded\"\n [id]=\"'reasoning-content-message' + ctx.messageDisplayIndex\"\n [isAnimated]=\"true\"\n data-cy=\"ai-reasoning-content\"\n >\n <div\n class=\"m-t-8 p-b-4 text-muted\"\n [innerHTML]=\"_part.text | markdownToHtml | async\"\n ></div>\n </div>\n </fieldset>\n} @else if (_part.type === 'step-start') {\n <!-- Visually hidden label included when users copy-paste from the chat, e.g. to report issues -->\n <span\n class=\"ai-step-start hidden-copy-label\"\n aria-hidden=\"true\"\n data-cy=\"ai-step-start-separator\"\n translate\n >--- (step separator) ---</span\n >\n} @else if (_part.type.startsWith('tool')) {\n @let tool = $any(_part);\n @let toolDisplay = toolCallConfig[tool.toolName];\n\n <!-- Visually hidden label included when users copy-paste from the chat, e.g. to report issues -->\n <span\n class=\"hidden-copy-label\"\n aria-hidden=\"true\"\n translate\n [translateParams]=\"{ toolName: tool.toolName }\"\n ngNonBindable\n >--- Tool call: {{ toolName }} ---</span\n >\n\n @if (toolDisplay?.component) {\n <div data-cy=\"ai-tool-with-custom-component\">\n <ng-container\n [ngComponentOutlet]=\"toolDisplay.component\"\n [ngComponentOutletInputs]=\"{\n tool: tool,\n ctx: ctx\n }\"\n ></ng-container>\n </div>\n } @else if (!toolDisplay?.isHidden) {\n <!-- Don't allow expanding while tool call is in progress - it's unlikely to have anything worth rendering,\n and complicates implementation for the client to have to check for the isExecuting case.\n -->\n <c8y-ai-chat-tool-call\n [tool]=\"tool\"\n [isExecuting]=\"tool.type !== 'tool-result' && ctx.isMessageLoading\"\n [toolDetailsComponent]=\"_config.toolDetailsComponent?.(tool)\"\n [showDefaultToolDetails]=\"_config.showDefaultToolDetails === 'all'\"\n [executingLabel]=\"toolDisplay?.executingLabel\"\n [completedLabel]=\"toolDisplay?.completedLabel\"\n [labelProvider]=\"toolDisplay?.labelProvider\"\n ></c8y-ai-chat-tool-call>\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n inject,\n input,\n signal\n} from '@angular/core';\nimport { C8yTranslateModule, C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport {\n AIAssistantMessage,\n AIMessagePart,\n AssistantMessageDisplayConfig,\n ToolCallPart\n} from '@c8y/ngx-components/ai';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { TranslateService } from '@ngx-translate/core';\nimport { CollapseModule } from 'ngx-bootstrap/collapse';\nimport { AiChatAssistantPartComponent } from './ai-chat-assistant-part.component';\n\n/**\n * Context object which includes the inputs needed for assistant message rendering.\n * If creating a custom component for assistant message rendering, you will receive this as an input.\n */\nexport interface AssistantMessageContext {\n message: AIAssistantMessage;\n config: AssistantMessageDisplayConfig;\n\n /** The message response is currently streaming in (not yet complete). */\n isMessageLoading: boolean;\n\n /** A number identifying this message in the chat history numbered from the latest - 0 is the latest, -1 is the previous, etc. */\n messageDisplayIndex: number;\n}\n\n/**\n * This is the default component used to render the contents of a message from the AI assistant, including\n * the main answer text, text from earlier steps, reasoning text and tool calls.\n */\n@Component({\n selector: 'c8y-ai-chat-assistant-message',\n templateUrl: './ai-chat-assistant-message.component.html',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n C8yTranslatePipe,\n IconDirective,\n CollapseModule,\n C8yTranslateModule,\n AiChatAssistantPartComponent\n ]\n})\nexport class AiChatAssistantMessageComponent {\n /**\n * The context needed to render a message.\n * This is a single input so we can extend in future without breaking people who have a custom rendering implementation.\n */\n readonly assistantMessageContext = input.required<AssistantMessageContext>();\n\n /**\n * By default this component will render a \"Working...\" indicator while streaming results. This input can turn that off if required.\n */\n readonly showWorkingIndicator = input(true);\n\n /**\n * Whether the thinking section is expanded. Initialized to false unless the message is still loading.\n * Call setThinkingExpanded() via viewChild to control this programmatically. Does nothing if appearance does not distinguish thinking steps.\n */\n protected readonly thinkingExpanded = signal(false);\n\n /**\n * Tracks which reasoning sections are expanded, keyed by step index.\n */\n protected readonly expandedReasoningStepIndices = signal(new Set<number>());\n\n private readonly translateService = inject(TranslateService);\n\n protected readonly thinkingAndMainAnswerParts = computed(() =>\n this.splitContentIntoThinkingAndMainAnswer(this.assistantMessageContext())\n );\n\n constructor() {\n // Expand when we initially set the message loading flag, without overwriting the value\n // any other time\n effect(() => {\n if (this.assistantMessageContext().isMessageLoading) {\n this.thinkingExpanded.set(true);\n }\n });\n }\n\n /**\n * This is public and exists for agent-chat to collapse older messages.\n * @param expanded Whether the thinking section should be expanded or not.\n */\n setThinkingExpanded(expanded: boolean): void {\n this.thinkingExpanded.set(expanded);\n }\n\n /**\n * Get a translated/translateable label for the specified tool.\n * @param tool The tool call part to get the label for.\n * @return The label to show for this tool call.\n */\n getToolLabel(tool: ToolCallPart): string {\n const isExecuting = tool.type !== 'tool-result';\n const config = this.assistantMessageContext().config;\n const toolCallConfig = config?.toolCallConfig?.[tool.toolName];\n if (toolCallConfig?.labelProvider) {\n try {\n const dynamicLabel = toolCallConfig.labelProvider(tool, this.translateService);\n // Run it through translate in case it contains gettext values\n if (dynamicLabel) return dynamicLabel;\n } catch (err) {\n // Should never happen, so report this - then fallback to default logic\n console.warn(`Error in labelProvider for tool ${tool.toolName}:`, err);\n }\n }\n\n if (isExecuting && toolCallConfig?.executingLabel) {\n return toolCallConfig.executingLabel;\n }\n if (!isExecuting && toolCallConfig?.completedLabel) {\n return toolCallConfig.completedLabel;\n }\n\n // If we have no specific label configured, use the default\n return this.translateService.instant(\n isExecuting ? gettext('Calling tool {{toolName}}') : gettext('Used tool {{toolName}}'),\n // Have to use the tool id since that's all we have\n { toolName: tool.toolName }\n );\n }\n\n protected toggleReasoningExpanded(stepIndex: number): void {\n this.expandedReasoningStepIndices.update(s => {\n const next = new Set(s);\n s.has(stepIndex) ? next.delete(stepIndex) : next.add(stepIndex);\n return next;\n });\n }\n\n /**\n * Note: ctx is passed as a parameter rather than reading the signal in the template to ensure\n * it's totally aligned with what the template is rendering.\n * @param ctx The context for the assistant message.\n * @return The label to display for the reasoning section.\n */\n protected getThinkingLabel(ctx: AssistantMessageContext): string {\n return ctx.isMessageLoading\n ? gettext('Reasoning')\n : this.thinkingExpanded()\n ? gettext('Hide reasoning')\n : gettext('Show reasoning');\n }\n\n protected getToolName(part: AIMessagePart): string | undefined {\n return part.type === 'tool-input-streaming' ||\n part.type === 'tool-executing' ||\n part.type === 'tool-result'\n ? part.toolName\n : undefined;\n }\n\n protected experimental_nonFinalStepTextDisplay(\n ctx: AssistantMessageContext\n ): AssistantMessageDisplayConfig['experimental_nonFinalStepTextDisplay'] {\n // For now be conservative with the old behaviour, but hope to change this once we've got working really smoothly.\n return ctx.config?.experimental_nonFinalStepTextDisplay || 'main-answer';\n }\n\n /**\n * Splits the assistant message content into two arrays: thinking content and main answer content.\n * This also removes hidden tools.\n *\n * If using the experimental rendering modes, main answer content is text in the final step (if conditions are met) plus any tool calls configured to be shown with the main answer.\n * Thinking content is everything else (reasoning, earlier text, tool calls not shown with main answer).\n *\n * @param ctx The context for the assistant message.\n * @return An object with thinkingParts and mainAnswerParts arrays.\n */\n protected splitContentIntoThinkingAndMainAnswer(ctx: AssistantMessageContext): {\n thinkingParts: AIMessagePart[];\n mainAnswerParts: AIMessagePart[];\n } {\n // Remove hidden tools\n let content = ctx.message?.content || [];\n if (Object.values(ctx.config?.toolCallConfig || {}).some(c => c?.isHidden)) {\n content = (ctx.message?.content || []).filter(\n part => !ctx.config?.toolCallConfig?.[this.getToolName(part) || '']?.isHidden\n );\n }\n\n // Putting this check here keeps things safe by ensuring there is no chance of any rendering differences\n // during streaming unless in one of the experimental modes. This means the rest of this method only applies\n // to the experimental rendering.\n if (this.experimental_nonFinalStepTextDisplay(ctx) === 'main-answer') {\n return { thinkingParts: [], mainAnswerParts: content };\n }\n\n const { finalStepStart, finalStepHasText } = this.findFinalStepWithText(content);\n\n const hasToolCalls = content.some(\n part =>\n part.type === 'tool-input-streaming' ||\n part.type === 'tool-executing' ||\n part.type === 'tool-result'\n );\n // Since we don't bother with a step-start at index 0 for the first step, add one\n const stepCount =\n content.filter((part, index) => index > 0 && part.type === 'step-start').length + 1;\n\n // The final step text goes in the main answer area if there are no pending tool calls\n // (since otherwise the tools would show below it), and\n // message has finished loading, or we're expecting more steps than this.\n // Note that we check all steps for toolCalls not just the current one, for the sake of \"fake\" tool calls created by preprocessAgentMessage\n // where additional step boundaries may be added to simplify parsing.\n const shouldShowLastTextAsMainAnswer =\n finalStepHasText &&\n finalStepStart !== -1 &&\n !hasToolCalls &&\n (!ctx.isMessageLoading || stepCount >= (ctx.config?.experimental_expectedStepCount || 2));\n\n if (!shouldShowLastTextAsMainAnswer) {\n return { thinkingParts: content, mainAnswerParts: [] };\n }\n\n const thinkingParts: AIMessagePart[] = [];\n const mainAnswerParts: AIMessagePart[] = [];\n\n // Split the content: final step and promoted tool calls go to main answer, everything else to thinking\n content.forEach((part, index) => {\n const isPromotedToolCall =\n ctx.config?.toolCallConfig?.[this.getToolName(part) || '']?.isShownWithMainAnswer;\n\n // This ensures promoted tool calls never go to the collapseable thinking area\n if (index >= finalStepStart || isPromotedToolCall) {\n mainAnswerParts.push(part);\n } else {\n thinkingParts.push(part);\n }\n });\n\n return { thinkingParts, mainAnswerParts };\n }\n\n /**\n * Scans backwards through the content parts to find the step-start index for the last step\n * that contains at least one text part. Skips trailing empty steps (step-start with no text after).\n *\n * @returns `finalStepStart` — index of the step-start part, or 0 if content belongs to the implicit first step.\n * `finalStepHasText` — whether a step with text was found at all.\n */\n private findFinalStepWithText(content: AIMessagePart[]): {\n finalStepStart: number;\n finalStepHasText: boolean;\n } {\n let finalStepStart = 0;\n let finalStepHasText = false;\n for (let i = content.length - 1; i >= 0; i--) {\n if (content[i].type === 'text') {\n finalStepHasText = true;\n }\n if (content[i].type === 'step-start') {\n if (finalStepHasText) {\n finalStepStart = i;\n break;\n } else if (i === content.length - 1) {\n // Trailing empty step-start — keep looking\n continue;\n } else {\n // step-start found but no text in that step\n finalStepStart = -1;\n break;\n }\n }\n }\n return { finalStepStart, finalStepHasText };\n }\n}\n","@let ctx = assistantMessageContext();\n@let parts = ctx.message.content;\n@let _config = ctx.config;\n\n<!-- \nWe show the assistant message in (up to) 3 slots:\n- collapsible thinking block (for intermediate step text, standard tool calls, etc)\n- special \"artifact\" tools that update user artifacts and need prominent display (e.g. for code edits made by the AI)\n- the main answer (typically from the final step)\n\nThis is a standard approach for AI chats - step text and tools from an LLM are treated as a work log, i.e. useful to \ndisplay progress while streaming the response, but only the text from the last step after all tool calls gives the main answer of the AI to the user. \n\nDepending on configuration, we have an experimental option (if we need it) to style the thinking block the same as the main answer. \n\nOnce the message finishes loading we know the final step IS the main content, but if it's still steaming \nwe don't know for sure which step has the final/main answer until the LLM has actually finished so have to take a heuistic guess \n(and minimize jumping in the UI). \n\nFor applications where we expect tool calls in most responses, assume the 2nd step is probably the final text; \nfor applications where tool calls are less ubiquitous, assume the first step is main answer until proved otherwise. \nThis minimizes jumping (except when there are >2 steps, which is rare).\n\n-->\n\n@let contentSplit = thinkingAndMainAnswerParts();\n@let nonFinalStepTextDisplay = experimental_nonFinalStepTextDisplay(ctx);\n\n<!-- Thinking steps section - holds reasoning, text from non-final steps, and standard/non-artifact tool calls -->\n\n@if (contentSplit.thinkingParts.length > 0) {\n <div\n class=\"m-b-8 text-muted\"\n [class.thinking-block]=\"nonFinalStepTextDisplay === 'collapsible-thinking-block'\"\n [class.small]=\"nonFinalStepTextDisplay === 'muted-main-answer'\"\n [class.thinking-steps-appearance]=\"nonFinalStepTextDisplay\"\n data-cy=\"thinking-steps\"\n >\n @if (nonFinalStepTextDisplay === 'collapsible-thinking-block') {\n <button\n class=\"btn btn-clean btn-xs text-muted p-l-0\"\n aria-label=\"{{ 'Toggle collapse of the reasoning section' | translate }}\"\n [attr.aria-expanded]=\"thinkingExpanded()\"\n [attr.aria-controls]=\"'thinking-content-' + ctx.messageDisplayIndex\"\n type=\"button\"\n (click)=\"thinkingExpanded.set(!thinkingExpanded())\"\n >\n <span class=\"small\">{{ getThinkingLabel(ctx) }}</span>\n <i\n class=\"m-l-4 icon-12\"\n [c8yIcon]=\"thinkingExpanded() ? 'collapse-arrow' : 'expand-arrow'\"\n ></i>\n </button>\n }\n\n @let ariaLabel =\n 'Reasoning for message number {{ number }}' | translate: { number: ctx.messageDisplayIndex };\n <div\n class=\"collapse\"\n [attr.aria-label]=\"ariaLabel\"\n role=\"region\"\n [collapse]=\"nonFinalStepTextDisplay === 'collapsible-thinking-block' && !thinkingExpanded()\"\n [id]=\"'thinking-content-' + ctx.messageDisplayIndex\"\n [isAnimated]=\"true\"\n >\n <div\n [class]=\"\n nonFinalStepTextDisplay === 'collapsible-thinking-block'\n ? 'thinking-content bg-level-1 m-t-8 p-8 b-r-4 border-left-accent small m-b-0 text-muted'\n : ''\n \"\n >\n @for (part of contentSplit.thinkingParts; track $index) {\n @if (part.type !== 'step-start' || $index > 0) {\n <c8y-ai-chat-assistant-part\n [part]=\"part\"\n [assistantMessageContext]=\"ctx\"\n [displayAsPartOfMainAnswer]=\"nonFinalStepTextDisplay !== 'muted-main-answer'\"\n ></c8y-ai-chat-assistant-part>\n }\n }\n </div>\n </div>\n </div>\n}\n\n<!-- Main answer area contains the text from the final step, and \n any promoted tool calls which are too important to be hidden in the collapeable thinking area -->\n<div\n class=\"message-content\"\n data-cy=\"ai-main-answer-content\"\n>\n @for (part of contentSplit.mainAnswerParts; track $index) {\n <c8y-ai-chat-assistant-part\n [part]=\"part\"\n [assistantMessageContext]=\"ctx\"\n [displayAsPartOfMainAnswer]=\"true\"\n ></c8y-ai-chat-assistant-part>\n }\n</div>\n\n@if (ctx.isMessageLoading && showWorkingIndicator()) {\n <!-- Once the message starts to stream, show a small/low-key thinking indicator -->\n <div\n class=\"text-muted text-12 fade-in-out d-flex j-c-end\"\n aria-live=\"polite\"\n role=\"status\"\n data-cy=\"working-indicator\"\n >\n {{ 'Working…' | translate }}\n </div>\n}\n","import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport { SupportedIconsSuggestions } from '@c8y/ngx-components/icon-selector/icons';\nimport { TooltipModule } from 'ngx-bootstrap/tooltip';\n\n/**\n * An action button that can be added to chat messages.\n * Typically used for actions like copying, regenerating, or providing feedback on messages.\n */\n@Component({\n selector: 'c8y-ai-chat-message-action',\n templateUrl: './ai-chat-message-action.component.html',\n standalone: true,\n imports: [TooltipModule, C8yTranslatePipe, IconDirective]\n})\nexport class AiChatMessageActionComponent {\n /**\n * Set to true to use content projection for custom action button content.\n */\n @Input()\n custom = false;\n\n /**\n * Disables the action button when true.\n */\n @Input()\n disabled = false;\n\n /**\n * Tooltip text displayed when hovering over the action button.\n */\n @Input()\n tooltip = '';\n\n /**\n * Icon to display in the action button.\n */\n @Input()\n icon: SupportedIconsSuggestions = 'cog';\n\n /**\n * Emitted when the action button is clicked.\n */\n @Output()\n actionClicked = new EventEmitter<void>();\n}\n","@if (!custom) {\n <button\n class=\"btn btn-dot text-muted\"\n [attr.aria-label]=\"tooltip | translate\"\n [tooltip]=\"tooltip | translate\"\n [adaptivePosition]=\"true\"\n [delay]=\"500\"\n (click)=\"actionClicked.emit()\"\n [disabled]=\"disabled\"\n >\n <i\n class=\"text-12\"\n [c8yIcon]=\"icon\"\n ></i>\n </button>\n} @else {\n <ng-content></ng-content>\n}\n","import { Component, computed, input, inject, ChangeDetectionStrategy } from '@angular/core';\n\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { AIMessage } from '@c8y/ngx-components/ai';\nimport { C8yTranslatePipe, DatePipe } from '@c8y/ngx-components';\nimport { NgClass } from '@angular/common';\nimport { TooltipModule } from 'ngx-bootstrap/tooltip';\nimport { TranslateService } from '@ngx-translate/core';\n\n/**\n * A container for content and actions that should be rendered for each chat message.\n *\n * Project content into this component to display the message, for example add an `<ai-chat-assistant-message>`\n * for assistant messages, and a simple `markdownToHtml | async` rendering of the content for user messages.\n */\n@Component({\n selector: 'c8y-ai-chat-message',\n templateUrl: './ai-chat-message.component.html',\n styleUrl: './ai-chat-message.component.scss',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [NgClass, TooltipModule, C8yTranslatePipe, DatePipe]\n})\nexport class AiChatMessageComponent {\n readonly role = input<AIMessage['role']>();\n readonly message = input<AIMessage>();\n\n private readonly translateService = inject(TranslateService);\n\n private readonly roleResolved = computed(() => {\n return this.message()?.role || this.role();\n });\n\n /**\n * Generates an accessible label for the message container.\n * Includes the role (user or assistant) and timestamp if available.\n * @returns The aria-label string for screen readers\n */\n readonly ariaLabel = computed(() => {\n const tpl =\n this.roleResolved() === 'user'\n ? gettext('You said: \"{{ message }}\"')\n : gettext('Assistant said: \"{{ message }}\"');\n const msg = this.message();\n return this.translateService.instant(tpl, { message: msg?.content || gettext('No response.') });\n });\n\n /**\n * Generates an accessible label for the message content.\n * Prefixes the content with contextual information about who sent it.\n * @returns The aria-label string with prefixed role information\n */\n readonly messageContentAriaLabel = computed(() => {\n const msg = this.message();\n const time =\n msg.role != 'system' && msg.timestamp ? new Date(msg.timestamp).toLocaleTimeString() : '';\n let tpl: string;\n if (time) {\n tpl =\n this.roleResolved() === 'user'\n ? gettext('User message at {{ time }}')\n : gettext('Assistant message at {{ time }}');\n } else {\n tpl = this.roleResolved() === 'user' ? gettext('User message') : gettext('Assistant message');\n }\n return this.translateService.instant(tpl, { time });\n });\n}\n","<div\n class=\"d-col p-t-16\"\n [attr.aria-label]=\"ariaLabel()\"\n role=\"article\"\n>\n <div\n class=\"chat-message text-break-word\"\n [ngClass]=\"{\n 'user-message': message()?.role === 'user' || role() === 'user',\n 'agent-message': message()?.role === 'assistant' || role() === 'assistant'\n }\"\n >\n <!-- Visually hidden label included when users copy-paste from the chat, e.g. to report issues -->\n <span\n class=\"hidden-copy-label\"\n aria-hidden=\"true\"\n >\n {{ `====== ${messageContentAriaLabel()} ======` }}</span\n >\n\n <!-- Apply the class and aria-label to both the main content and whatever is projected, so we get the same styling by default -->\n <div\n class=\"message-content\"\n [attr.aria-label]=\"messageContentAriaLabel()\"\n >\n <div style=\"display: contents\">\n <ng-content select=\":not(c8y-ai-chat-message-action)\"></ng-content>\n </div>\n </div>\n @if (message()?.timestamp) {\n <div class=\"message-timestamp\">\n <span [tooltip]=\"message()?.timestamp | c8yDate\">\n {{ message()?.timestamp | c8yDate: 'adaptiveDate' }}\n </span>\n </div>\n }\n </div>\n <div\n class=\"message-action\"\n [attr.aria-label]=\"'Message actions' | translate\"\n role=\"toolbar\"\n [ngClass]=\"{\n 'user-action showOnHover': message()?.role === 'user' || role() === 'user',\n 'agent-action p-l-16': message()?.role === 'assistant' || role() === 'assistant'\n }\"\n >\n <ng-content select=\"c8y-ai-chat-message-action\"></ng-content>\n </div>\n</div>\n","import { Component, input, output } from '@angular/core';\nimport { C8yTranslatePipe, IconDirective } from '@c8y/ngx-components';\nimport { AIMessage } from '@c8y/ngx-components/ai';\nimport { SupportedIconsSuggestions } from '@c8y/ngx-components/icon-selector/icons';\n\n/**\n * A suggestion chip that can be displayed in the chat interface.\n * When clicked, it automatically populates and sends a predefined prompt.\n */\n@Component({\n selector: 'c8y-ai-chat-suggestion',\n templateUrl: './ai-chat-suggestion.component.html',\n host: { class: 'd-contents' },\n standalone: true,\n imports: [IconDirective, C8yTranslatePipe]\n})\nexport class AiChatSuggestionComponent {\n /**\n * The visible label text displayed on the suggestion chip.\n */\n readonly label = input.required<string>();\n\n /**\n * The prompt text that will be sent when the suggestion is clicked.\n */\n readonly prompt = input.required<string>();\n\n /**\n * Icon to display alongside the suggestion label.\n */\n readonly icon = input<SupportedIconsSuggestions>('c8y-bulb');\n\n /**\n * When true, uses AI-styled buttons instead of default styling.\n */\n readonly useAiButtons = input(false);\n\n /**\n * Disables the suggestion chip when true.\n */\n readonly disabled = input(false);\n\n /**\n * Emitted when the suggestion is clicked, providing the prompt as an AIMessage.\n */\n readonly suggestionClicked = output<AIMessage>();\n\n /**\n * Handles suggestion click and emits the prompt as a user message.\n */\n suggest() {\n this.suggestionClicked.emit({\n content: this.prompt(),\n role: 'user',\n timestamp: new Date().toISOString()\n });\n }\n}\n","@if (!useAiButtons()) {\n <button\n class=\"btn btn-default btn-sm\"\n [title]=\"prompt() | translate\"\n (click)=\"suggest()\"\n [disabled]=\"disabled()\"\n >\n <i [c8yIcon]=\"icon()\"></i>\n {{ label() | translate }}\n </button>\n} @else {\n <button\n class=\"btn btn-sm btn-ai\"\n [title]=\"prompt() | translate\"\n (click)=\"suggest()\"\n [disabled]=\"disabled()\"\n >\n <span>{{ label() | translate }}</span>\n </button>\n}\n","import { AsyncPipe, NgClass, NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n contentChildren,\n effect,\n ElementRef,\n EventEmitter,\n Input,\n Output,\n TemplateRef,\n viewChild\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n C8yTranslatePipe,\n IconDirective,\n MarkdownToHtmlPipe,\n TextareaAutoresizeDirective\n} from '@c8y/ngx-components';\nimport { AIMessage, ChatConfig } from '@c8y/ngx-components/ai';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { AiChatMessageComponent } from './ai-chat-message.component';\n\n/**\n * An interactive chat interface component for AI-powered conversations.\n * Displays messages in a conversation format with support for loading states,\n * custom configuration, and markdown formatting.\n */\n@Component({\n selector: 'c8y-ai-chat',\n templateUrl: './ai-chat.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n C8yTranslatePipe,\n FormsModule,\n TextareaAutoresizeDirective,\n IconDirective,\n NgClass,\n NgTemplateOutlet,\n MarkdownToHtmlPipe,\n AsyncPipe\n ],\n standalone: true,\n host: { class: 'd-contents' }\n})\nexport class AiChatComponent {\n /**\n * Indicates whether the chat is currently processing a request.\n * When true, displays a cancel button instead of send button and disables the input.\n */\n @Input()\n isLoading = false;\n\n /**\n * Disables the chat input and send button when true.\n */\n @Input()\n disabled = false;\n\n /**\n * The current text in the chat input field. Supports two-way binding.\n */\n @Input()\n prompt = '';\n\n /**\n * Template for rendering custom suggestions below the input field. Can be used to provide predefined prompts or actions\n * from a dynamic source such as the AI. To use this, wrap your suggestion components in an `<ng-template #suggestionsRef>`\n * (where `suggestionsRef` matches the suggestionsTemplate reference);\n */\n @Input()\n suggestionsTemplate?: TemplateRef<any>;\n\n /** Template for customizing the welcome view using `<ng-template>`. */\n @Input() welcomeTemplate?: TemplateRef<any>;\n\n /**\n * Emitted when the user sends a message.\n * Provides an AIMessage object with role, content, and timestamp.\n */\n @Output()\n onMessage = new EventEmitter<AIMessage>();\n\n /**\n * Emitted when the user cancels an ongoing operation during loading state.\n */\n @Output()\n onCancel = new EventEmitter<void>();\n\n /**\n * Child message components displayed in the chat.\n */\n readonly messages = contentChildren(AiChatMessageComponent);\n\n /**\n * Reference to the scroll container for the chat messages.\n */\n private readonly scrollContainer = viewChild<ElementRef<HTMLDivElement>>('chatScrollContainer');\n\n readonly componentId = `chat-${crypto.randomUUID()}`;\n\n private _config: ChatConfig = {\n headline: gettext('Welcome!'),\n welcomeText: '',\n welcomePosition: 'top',\n title: gettext('What can I help you with?'),\n placeholder: gettext('Type your message here...'),\n scrollbarOnlyOnHover: false,\n sendButtonText: gettext('Send'),\n cancelButtonText: gettext('Cancel'),\n disclaimerText: gettext(\n 'AI-generated responses can contain errors. Verify the details before use.'\n ),\n userInterfaceIcons: {\n send: 'arrow-circle-up',\n cancel: 'stop-circle'\n }\n };\n\n constructor() {\n // Auto-scroll to bottom when messages change\n effect(() => {\n this.messages(); // track changes\n const container = this.scrollContainer()?.nativeElement;\n if (!container) return;\n // In column-reverse, scrollTop=0 IS the visual bottom.\n // Only snap back if user is already near the bottom (wasn't scrolled up).\n if (container.scrollTop < 50) {\n container.scrollTop = 0;\n }\n });\n }\n\n /**\n * Configuration object for customizing labels, placeholders, and icons.\n * Accepts partial configuration to override defaults.\n * @param value Partial configuration to merge with defaults.\n * @returns The complete configuration object.\n */\n @Input()\n set config(value: Partial<ChatConfig>) {\n this._config = { ...this._config, ...value };\n }\n get config(): ChatConfig {\n return this._config;\n }\n\n /**\n * Handles message submission when the user sends a message.\n * Emits the onMessage event and clears the input.\n * @param $event The event object from the form submission\n */\n sendMessage($event: Event): void {\n $event.preventDefault();\n if (!this.prompt) return;\n this.onMessage.emit({\n role: 'user',\n content: this.prompt,\n timestamp: new Date().toISOString()\n });\n this.prompt = '';\n }\n\n /**\n * Handles cancellation of ongoing operations during loading state.\n * Emits the onCancel event.\n */\n cancel(): void {\n this.onCancel.emit();\n }\n}\n","<div\n class=\"d-col fit-h fit-w flex-grow\"\n [attr.aria-label]=\"config.headline | translate\"\n role=\"region\"\n>\n @if (messages().length > 0) {\n <div\n [attr.aria-label]=\"'Chat conversation' | translate\"\n aria-live=\"polite\"\n aria-atomic=\"false\"\n role=\"log\"\n #chatScrollContainer\n [ngClass]=\"{\n 'inner-scroll': true,\n 'd-col-reverse': true,\n 'scrollbar-only-on-hover': config.scrollbarOnlyOnHover,\n 'flex-grow': true,\n 'min-height-0': true,\n 'bg-level-0': true\n }\"\n >\n <div class=\"d-col p-l-16 p-r-16\">\n <ng-content select=\"[slot='before-messages']\"></ng-content>\n <ng-content select=\"c8y-ai-chat-message\"></ng-content>\n <ng-content select=\"[slot='after-messages']\"></ng-content>\n </div>\n </div>\n }\n <div\n [ngClass]=\"{\n 'd-col fit-h': messages().length === 0\n }\"\n >\n @if (messages().length === 0) {\n <div\n class=\"p-24 d-col fit-h inner-scroll\"\n aria-live=\"polite\"\n role=\"status\"\n [ngClass]=\"{\n 'j-c-start': config.welcomePosition === 'top',\n 'j-c-center': config.welcomePosition === 'center',\n 'j-c-end': config.welcomePosition === 'bottom'\n }\"\n >\n <h4 class=\"m-b-16 text-medium\">{{ config.headline | translate }}</h4>\n @if (config.title.length > 0) {\n <p class=\"p-b-8 text-balance\">{{ config.title | translate }}</p>\n }\n <div class=\"text-balance chat-message min-height-0\">\n <div\n class=\"text-muted\"\n [innerHTML]=\"config.welcomeText | translate | markdownToHtml | async\"\n ></div>\n @if (welcomeTemplate) {\n <ng-container *ngTemplateOutlet=\"welcomeTemplate\"></ng-container>\n }\n </div>\n </div>\n }\n <div\n class=\"chat-input\"\n [class.bg-level-1]=\"config.appearance !== 'flat'\"\n >\n <!-- For simple cases allow ng-content projection; however this doesn't seem to work with dynamic \n suggestion lists from a signal (e.g. returned from the AI) so also support `suggestionsTemplate` for that. \n -->\n @if (!isLoading) {\n <div\n [class]=\"\n 'd-flex inner-scroll gap-8 p-l-16 p-r-16 p-b-8 ' +\n (config.suggestionsLayout === 'vertical' ? 'flex-wrap' : 'a-i-center')\n \"\n >\n <ng-content select=\"c8y-ai-chat-suggestion\"></ng-content>\n\n @if (suggestionsTemplate) {\n <ng-container *ngTemplateOutlet=\"suggestionsTemplate\"></ng-container>\n }\n </div>\n }\n <div class=\"chat-input-group\">\n <label\n class=\"sr-only\"\n for=\"chat-input-{{ componentId }}\"\n >\n {{ config.placeholder | translate }}\n </label>\n <textarea\n class=\"form-control no-resize\"\n [class.text-muted]=\"isLoading\"\n style=\"max-height: 200px !important\"\n [attr.aria-label]=\"config.placeholder | translate\"\n id=\"chat-input-{{ componentId }}\"\n placeholder=\"{{ config.placeholder | translate }}\"\n [attr.aria-describedby]=\"config.disclaimerText ? 'chat-disclaimer-' + componentId : null\"\n [attr.aria-busy]=\"isLoading\"\n [(ngModel)]=\"prompt\"\n (keydown.enter)=\"!isLoading && sendMessage($event)\"\n [disabled]=\"disabled\"\n c8y-textarea-autoresize\n ></textarea>\n <div class=\"chat-input-group-btn\">\n @if (!isLoading) {\n <button\n class=\"btn btn-dot\"\n [attr.title]=\"config.sendButtonText || '' | translate\"\n [attr.aria-label]=\"config.sendButtonText || '' | translate\"\n type=\"button\"\n (click)=\"sendMessage($event)\"\n [disabled]=\"disabled || prompt.trim().length === 0\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.send || 'arrow-circle-right'\"></i>\n </button>\n } @else {\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.title]=\"config.cancelButtonText || '' | translate\"\n [attr.aria-label]=\"config.cancelButtonText || '' | translate\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.cancel || 'stop'\"></i>\n </button>\n }\n </div>\n </div>\n @if (config.disclaimerText) {\n <div\n class=\"text-muted m-b-8 text-10 p-l-16\"\n id=\"chat-disclaimer-{{ componentId }}\"\n role=\"note\"\n >\n {{ config.disclaimerText | translate }}\n </div>\n }\n </div>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1"],"mappings":"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"}
@@ -201,8 +201,7 @@ class AIService {
201
201
  const reader = stream.getReader();
202
202
  const message = {
203
203
  role: 'assistant',
204
- content: '',
205
- steps: []
204
+ content: []
206
205
  };
207
206
  const abortHandler = () => {
208
207
  reader.cancel();
@@ -239,53 +238,65 @@ class AIService {
239
238
  // We will need to rewrite this to include tool outputs soon (effectively this means targetting LanguageModelV*ToolResultOutput).
240
239
  // Once we have more fields than just role and content, we will need to convert between our format and
241
240
  // the Vercel format expected by the agent manager (e.g. steps->content parts)
242
- return messages
243
- .filter(m => m)
244
- .map(m => ({
241
+ return messages.map(m => ({
245
242
  role: m.role,
246
- content: m.content
243
+ content: m.role === 'assistant'
244
+ ? m.content
245
+ .filter((part) => part.type === 'text')
246
+ .map(part => part.text)
247
+ .join('\n\n')
248
+ : m.content
247
249
  }));
248
250
  }
249
251
  /**
250
- * Convert a tool output from the wire format (which is different/more compact than LanguageModelV3ToolResultOutput)
251
- * into our own standard representation.
252
+ * Convert a tool output from the MCP/wire format (which is different/more compact than LanguageModelV3ToolResultOutput)
253
+ * into our own standard representation, which can be roundtripped to the format we need to provide when making future requests.
254
+ *
255
+ * Handles different data types from Vercel's streaming API:
256
+ * - Text: stored as simple string in output field
257
+ * - JSON objects: stored as-is in output field
258
+ * - Content arrays: stored in output field with outputType="content" to enable roundtripping
259
+ * - Single text in content array: unwrapped to simple string for simpler handling (and easier truncation)
260
+ * - Errors: error flag set to true
252
261
  */
253
262
  convertStreamingToolOutputToToolCallPart(output, target) {
254
- // So far we just pass the data through unchanged from the streaming API but that's pretty hard to work with since it's neither
255
- // in the format returned by the tool nor in the LanguageModelV3ToolResultOutput format that we have to use
256
- // when passing it back for the next request
257
- target.output = output;
258
- if (output?.type?.startsWith('error-') || output?.isError)
263
+ if (!output) {
264
+ return;
265
+ }
266
+ if (output.isError || output.type === 'error-text' || output.type === 'error-json')
259
267
  target.error = true;
268
+ // Handle content array format from streaming API
269
+ if (output.content && Array.isArray(output.content)) {
270
+ // Single text element - unwrap to simple string for simplicity
271
+ if (output.content.length === 1 && output.content[0].type === 'text') {
272
+ target.output = output.content[0].text;
273
+ return;
274
+ }
275
+ // Multiple elements or mixed types - preserve as content array
276
+ target.output = output.content;
277
+ target.outputType = 'content'; // Mark as content to enable roundtripping
278
+ return;
279
+ }
280
+ // Plain string or structured (JSON-serializable) object - store as-is
281
+ target.output = output;
260
282
  }
261
283
  /** Add the specified tool call info to the current step. If this toolCallId is already known,
262
284
  * updates it rather than adding a new one, since for UI rendering and compactness of data it's
263
285
  * easiest to just have one item per tool call.
286
+ *
287
+ * Returns the changed item.
264
288
  */
265
289
  addToolCallInfo(type, rawInfo, addTo) {
266
290
  // Vercel v4 seems to set this to "id" not "toolCallId" in some places despite doc to the contrary, so normalize it here
267
291
  if (!rawInfo.toolCallId)
268
292
  rawInfo.toolCallId = rawInfo.id;
269
- // We can simplify this logic once we have AIMessage as a list of parts instead of separate lists for these
270
- let existing = addTo.toolCalls?.find(tc => tc.toolCallId === rawInfo.toolCallId);
271
- if (!existing)
272
- existing = addTo.toolResults?.find(tc => tc.toolCallId === rawInfo.toolCallId);
273
- // Move from toolCalls to toolResults when transitioning to tool-result
274
- if (existing && type === 'tool-result' && existing.type !== 'tool-result') {
275
- addTo.toolCalls = addTo.toolCalls?.filter(tc => tc.toolCallId !== existing?.toolCallId);
293
+ let existing = addTo.find((tc) => tc.type.startsWith('tool-') && tc.toolCallId === rawInfo.toolCallId);
294
+ if (existing) {
276
295
  existing.type = type;
277
- addTo.toolResults = [...(addTo.toolResults || []), existing];
278
296
  }
279
- else if (existing && existing.type !== type) {
280
- // Just update the type in place for other transitions
281
- existing.type = type;
282
- }
283
- if (!existing) {
297
+ else if (!existing) {
284
298
  existing = { type: type, toolName: rawInfo.toolName, toolCallId: rawInfo.toolCallId };
285
- if (type !== 'tool-result')
286
- addTo.toolCalls = [...(addTo.toolCalls || []), existing];
287
- else
288
- addTo.toolResults = [...(addTo.toolResults || []), existing];
299
+ addTo.push(existing);
289
300
  }
290
301
  if (rawInfo?.input)
291
302
  existing.input = rawInfo.input;
@@ -300,7 +311,7 @@ class AIService {
300
311
  * This is similar to what the Vercel `toUIMessageStreamResponse` API does (though it'd need the agent manager to publish the
301
312
  * UIMessageStream which has a bit more - useful - data than what is included here).
302
313
  *
303
- * We always use the same steps (or in future, parts) object, to make it easier for consumers (eg. agent-chat)
314
+ * We always use the same parts object, to make it easier for consumers (eg. agent-chat)
304
315
  * to add items to the list and have them still there on the next update from this service.
305
316
  */
306
317
  processLine(line, observer, message) {
@@ -318,11 +329,7 @@ class AIService {
318
329
  console.error('Error parsing line from AI response: ', line, e);
319
330
  return;
320
331
  }
321
- // Ensure there's a step into which we can store everything
322
- if (!message.steps || message.steps.length === 0) {
323
- message.steps = [{ type: 'text', text: '' }];
324
- }
325
- const lastStep = message.steps[message.steps.length - 1];
332
+ let lastPart = !message.content ? undefined : message.content[message.content.length - 1];
326
333
  switch (type) {
327
334
  case DataStreamType.STEP_START:
328
335
  if (data.request && data.request.body) {
@@ -335,45 +342,54 @@ class AIService {
335
342
  }
336
343
  });
337
344
  }
338
- // Create a step, unless we already have an empty one from the initialization section above
339
- if (lastStep.text || lastStep.reasoning || lastStep.toolCalls || lastStep.toolResults) {
340
- message.steps.push({
341
- type: 'text',
342
- text: ''
343
- });
345
+ // Don't add consecutive duplicate step bounaries
346
+ if (!lastPart || lastPart.type !== 'step-start') {
347
+ message.content.push({ type: 'step-start' });
348
+ observer.next({ message, changedPart: message.content[message.content.length - 1] });
344
349
  }
345
350
  return;
346
- case DataStreamType.REASONING:
347
- if (lastStep.reasoning === undefined) {
348
- lastStep.reasoning = '';
351
+ case DataStreamType.REASONING_DELTA:
352
+ const reasoning = data.text;
353
+ if (!reasoning)
354
+ return;
355
+ if (lastPart?.type === 'reasoning') {
356
+ lastPart.text += reasoning;
349
357
  }
350
- lastStep.reasoning += data.text || data.textDelta;
351
- observer.next({ message, changedPart: undefined });
358
+ else {
359
+ lastPart = { type: 'reasoning', text: reasoning };
360
+ message.content.push(lastPart);
361
+ }
362
+ observer.next({ message, changedPart: lastPart });
352
363
  return;
353
364
  case DataStreamType.TEXT_DELTA:
354
- lastStep.text += data.text || data.textDelta;
355
- // FUTURE: this setting the same value to message.content is probably not correct;
356
- // duplicating the same text wastes space so not necessary given it's already in steps, and
357
- // the Vercel SDK sets message.content to the text of the LAST step only (the summarizing step)
358
- message.content += data.text || data.textDelta;
359
- observer.next({ message, changedPart: undefined });
365
+ const text = data.textDelta || data.text;
366
+ if (!text)
367
+ return;
368
+ if (lastPart?.type === 'text') {
369
+ lastPart.text += text;
370
+ }
371
+ else {
372
+ lastPart = { type: 'text', text: text };
373
+ message.content.push(lastPart);
374
+ }
375
+ observer.next({ message, changedPart: lastPart });
360
376
  return;
361
377
  case DataStreamType.TOOL_INPUT_START:
362
378
  observer.next({
363
379
  message,
364
- changedPart: this.addToolCallInfo('tool-input-streaming', data, lastStep)
380
+ changedPart: this.addToolCallInfo('tool-input-streaming', data, message.content)
365
381
  });
366
382
  return;
367
383
  case DataStreamType.TOOL_CALL:
368
384
  observer.next({
369
385
  message,
370
- changedPart: this.addToolCallInfo('tool-executing', data, lastStep)
386
+ changedPart: this.addToolCallInfo('tool-executing', data, message.content)
371
387
  });
372
388
  return;
373
389
  case DataStreamType.TOOL_RESULT:
374
390
  observer.next({
375
391
  message,
376
- changedPart: this.addToolCallInfo('tool-result', data, lastStep)
392
+ changedPart: this.addToolCallInfo('tool-result', data, message.content)
377
393
  });
378
394
  return;
379
395
  case DataStreamType.FINISH:
@@ -404,10 +420,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
404
420
  }]
405
421
  }], ctorParameters: () => [{ type: i1.FetchClient }] });
406
422
  /**
407
- * The default method for reducing the size of the message history so it is ready to be sent to the LLM agent.
423
+ * The default implementation of for reducing the size of the message history so it is ready to be sent to the LLM agent.
408
424
  *
409
425
  * This is important since old tool inputs and outputs can be very large and fill up the agent's context window.
410
426
  *
427
+ * Implements `pruneMessagesFunction`.
428
+ *
411
429
  * When sending an AI request you can provide your own function instead of using this one,
412
430
  * or you can write your own function that calls this and adds extra logic,
413
431
  * for example to suppress specific tools from the AIMessage, or
@@ -421,10 +439,23 @@ function defaultPruneMessagesForAgent(messages) {
421
439
  // to avoid too many tokens and context window consumption.
422
440
  // Some applications will want to entirely remove specific tool calls that have only transient use,
423
441
  // which can be done by providing their own pruneMessagesForAgent function.
424
- return messages.map(m => ({
425
- role: m.role,
426
- content: m.content
427
- }));
442
+ return messages.map(m => m.role !== 'assistant'
443
+ ? {
444
+ role: m.role,
445
+ content: m.content
446
+ }
447
+ : {
448
+ role: m.role,
449
+ content: [
450
+ {
451
+ type: 'text',
452
+ text: m.content
453
+ .filter((part) => part.type === 'text')
454
+ .map(part => part.text)
455
+ .join('\n\n')
456
+ }
457
+ ]
458
+ });
428
459
  }
429
460
 
430
461
  /**