@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
388 lines (382 loc) • 30.9 kB
JavaScript
import { NgClass, JsonPipe, AsyncPipe, NgComponentOutlet } from '@angular/common';
import * as i0 from '@angular/core';
import { Input, Component, EventEmitter, inject, Output } from '@angular/core';
import { ListGroupComponent, ListItemComponent, ListItemCollapseComponent, ListItemBodyComponent, ListItemIconComponent, MarkdownToHtmlPipe, C8yTranslatePipe, GainsightService, AlertService, LoadingComponent, EmptyStateComponent, ContextRouteService } from '@c8y/ngx-components';
import { AIService } from '@c8y/ngx-components/ai';
import { AiChatComponent, AiChatSuggestionComponent, AiChatMessageComponent, AiChatMessageActionComponent } from '@c8y/ngx-components/ai/ai-chat';
import { gettext } from '@c8y/ngx-components/gettext';
import { BehaviorSubject, map, of } from 'rxjs';
import { WidgetConfigService, WidgetConfigFeedbackComponent } from '@c8y/ngx-components/context-dashboard';
class AgentStepFeedbackComponent {
constructor() {
this.loading = false;
this.collapsed = true;
this.canCollapse = false;
}
ngOnInit() {
if (this.step) {
this.parseDefaultAgentStep(this.step);
}
}
ngOnChanges(changes) {
if (changes.step) {
this.parseDefaultAgentStep(changes.step.currentValue);
}
}
parseDefaultAgentStep(step) {
if (step.reasoning) {
this.label = gettext('Reasoning');
this.loading = false;
this.canCollapse = true;
this.collapsed = false;
}
if (step.toolCalls.length > 0 && !step.toolResults?.length) {
this.label = gettext('Calling a tool');
this.loading = true;
this.canCollapse = true;
this.collapsed = true;
}
else if (step.toolResults?.length > 0) {
this.label = gettext('Tool result');
this.loading = false;
this.canCollapse = true;
this.collapsed = true;
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AgentStepFeedbackComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: AgentStepFeedbackComponent, isStandalone: true, selector: "c8y-agent-step-feedback", inputs: { step: "step", label: "label", loading: "loading", collapsed: "collapsed", canCollapse: "canCollapse" }, host: { classAttribute: "agent-step-feedback" }, usesOnChanges: true, ngImport: i0, template: "@if (!step.reasoning) {\n <div [innerHTML]=\"step.text | markdownToHtml | async\"></div>\n}\n@if (label) {\n <c8y-list-group class=\"m-t-16 m-b-16\">\n <c8y-li\n [active]=\"!loading\"\n [collapsed]=\"collapsed\"\n >\n <c8y-li-icon>\n <span\n class=\"btn-ai btn-ai-hint btn-sm\"\n [ngClass]=\"{ working: loading }\"\n >\n <span></span>\n </span>\n </c8y-li-icon>\n <c8y-li-body>\n {{ label | translate }}\n </c8y-li-body>\n\n @if (canCollapse) {\n <c8y-li-collapse>\n @if (step.reasoning) {\n <div [innerHTML]=\"step.reasoning | markdownToHtml | async\"></div>\n } @else if (step) {\n <pre\n class=\"fit-w\"\n style=\"max-height: 320px\"\n >{{ step | json }}</pre\n >\n }\n </c8y-li-collapse>\n }\n </c8y-li>\n </c8y-list-group>\n}\n", dependencies: [{ kind: "component", type: ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: ListItemCollapseComponent, selector: "c8y-list-item-collapse, c8y-li-collapse", inputs: ["collapseWay"] }, { kind: "component", type: ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "component", type: ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: MarkdownToHtmlPipe, name: "markdownToHtml" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AgentStepFeedbackComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-agent-step-feedback', standalone: true, imports: [
ListGroupComponent,
ListItemComponent,
ListItemCollapseComponent,
ListItemBodyComponent,
ListItemIconComponent,
NgClass,
JsonPipe,
MarkdownToHtmlPipe,
AsyncPipe,
C8yTranslatePipe
], host: { class: 'agent-step-feedback' }, template: "@if (!step.reasoning) {\n <div [innerHTML]=\"step.text | markdownToHtml | async\"></div>\n}\n@if (label) {\n <c8y-list-group class=\"m-t-16 m-b-16\">\n <c8y-li\n [active]=\"!loading\"\n [collapsed]=\"collapsed\"\n >\n <c8y-li-icon>\n <span\n class=\"btn-ai btn-ai-hint btn-sm\"\n [ngClass]=\"{ working: loading }\"\n >\n <span></span>\n </span>\n </c8y-li-icon>\n <c8y-li-body>\n {{ label | translate }}\n </c8y-li-body>\n\n @if (canCollapse) {\n <c8y-li-collapse>\n @if (step.reasoning) {\n <div [innerHTML]=\"step.reasoning | markdownToHtml | async\"></div>\n } @else if (step) {\n <pre\n class=\"fit-w\"\n style=\"max-height: 320px\"\n >{{ step | json }}</pre\n >\n }\n </c8y-li-collapse>\n }\n </c8y-li>\n </c8y-list-group>\n}\n" }]
}], propDecorators: { step: [{
type: Input,
args: [{ required: true }]
}], label: [{
type: Input
}], loading: [{
type: Input
}], collapsed: [{
type: Input
}], canCollapse: [{
type: Input
}] } });
class AgentChatComponent {
constructor() {
this.suggestions = [];
this.headline = gettext('Welcome!');
this.autoInstallAgents = true;
this.variables = {};
this.stepRenderComponent = AgentStepFeedbackComponent;
this.onMessageDelta = new EventEmitter();
this.onMessageText = new EventEmitter();
this.onMessageFinish = new EventEmitter();
this.onToolResult = new EventEmitter();
this.isLoading = false;
/**
* A stream of AI messages representing the conversation.
*/
this.messages$ = new BehaviorSubject([]);
this.hasError = true;
this.canCreate = false;
this.errorMsg = '';
this.prompt = '';
this.aiService = inject(AIService);
this.gainsightService = inject(GainsightService);
this.alertService = inject(AlertService);
this.defaultAgentStepRendererPipe = (source) => {
return source.pipe(map(steps => steps.map(step => {
if (step.reasoning || step.toolCalls || step.toolResults) {
return { content: this.stepRenderComponent, origin: { ...step } };
}
return { content: step.text, origin: { ...step } };
})));
};
}
async ngOnInit() {
this.isLoading = true;
this.agentName = typeof this.agent === 'string' ? this.agent : this.agent.definitions[0].name;
try {
const agentHealth = await this.aiService.getAgentHealth(this.agentName);
this.composeErrorMessage(agentHealth);
if (typeof this.agent !== 'string' && this.agent.snapshot) {
this.createAgent();
}
}
catch (ex) {
this.errorMsg = gettext('Microservice not found. Please contact your administrator.');
this.hasError = true;
}
this.isLoading = false;
}
async sendMessage(message) {
this.messages$.next([...this.messages$.value, message]);
this.isLoading = true;
this.abortController = new AbortController();
const currentAssistantMessage = {
role: 'assistant',
content: ''
};
this.messages$.next([...this.messages$.value, currentAssistantMessage]);
const stream = await this.aiService.stream$(this.agentName, this.messages$.value.filter(m => m !== currentAssistantMessage), this.variables, this.abortController);
if (this.assistantSubscription) {
this.assistantSubscription.unsubscribe();
}
this.assistantSubscription = stream.subscribe((messageFromAssistant) => this.processAgentMessage(currentAssistantMessage, messageFromAssistant, this.agentName, message));
}
ngOnDestroy() {
this.cancel();
}
reprompt(userMessage) {
const index = this.messages$.value.indexOf(userMessage);
if (index > -1) {
this.messages$.next(this.messages$.value.slice(0, index));
this.prompt = userMessage.content;
}
}
rate(assistantMessage, positive) {
const agentName = typeof this.agent === 'string' ? this.agent : this.agent.label;
this.gainsightService.triggerEvent('ai.agent.feedback', {
positive,
assistant: assistantMessage,
user: this.messages$.value[this.messages$.value.indexOf(assistantMessage) - 1],
agent: agentName
});
}
reload(assistantMessage) {
const index = this.messages$.value.indexOf(assistantMessage);
const userMessage = this.messages$.value[index - 1];
if (index > -1) {
this.messages$.next(this.messages$.value.slice(0, index - 1));
this.sendMessage({
role: 'user',
content: userMessage.content,
timestamp: new Date().toISOString()
});
}
}
cancel() {
if (this.abortController) {
this.abortController.abort();
}
if (this.assistantSubscription) {
this.assistantSubscription.unsubscribe();
}
this.isLoading = false;
}
async createAgent() {
this.isLoading = true;
try {
await this.aiService.createOrUpdateAgent(this.agent);
this.hasError = false;
}
catch (ex) {
this.alertService.danger(gettext('Failed to create the agent.'));
this.hasError = true;
}
this.isLoading = false;
}
composeErrorMessage(agentHealth) {
if (agentHealth.exists) {
this.errorMsg = '';
this.hasError = false;
return;
}
this.hasError = true;
if (!agentHealth.isProviderConfigured) {
this.errorMsg = gettext('AI provider is not configured. Please contact your administrator.');
return;
}
if (agentHealth.canCreate && typeof this.agent === 'string') {
this.errorMsg = gettext('The agent does not exist. Provide the agent definition in the agent manager to use it.');
return;
}
if (agentHealth.canCreate && typeof this.agent !== 'string') {
this.canCreate = true;
if (this.autoInstallAgents) {
this.createAgent();
return;
}
this.errorMsg = gettext('The agent does not exist. You can create it now.');
return;
}
if (!agentHealth.canCreate) {
this.errorMsg = gettext('The agent does not exist. Please contact your administrator.');
if (agentHealth.messages?.length) {
this.errorMsg += '\n' + agentHealth.messages.join(' ');
}
return;
}
this.errorMsg = gettext('Unknown error. Please contact your administrator.');
}
processAgentMessage(currentAssistantMessage, messageFromAssistant, agentName, message) {
currentAssistantMessage.content = messageFromAssistant.content;
const steps = messageFromAssistant.steps || [];
const lastStep = steps.length ? steps[steps.length - 1] : null;
this.onMessageDelta.emit(lastStep.textDelta);
this.onMessageText.emit(lastStep.text);
currentAssistantMessage.componentSteps$ = of(steps).pipe(this.defaultAgentStepRendererPipe);
if (messageFromAssistant.finishReason === 'stop') {
currentAssistantMessage.timestamp = new Date().toISOString();
this.onMessageFinish.emit(currentAssistantMessage.content);
this.gainsightService.triggerEvent('ai.agent.message', {
agent: agentName,
user: message,
assistant: currentAssistantMessage.content
});
this.isLoading = false;
}
if (messageFromAssistant.finishReason === 'error') {
currentAssistantMessage.timestamp = new Date().toISOString();
this.isLoading = false;
}
if (lastStep?.toolResults) {
lastStep.toolResults.forEach(toolResult => {
this.onToolResult.emit(toolResult);
});
}
// as we are mutating the currentAssistantMessage object
// which is already in the messages array we need to emit a new array reference
this.messages$.next([...this.messages$.value]);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AgentChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: AgentChatComponent, isStandalone: true, selector: "c8y-agent-chat", inputs: { agent: "agent", suggestions: "suggestions", title: "title", headline: "headline", welcomeText: "welcomeText", autoInstallAgents: "autoInstallAgents", variables: "variables", stepRenderComponent: "stepRenderComponent" }, outputs: { onMessageDelta: "onMessageDelta", onMessageText: "onMessageText", onMessageFinish: "onMessageFinish", onToolResult: "onToolResult" }, ngImport: i0, template: "@if (hasError && isLoading) {\n <c8y-loading class=\"m-auto\"></c8y-loading>\n}\n@if (hasError && !isLoading) {\n <c8y-ui-empty-state\n class=\"m-auto\"\n [icon]=\"'disclaimer'\"\n [title]=\"'An error occurred' | translate\"\n [subtitle]=\"errorMsg | translate\"\n [horizontal]=\"true\"\n >\n @if (canCreate) {\n <div class=\"text-center m-t-16 m-b-16\">\n <button\n class=\"btn btn-primary\"\n (click)=\"createAgent()\"\n >\n {{ 'Create agent' | translate }}\n </button>\n </div>\n }\n </c8y-ui-empty-state>\n}\n\n@if (!hasError) {\n <c8y-ai-chat\n (onMessage)=\"sendMessage($event)\"\n [isLoading]=\"isLoading\"\n (onCancel)=\"cancel()\"\n [config]=\"{ title: title, headline: headline, welcomeText: welcomeText }\"\n [prompt]=\"prompt\"\n >\n @for (message of messages$ | async; track $index; let i = $index) {\n <c8y-ai-chat-message\n [message]=\"{ role: message.role, content: '', timestamp: message.timestamp }\"\n >\n @if (!message.componentSteps$) {\n <div [innerHTML]=\"message.content | markdownToHtml | async\"></div>\n }\n @for (step of message.componentSteps$ | async; track $index) {\n @if (typeof step.content === 'string') {\n <div [innerHTML]=\"step.content | markdownToHtml | async\"></div>\n } @else {\n <ng-container\n [ngComponentOutlet]=\"step.content\"\n [ngComponentOutletInputs]=\"{ step: step.origin }\"\n ></ng-container>\n }\n }\n\n @if (message.role === 'user') {\n <c8y-ai-chat-message-action\n icon=\"pencil\"\n [tooltip]=\"'Edit and resend this message' | translate\"\n [disabled]=\"isLoading\"\n (click)=\"reprompt(message)\"\n ></c8y-ai-chat-message-action>\n }\n\n @if (message.role === 'assistant' && (i < (messages$ | async)?.length - 1 || !isLoading)) {\n <c8y-ai-chat-message-action\n icon=\"thumbs-up\"\n [tooltip]=\"'This is useful' | translate\"\n [disabled]=\"isLoading\"\n (click)=\"rate(message, true)\"\n ></c8y-ai-chat-message-action>\n }\n\n @if (message.role === 'assistant' && (i < (messages$ | async)?.length - 1 || !isLoading)) {\n <c8y-ai-chat-message-action\n icon=\"thumbs-down\"\n [tooltip]=\"'This is not useful' | translate\"\n [disabled]=\"isLoading\"\n (click)=\"rate(message, false)\"\n ></c8y-ai-chat-message-action>\n }\n\n @if (message.role === 'assistant' && (i < (messages$ | async)?.length - 1 || !isLoading)) {\n <c8y-ai-chat-message-action\n icon=\"refresh\"\n [tooltip]=\"'Regenerate this response' | translate\"\n [disabled]=\"isLoading\"\n (click)=\"reload(message)\"\n ></c8y-ai-chat-message-action>\n }\n\n @if (\n !message.content && message.role === 'assistant' && i === (messages$ | async)?.length - 1\n ) {\n <div class=\"text-center\">\n <c8y-loading></c8y-loading>\n </div>\n }\n </c8y-ai-chat-message>\n }\n\n @for (suggestion of suggestions; track $index) {\n <c8y-ai-chat-suggestion\n [icon]=\"suggestion.icon || 'c8y-bulb'\"\n [useAiButtons]=\"true\"\n [label]=\"suggestion.label\"\n [prompt]=\"suggestion.prompt\"\n (suggestionClicked)=\"sendMessage($event)\"\n [disabled]=\"isLoading\"\n ></c8y-ai-chat-suggestion>\n }\n </c8y-ai-chat>\n}\n", dependencies: [{ kind: "component", type: AiChatComponent, selector: "c8y-ai-chat", inputs: ["isLoading", "disabled", "prompt", "config"], outputs: ["onMessage", "onCancel"] }, { kind: "component", type: AiChatSuggestionComponent, selector: "c8y-ai-chat-suggestion", inputs: ["label", "prompt", "icon", "useAiButtons", "disabled"], outputs: ["suggestionClicked"] }, { kind: "component", type: AiChatMessageComponent, selector: "c8y-ai-chat-message", inputs: ["role", "message"] }, { kind: "component", type: AiChatMessageActionComponent, selector: "c8y-ai-chat-message-action", inputs: ["disabled", "tooltip", "icon"], outputs: ["click"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: MarkdownToHtmlPipe, name: "markdownToHtml" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AgentChatComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-agent-chat', imports: [
AiChatComponent,
AiChatSuggestionComponent,
AiChatMessageComponent,
AiChatMessageActionComponent,
LoadingComponent,
MarkdownToHtmlPipe,
AsyncPipe,
NgComponentOutlet,
C8yTranslatePipe,
EmptyStateComponent
], template: "@if (hasError && isLoading) {\n <c8y-loading class=\"m-auto\"></c8y-loading>\n}\n@if (hasError && !isLoading) {\n <c8y-ui-empty-state\n class=\"m-auto\"\n [icon]=\"'disclaimer'\"\n [title]=\"'An error occurred' | translate\"\n [subtitle]=\"errorMsg | translate\"\n [horizontal]=\"true\"\n >\n @if (canCreate) {\n <div class=\"text-center m-t-16 m-b-16\">\n <button\n class=\"btn btn-primary\"\n (click)=\"createAgent()\"\n >\n {{ 'Create agent' | translate }}\n </button>\n </div>\n }\n </c8y-ui-empty-state>\n}\n\n@if (!hasError) {\n <c8y-ai-chat\n (onMessage)=\"sendMessage($event)\"\n [isLoading]=\"isLoading\"\n (onCancel)=\"cancel()\"\n [config]=\"{ title: title, headline: headline, welcomeText: welcomeText }\"\n [prompt]=\"prompt\"\n >\n @for (message of messages$ | async; track $index; let i = $index) {\n <c8y-ai-chat-message\n [message]=\"{ role: message.role, content: '', timestamp: message.timestamp }\"\n >\n @if (!message.componentSteps$) {\n <div [innerHTML]=\"message.content | markdownToHtml | async\"></div>\n }\n @for (step of message.componentSteps$ | async; track $index) {\n @if (typeof step.content === 'string') {\n <div [innerHTML]=\"step.content | markdownToHtml | async\"></div>\n } @else {\n <ng-container\n [ngComponentOutlet]=\"step.content\"\n [ngComponentOutletInputs]=\"{ step: step.origin }\"\n ></ng-container>\n }\n }\n\n @if (message.role === 'user') {\n <c8y-ai-chat-message-action\n icon=\"pencil\"\n [tooltip]=\"'Edit and resend this message' | translate\"\n [disabled]=\"isLoading\"\n (click)=\"reprompt(message)\"\n ></c8y-ai-chat-message-action>\n }\n\n @if (message.role === 'assistant' && (i < (messages$ | async)?.length - 1 || !isLoading)) {\n <c8y-ai-chat-message-action\n icon=\"thumbs-up\"\n [tooltip]=\"'This is useful' | translate\"\n [disabled]=\"isLoading\"\n (click)=\"rate(message, true)\"\n ></c8y-ai-chat-message-action>\n }\n\n @if (message.role === 'assistant' && (i < (messages$ | async)?.length - 1 || !isLoading)) {\n <c8y-ai-chat-message-action\n icon=\"thumbs-down\"\n [tooltip]=\"'This is not useful' | translate\"\n [disabled]=\"isLoading\"\n (click)=\"rate(message, false)\"\n ></c8y-ai-chat-message-action>\n }\n\n @if (message.role === 'assistant' && (i < (messages$ | async)?.length - 1 || !isLoading)) {\n <c8y-ai-chat-message-action\n icon=\"refresh\"\n [tooltip]=\"'Regenerate this response' | translate\"\n [disabled]=\"isLoading\"\n (click)=\"reload(message)\"\n ></c8y-ai-chat-message-action>\n }\n\n @if (\n !message.content && message.role === 'assistant' && i === (messages$ | async)?.length - 1\n ) {\n <div class=\"text-center\">\n <c8y-loading></c8y-loading>\n </div>\n }\n </c8y-ai-chat-message>\n }\n\n @for (suggestion of suggestions; track $index) {\n <c8y-ai-chat-suggestion\n [icon]=\"suggestion.icon || 'c8y-bulb'\"\n [useAiButtons]=\"true\"\n [label]=\"suggestion.label\"\n [prompt]=\"suggestion.prompt\"\n (suggestionClicked)=\"sendMessage($event)\"\n [disabled]=\"isLoading\"\n ></c8y-ai-chat-suggestion>\n }\n </c8y-ai-chat>\n}\n" }]
}], propDecorators: { agent: [{
type: Input,
args: [{ required: true }]
}], suggestions: [{
type: Input
}], title: [{
type: Input
}], headline: [{
type: Input
}], welcomeText: [{
type: Input
}], autoInstallAgents: [{
type: Input
}], variables: [{
type: Input
}], stepRenderComponent: [{
type: Input
}], onMessageDelta: [{
type: Output
}], onMessageText: [{
type: Output
}], onMessageFinish: [{
type: Output
}], onToolResult: [{
type: Output
}] } });
class WidgetAiChatSectionComponent {
constructor() {
this.suggestions = [];
this.headline = gettext('Welcome!');
this.title = gettext('What can I help you with?');
this.useContextAsVariable = true;
this.contextVariableName = 'c8yContext';
this.widgetConfigService = inject(WidgetConfigService);
this.alertService = inject(AlertService);
this.contextRouteService = inject(ContextRouteService);
/**
* A component that is used to render each step in the chat. By default, it uses the `AgentStepFeedbackComponent`.
* You can provide your own component by returning it from this callback.
*
* @returns A promise that resolves to a component type.
*/
this.loadRenderStepComponent = () => Promise.resolve(AgentStepFeedbackComponent);
/**
* A callback that is invoked when a tool result is returned. The function can return either:
* - `undefined` or `void`: No action is taken.
* - an object which is stored to the widget configuration.
*/
this.onToolResult = () => undefined;
}
/**
* @ignore
*/
async ngOnInit() {
if (!this.variables && this.useContextAsVariable) {
const { contextData } = this.contextRouteService.activatedContextData;
this.variables = {
[this.contextVariableName]: contextData || this.widgetConfigService.currentConfig.device
};
}
this._renderStepComponent = await this.loadRenderStepComponent();
}
/**
* Handles the tool result returned from the AI agent.
* @param tool The tool result returned from the AI agent.
*/
toolResultHandler(tool) {
try {
const parsedResult = this.onToolResult(tool);
if (!parsedResult) {
return;
}
this.widgetConfigService.updateConfig({
config: {
...this.widgetConfigService.currentConfig,
...parsedResult
}
}, true);
}
catch (e) {
this.alertService.danger(gettext('There was an error processing the AI response.'));
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: WidgetAiChatSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: WidgetAiChatSectionComponent, isStandalone: true, selector: "c8y-widget-ai-chat-section", inputs: { suggestions: "suggestions", agent: "agent", headline: "headline", title: "title", welcomeText: "welcomeText", variables: "variables", useContextAsVariable: "useContextAsVariable", contextVariableName: "contextVariableName", loadRenderStepComponent: "loadRenderStepComponent" }, ngImport: i0, template: "<c8y-widget-config-feedback>\n <div\n class=\"m-l-4 btn-ai btn-ai-hint btn-sm\"\n [title]=\"'AI code assistant' | translate\"\n >\n <span></span>\n </div>\n</c8y-widget-config-feedback>\n\n<c8y-agent-chat\n [title]=\"title | translate\"\n [headline]=\"headline | translate\"\n [welcomeText]=\"welcomeText | translate\"\n #agentChat\n [suggestions]=\"(agentChat.messages$ | async)?.length === 0 ? suggestions : []\"\n [agent]=\"agent\"\n [variables]=\"variables\"\n [stepRenderComponent]=\"_renderStepComponent\"\n (onToolResult)=\"toolResultHandler($event)\"\n></c8y-agent-chat>\n", dependencies: [{ kind: "component", type: AgentChatComponent, selector: "c8y-agent-chat", inputs: ["agent", "suggestions", "title", "headline", "welcomeText", "autoInstallAgents", "variables", "stepRenderComponent"], outputs: ["onMessageDelta", "onMessageText", "onMessageFinish", "onToolResult"] }, { kind: "component", type: WidgetConfigFeedbackComponent, selector: "c8y-widget-config-feedback" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: WidgetAiChatSectionComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-widget-ai-chat-section', imports: [AgentChatComponent, C8yTranslatePipe, AsyncPipe, WidgetConfigFeedbackComponent], standalone: true, template: "<c8y-widget-config-feedback>\n <div\n class=\"m-l-4 btn-ai btn-ai-hint btn-sm\"\n [title]=\"'AI code assistant' | translate\"\n >\n <span></span>\n </div>\n</c8y-widget-config-feedback>\n\n<c8y-agent-chat\n [title]=\"title | translate\"\n [headline]=\"headline | translate\"\n [welcomeText]=\"welcomeText | translate\"\n #agentChat\n [suggestions]=\"(agentChat.messages$ | async)?.length === 0 ? suggestions : []\"\n [agent]=\"agent\"\n [variables]=\"variables\"\n [stepRenderComponent]=\"_renderStepComponent\"\n (onToolResult)=\"toolResultHandler($event)\"\n></c8y-agent-chat>\n" }]
}], propDecorators: { suggestions: [{
type: Input
}], agent: [{
type: Input
}], headline: [{
type: Input
}], title: [{
type: Input
}], welcomeText: [{
type: Input
}], variables: [{
type: Input
}], useContextAsVariable: [{
type: Input
}], contextVariableName: [{
type: Input
}], loadRenderStepComponent: [{
type: Input
}] } });
/**
* Generated bundle index. Do not edit.
*/
export { AgentChatComponent, AgentStepFeedbackComponent, WidgetAiChatSectionComponent };
//# sourceMappingURL=c8y-ngx-components-ai-agent-chat.mjs.map