@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
342 lines (338 loc) • 24.2 kB
TypeScript
import * as _angular_core from '@angular/core';
import { OnInit, OnDestroy, OnChanges, TemplateRef, Type, SimpleChanges, Injector } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { ClientAgentDefinition, Suggestion, AgentChatConfig, AssistantMessageDisplayConfig, AIAssistantMessage, AIStreamResponse, pruneMessagesFunction, AIMessage, ToolCallPart, ChatHistory, AIUserMessage, WidgetAiChatSectionComponentConfig } from '@c8y/ngx-components/ai';
import { Observable } from 'rxjs';
declare class AgentChatComponent implements OnInit, OnDestroy, OnChanges {
readonly translateService: TranslateService;
private readonly datePipe;
private readonly modalService;
/** Debug logging function for AI messages. Can be enabled at runtime with localStorage.setItem('c8y-debug-log.agent-chat', 'true'); */
readonly debugLog: (message: string, ...args: any[]) => void;
/**
* Identifies which AI agent from the AI Agent Manager service will be used by this component.
*
* Where possible, provide a `ClientAgentDefinition` rather than just a name.
*
* It is recommended to define a `toolCallConfig` in the same place you define `ClientAgentDefinition`,
* and to use the keys from `assistantMessageDisplayConfig.toolCallConfig`
* in the `ClientAgentDefinition` tools list.
*/
readonly agent: _angular_core.InputSignal<string | ClientAgentDefinition>;
get agentName(): string;
get agentDefinition(): ClientAgentDefinition | undefined;
/**
* Clickable suggestions buttons to display just above the chat, for likely next user actions.
* These may be hardcoded or be set by the AI agent (e.g. in a tool call).
* This input should be `undefined` to indicate that there are no new suggestions yet, and that any restored from the chat history should be used instead.
* You can use the `isWelcoming` output to show different suggestions while the initial welcome message is displayed.
*/
readonly suggestions: _angular_core.InputSignal<Suggestion[]>;
/** ChatConfig to customize the ai-chat component's configuration if desired. */
readonly chatConfig: _angular_core.InputSignal<Partial<AgentChatConfig>>;
/** Template for customizing the welcome view using `ng-template`. */
readonly welcomeTemplate: _angular_core.InputSignal<TemplateRef<any>>;
/** Indicates whether the component has zero messages and is showing the welcome page. */
readonly isWelcoming: _angular_core.Signal<boolean>;
/** Configures whether this component should automatically create the provided `agent: ClientAgentDefinition`
* if an agent of that name doesn't already exist. This is an alternative to the usual mechanism of configuring
* agents using a `.agent.c8y.ts` file.
*/
readonly autoCreateAgents: _angular_core.InputSignal<boolean>;
/** Variables to pass to the AI agent for placeholders specified in the agent's system prompt. */
readonly variables: _angular_core.InputSignal<Record<string, any>>;
/**
* Allows overriding the component used to render messages from the AI assistant, if the default
* AiChatAssistantMessageComponent does not do what you need.
*
* The component must accept a single input `assistantMessageContext: AssistantMessageContext`.
* This object contains all data needed to render the assistant message and is forward-compatible with future additions.
*
* Example usage:
* <c8y-agent-chat [assistantMessageComponent]="MyCustomAssistantMessageComponent"></c8y-agent-chat>
*/
readonly assistantMessageComponent: _angular_core.InputSignal<Type<any>>;
/**
* Configuration passed to `AiChatAssistantMessageComponent` for controlling how messages from the assistant
* are rendered, including tool calls.
*
* If you are performing any tool calls it is recommended to configure the `toolCallConfig`
* to provide localized display names for the tools used in your `AgentDefinitionConfig`.
*/
readonly assistantMessageDisplayConfig: _angular_core.InputSignal<AssistantMessageDisplayConfig>;
/**
* Optional function to preprocess messages from the assistant before they are displayed, for example if you need to remove special
* tagged sections from the content to move into simulated tool calls.
*
* This function may be called many times for each message, as more steps, tool calls and content are streamed from the agent.
*
* If you modify any part of the message other than the `changedPart`, you should replace it with a new shallow copy of the object so
* that change detection works correctly. This is not necessary for changedPart.
*
* @param message The message from the AI assistant.
* @param changedPart The part of the message that has changed, which can be modified in-place if desired.
*/
readonly preprocessAgentMessage: _angular_core.InputSignal<(message: AIAssistantMessage, changedPart?: AIStreamResponse["changedPart"]) => AIAssistantMessage>;
/** Optional function to override how the message history is prepared and compacted ready for sending with
* agent requests. This overrides the default behaviour from `defaultPruneMessagesForAgent`.
*
* For example this can be used to remove unnecessary information to minimize tokens, reduce the number of messages,
* or to make what is sent to the agent different from what is rendered in the UI.
*/
readonly pruneMessagesForAgent: _angular_core.InputSignal<pruneMessagesFunction>;
/** When true, skips the agent health check on initialization.
* Use this when the component is used with the test endpoint (snapshot mode) where the agent
* does not need to exist on the backend. Default: false. */
readonly skipHealthCheck: _angular_core.InputSignal<boolean>;
/** Input that provides a previously-saved chat history snapshot to restore. */
readonly initialChatHistory: _angular_core.InputSignal<string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/ any | {
[key: string]: string | number | boolean | /*elided*/ any | /*elided*/ any;
})[] | {
[key: string]: string | number | boolean | (string | number | boolean | /*elided*/ any | /*elided*/ any)[] | /*elided*/ any;
})[] | {
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/ any | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any;
})[] | {
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/ any | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any;
})[] | {
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/ any | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any;
})[] | {
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/ any | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any;
})[] | {
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/ any | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any;
})[] | {
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/ any | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any;
})[] | {
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/ any | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any;
})[] | {
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/ any | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any;
})[] | {
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/ any | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any;
})[] | {
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/ any | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any)[] | /*elided*/ any;
}>;
/** Suggestions that were restored from the initial chat history; used if `suggestions` input is not yet set. */
protected _restoredSuggestions: Suggestion[];
/**
* An optional function that returns a message sent in AI agent requests just before each new user message to provide context or "grounding" to
* anchor the AI's response - such as the current state of the document the AI is helping with.
*
* Typically this string would begin with a special prefix (e.g. "[STATE_SNAPSHOT]") that is described by the system prompt.
*
* This message does not form part of the chat history, to avoid confusing the AI agent with older grounding state.
* It is injected into the message history just before the latest user message as per standard recommendations,
* since AI gives more attention to the recent content.
*/
readonly groundingContextProvider: _angular_core.InputSignal<() => string>;
/**
* Provides application-defined fields to enrich the user feedback tracking data for this component.
*
* Do not include Intellectual Property or Personal Identifiable Information in this object, as it may
* be included in feedback data sent to third-party services.
*/
readonly userAnalyticsContext: _angular_core.InputSignal<Record<string, any>>;
readonly onMessageFinish: _angular_core.OutputEmitterRef<AIMessage>;
/**
* Notified when a tool result is received from the agent.
*
* This is called before it is added to the message displayed in the component.
*
* Tools with a client/UI implementation may provide `output` for the tool
* (e.g. data to render in the UI) by calling `addToolOutput`.
*/
readonly onToolResult: _angular_core.OutputEmitterRef<ToolCallPart<Record<string, unknown>, unknown>>;
/** Notified when the user presses the positive or negative feedback buttons for an assistant message.*/
readonly onFeedback: _angular_core.OutputEmitterRef<{
userMessage: AIMessage;
assistantMessage: AIMessage;
feedbackPositive: boolean;
}>;
/** The model name from the most recently received metadata while streaming a response, which is used by the analytics. */
protected model?: string;
/** The system prompt from the most recently received metadata while streaming a response, which is used by the analytics. */
protected systemPrompt?: Array<{
text: string;
type: string;
}>;
/**
* Emitted after any meaningful mutation of the messages list (send, finish, reprompt, reload, delete, reset).
* Allows the parent to react to conversation changes, e.g. to persist the conversation.
*/
readonly onMessagesChange: _angular_core.OutputEmitterRef<AIMessage[]>;
protected readonly _isLoading: _angular_core.WritableSignal<boolean>;
/** Is an AI agent request currently in progress. This can be used to disable UI elements while a reply (which might change the state) is being loaded. */
get isLoadingAiResponse(): _angular_core.Signal<boolean>;
private readonly aiAgentManagerApplicationName;
/** Stores any error with the agent or backend microservice. This error message is already translated. */
protected readonly _agentHealthError: _angular_core.WritableSignal<string>;
/** Stores the most recent agent health check response, or `undefined` while the initial check is in progress. */
private readonly _agentHealth;
/** Returns the most recent agent health check status such as `ready`, or an error. */
get agentHealthStatus(): "loading" | "missing-microservice" | "missing-permissions" | "missing-provider" | "missing-agent" | "ready";
/** Stores any detailed error messages from the backend. */
protected readonly agentHealthDetailedMessages: _angular_core.WritableSignal<string>;
/**
* Stores any error from LLM call.
*
* If possible this string is translated already or registered with `gettext`.
* In practice, this may not be translated if it comes from the backend.
*/
readonly agentRequestError: _angular_core.WritableSignal<string>;
readonly messages: _angular_core.WritableSignal<AIMessage[]>;
/** Computed cumulative token usage across all messages in the conversation. */
readonly cumulativeUsage: _angular_core.Signal<{
inputTokens: number;
outputTokens: number;
totalTokens: number;
}>;
/**
* Computed signal holding the last assistant message, which is the one which may be rapidly changing as we
* stream it back. This allows us to update the UI reactively without affecting the rest of the message history.
*/
protected readonly lastAssistantMessageContext: _angular_core.Signal<{
message: AIAssistantMessage;
config: AssistantMessageDisplayConfig;
isMessageLoading: boolean;
messageDisplayIndex: number;
}>;
/** If the create agent button should be shown to the user. */
canCreate: boolean;
prompt: string;
private readonly aiService;
private readonly userAnalyticsService;
private readonly alertService;
private readonly chatHistoryService;
private abortController;
private assistantSubscription;
private pluginContextPath;
private appState;
private readonly assistantMessageComponents;
private get currentContextPath();
/**
* Stores client-supplied tool outputs to override tool results for a given toolCallId in the current assistant message.
* Cleared at the start of each new message.
*/
private _clientToolOutputs;
ngOnInit(): Promise<void>;
ngOnChanges(changes: SimpleChanges): Promise<void>;
/**
* Save the current chat history and suggestions to an opaque, versioned, JSON-serializable snapshot of the chat history for persistence.
*
* To save space, only recent tool results and reasoning are included.
* Additional options for compressing the history can be provided using the config parameters.
*
* @param pruner Optional function to prune/transform messages before serialization.
* If not specified, `ChatHistoryService.createDefaultSerializationMessagePruner()` is used.
*/
saveChatHistory(pruner?: pruneMessagesFunction): ChatHistory;
/** Sends a message to the AI */
sendMessage(message: AIMessage): Promise<void>;
ngOnDestroy(): void;
reprompt(userMessage: AIUserMessage): Promise<void>;
/** Rates an AI message as positive/negative, sending the feedback to GainSight */
rate(assistantMessage: AIAssistantMessage, positive: boolean): Promise<void>;
reload(assistantMessage: AIMessage): void;
cancel(): void;
/** Clears all messages and cancels any in-flight stream. */
resetMessages(): void;
/** Removes the last user message and all assistant messages that follow it from the conversation. */
deleteLastExchange(): void;
/**
* Overrides the output of a specific tool result (in the current assistant message), including optionally indicating that an error occurred.
*
* This can be used to provide output for tool calls that are implemented on the client,
* and is typically called from `onToolResult`.
*
* @param output: A string or JSON-serializable object.
*/
addToolOutput(toolCallId: string, output: any, error?: boolean): void;
createAgent(): Promise<void>;
private initializeChat;
/** Restore chat history from a previously-saved snapshot. Does nothing if the component already has some messages. */
protected _restoreChatHistory(history: ChatHistory | undefined): void;
private checkAgentHealth;
private getAnalyticsMetadataContext;
private handleAgentError;
/**
* Called as responses are incrementally streamed from the agent.
* Reads the current assistant message from the end of the messages array, processes the update,
* and replaces it with a new immutable message object to trigger change detection.
* @param updatedAssistantMsg contains the latest data received from the agent
* @param changedPart if provided, indicates which part of the message was changed in this update
*/
private processAgentMessage;
private handleMessageFinish;
/** Handles sending a message to a text-type agent via SSE streaming. */
private _sendStreamMessage;
/** Handles sending a message to an object-type agent via a single non-streaming request.
* The response JSON is rendered as a fenced code block in the assistant message.
*/
private _sendObjectMessage;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AgentChatComponent, never>;
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AgentChatComponent, "c8y-agent-chat", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "suggestions": { "alias": "suggestions"; "required": false; "isSignal": true; }; "chatConfig": { "alias": "chatConfig"; "required": false; "isSignal": true; }; "welcomeTemplate": { "alias": "welcomeTemplate"; "required": false; "isSignal": true; }; "autoCreateAgents": { "alias": "autoCreateAgents"; "required": false; "isSignal": true; }; "variables": { "alias": "variables"; "required": false; "isSignal": true; }; "assistantMessageComponent": { "alias": "assistantMessageComponent"; "required": false; "isSignal": true; }; "assistantMessageDisplayConfig": { "alias": "assistantMessageDisplayConfig"; "required": false; "isSignal": true; }; "preprocessAgentMessage": { "alias": "preprocessAgentMessage"; "required": false; "isSignal": true; }; "pruneMessagesForAgent": { "alias": "pruneMessagesForAgent"; "required": false; "isSignal": true; }; "skipHealthCheck": { "alias": "skipHealthCheck"; "required": false; "isSignal": true; }; "initialChatHistory": { "alias": "initialChatHistory"; "required": false; "isSignal": true; }; "groundingContextProvider": { "alias": "groundingContextProvider"; "required": false; "isSignal": true; }; "userAnalyticsContext": { "alias": "userAnalyticsContext"; "required": false; "isSignal": true; }; }, { "onMessageFinish": "onMessageFinish"; "onToolResult": "onToolResult"; "onFeedback": "onFeedback"; "onMessagesChange": "onMessagesChange"; }, never, never, true, never>;
}
declare class WidgetAiChatSectionComponent implements OnInit {
/**
* Asynchronously return the parts of the config that may require dynamically importing other modules.
* @param componentInjector The function is provided a injector that can inject other services/components if needed.
*/
loadComponentConfig?: (componentInjector: Injector) => Promise<WidgetAiChatSectionComponentConfig>;
protected readonly _componentConfig: _angular_core.WritableSignal<WidgetAiChatSectionComponentConfig>;
suggestions: Array<{
label: string;
prompt: string;
}>;
agent: string | ClientAgentDefinition;
chatConfig?: Partial<AgentChatConfig>;
/** Provide the specified `contextVariableName` as a variable that can be used in the prompt. */
useContextAsVariable: boolean;
contextVariableName: string;
private variables$;
/**
* If set, the variables will be loaded async on each round-trip.
* This is useful if the variables depend on some async data source or if they need to be updated on each round-trip.
*
* @example
* ```ts
* variables = combineLatest([
* this.someService.getData(),
* this.anotherService.getOtherData()
* ]).pipe(
* map(([data, otherData]) => ({
* myVarOne: data,
* myVarTwo: otherData
* }))
* );
* ```
*/
set variables(val: Observable<{
[key: string]: any;
}> | {
[key: string]: any;
});
get variables(): Observable<{
[key: string]: any;
}>;
private readonly injector;
private readonly widgetConfigService;
private readonly alertService;
private readonly contextRouteService;
/**
* 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.
*/
onToolResult: (step: ToolCallPart) => undefined | any;
/**
* @ignore
*/
ngOnInit(): Promise<void>;
/**
* Handles the tool result returned from the AI agent.
* @param tool The tool result returned from the AI agent.
*/
toolResultHandler(tool: ToolCallPart): void;
static ɵfac: _angular_core.ɵɵFactoryDeclaration<WidgetAiChatSectionComponent, never>;
static ɵcmp: _angular_core.ɵɵComponentDeclaration<WidgetAiChatSectionComponent, "c8y-widget-ai-chat-section", never, { "loadComponentConfig": { "alias": "loadComponentConfig"; "required": false; }; "suggestions": { "alias": "suggestions"; "required": false; }; "agent": { "alias": "agent"; "required": false; }; "chatConfig": { "alias": "chatConfig"; "required": false; }; "useContextAsVariable": { "alias": "useContextAsVariable"; "required": false; }; "contextVariableName": { "alias": "contextVariableName"; "required": false; }; "variables": { "alias": "variables"; "required": false; }; "onToolResult": { "alias": "onToolResult"; "required": false; }; }, {}, never, never, true, never>;
}
export { AgentChatComponent, WidgetAiChatSectionComponent };
//# sourceMappingURL=index.d.ts.map