Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import { useLicense } from '../hooks/use_license';
import { PromptEditor } from '../prompt_editor/prompt_editor';
import { useKibana } from '../hooks/use_kibana';
import { ChatBanner } from './chat_banner';
import { useConversationContextMenu } from '../hooks';
import { useConversationContextMenu, useScopes } from '../hooks';

const fullHeightClassName = css`
height: 100%;
Expand Down Expand Up @@ -167,6 +167,8 @@ export function ChatBody({
false
);

const scopes = useScopes();

const {
conversation,
conversationId,
Expand Down Expand Up @@ -247,11 +249,15 @@ export function ChatBody({
conversation: { id, last_updated: lastUpdated },
};

const connector = connectors.getConnector(connectors.selectedConnector || '');

chatService.sendAnalyticsEvent({
type: ObservabilityAIAssistantTelemetryEventType.ChatFeedback,
payload: {
feedback,
conversation: conversationWithoutMessagesAndTitle,
connector,
scopes,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useLastUsedPrompts } from '../hooks/use_last_used_prompts';
import { PromptEditorFunction } from './prompt_editor_function';
import { PromptEditorNaturalLanguage } from './prompt_editor_natural_language';
import { useScopes } from '../hooks/use_scopes';
import { useGenAIConnectors } from '../hooks';

export interface PromptEditorProps {
disabled: boolean;
Expand All @@ -42,6 +43,7 @@ export function PromptEditor({
onSubmit,
}: PromptEditorProps) {
const scopes = useScopes();
const connectors = useGenAIConnectors();
const containerRef = useRef<HTMLDivElement>(null);

const [mode, setMode] = useState<'prompt' | 'function'>(
Expand Down Expand Up @@ -102,15 +104,19 @@ export function PromptEditor({

setInnerMessage(undefined);
setMode('prompt');
const connector = connectors.getConnector(connectors.selectedConnector || '');
onSendTelemetry({
type: ObservabilityAIAssistantTelemetryEventType.UserSentPromptInChat,
payload: { scopes },
payload: {
scopes,
connector,
},
});
} catch (_) {
setInnerMessage(oldMessage);
setMode(oldMessage.function_call?.name ? 'function' : 'prompt');
}
}, [addLastUsedPrompt, innerMessage, loading, onSendTelemetry, onSubmit, scopes]);
}, [addLastUsedPrompt, innerMessage, loading, onSendTelemetry, onSubmit, scopes, connectors]);

// Submit on Enter
useEffect(() => {
Expand Down
5 changes: 4 additions & 1 deletion x-pack/platform/plugins/shared/actions/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ export type {
SSLSettings,
} from './types';

export type { ConnectorWithExtraFindData as FindActionResult } from './application/connector/types';
export type {
ConnectorWithExtraFindData as FindActionResult,
Connector,
} from './application/connector/types';

export type { PluginSetupContract, PluginStartContract } from './plugin';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import type { EventTypeOpts } from '@kbn/core/public';
import type { Conversation } from '../../../common';
import type { Feedback } from '../../components/buttons/feedback_buttons';
import { ObservabilityAIAssistantTelemetryEventType } from '../telemetry_event_type';
import { type Connector, connectorSchema } from './connector';
import { type Scope, scopeSchema } from './scope';

export interface ChatFeedback {
export interface ChatFeedback extends Connector, Scope {
feedback: Feedback;
conversation: Omit<Omit<Conversation, 'messages' | 'systemMessage'>, 'conversation'> & {
conversation: Omit<Conversation['conversation'], 'title'>;
Expand Down Expand Up @@ -100,5 +102,9 @@ export const chatFeedbackEventSchema: EventTypeOpts<ChatFeedback> = {
},
},
},
connector: {
properties: connectorSchema,
},
scopes: scopeSchema,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { RootSchema } from '@kbn/core/public';
import type { InferenceConnectorType, ModelFamily, ModelProvider } from '@kbn/inference-common';

export interface Connector {
connector: {
connectorId: string;
name: string;
type: InferenceConnectorType;
family: ModelFamily;
provider: ModelProvider;
modelId: string | undefined;
};
}

export const connectorSchema: RootSchema<Connector['connector']> = {
connectorId: {
type: 'text',
_meta: {
description: 'The id of the connector.',
},
},
name: {
type: 'text',
_meta: {
description: 'The name of the connector.',
},
},
type: {
type: 'text',
_meta: {
description: 'The action type id of the connector.',
},
},
family: {
type: 'text',
_meta: {
description: 'The model family of the connector.',
},
},
provider: {
type: 'text',
_meta: {
description: 'The model provider of the connector.',
},
},
modelId: {
type: 'text',
_meta: {
description: 'The model id of the connector, if applicable.',
optional: true,
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
import type { EventTypeOpts } from '@kbn/core/public';
import type { Feedback } from '../../components/buttons/feedback_buttons';
import { ObservabilityAIAssistantTelemetryEventType } from '../telemetry_event_type';
import { type Connector, connectorSchema } from './connector';
import { type Scope, scopeSchema } from './scope';

export interface InsightFeedback {
export interface InsightFeedback extends Connector, Scope {
feedback: Feedback;
}

Expand All @@ -22,5 +24,9 @@ export const insightFeedbackEventSchema: EventTypeOpts<InsightFeedback> = {
description: 'Whether the user has deemed this response useful or not',
},
},
connector: {
properties: connectorSchema,
},
scopes: scopeSchema,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@

import type { EventTypeOpts } from '@kbn/core/public';
import { ObservabilityAIAssistantTelemetryEventType } from '../telemetry_event_type';
import { type Connector, connectorSchema } from './connector';
import { type Scope, scopeSchema } from './scope';

export interface InsightResponse {
export interface InsightResponse extends Connector, Scope {
'@timestamp': string;
}

Expand All @@ -21,5 +23,9 @@ export const insightResponseEventSchema: EventTypeOpts<InsightResponse> = {
description: 'The timestamp of the last response from the LLM.',
},
},
connector: {
properties: connectorSchema,
},
scopes: scopeSchema,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { SchemaValue } from '@kbn/core/public';
import type { AssistantScope } from '@kbn/ai-assistant-common';

export interface Scope {
scopes: AssistantScope[];
}

export const scopeSchema: SchemaValue<AssistantScope[]> = {
type: 'array',
items: {
type: 'text',
_meta: {
description: 'Scope of the AI Assistant',
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,18 @@
*/

import type { EventTypeOpts } from '@kbn/core/public';
import type { AssistantScope } from '@kbn/ai-assistant-common';
import { ObservabilityAIAssistantTelemetryEventType } from '../telemetry_event_type';
import { type Connector, connectorSchema } from './connector';
import { type Scope, scopeSchema } from './scope';

export interface UserSentPrompt {
scopes: AssistantScope[];
}
export interface UserSentPrompt extends Connector, Scope {}

export const userSentPromptEventSchema: EventTypeOpts<UserSentPrompt> = {
eventType: ObservabilityAIAssistantTelemetryEventType.UserSentPromptInChat,
schema: {
scopes: {
type: 'array',
items: {
type: 'text',
_meta: { description: 'Scope of the AI Assistant' },
},
scopes: scopeSchema,
connector: {
properties: connectorSchema,
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ function ChatContent({
const service = useObservabilityAIAssistant();
const chatService = useObservabilityAIAssistantChatService();
const scopes = chatService.getScopes();
const connectors = useGenAIConnectors();

const initialMessagesRef = useRef(initialMessages);

Expand All @@ -92,14 +93,17 @@ function ChatContent({

useEffect(() => {
if (state !== ChatState.Loading && lastAssistantResponse) {
const connector = connectors.getConnector(connectors.selectedConnector || '');
chatService.sendAnalyticsEvent({
type: ObservabilityAIAssistantTelemetryEventType.InsightResponse,
payload: {
'@timestamp': lastAssistantResponse['@timestamp'],
connector,
scopes,
},
});
}
}, [state, lastAssistantResponse, chatService]);
}, [state, lastAssistantResponse, chatService, connectors, scopes]);

return (
<>
Expand All @@ -124,10 +128,13 @@ function ChatContent({
<FeedbackButtons
onClickFeedback={(feedback) => {
if (lastAssistantResponse) {
const connector = connectors.getConnector(connectors.selectedConnector || '');
chatService.sendAnalyticsEvent({
type: ObservabilityAIAssistantTelemetryEventType.InsightFeedback,
payload: {
feedback,
connector,
scopes,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@

import { useCallback, useEffect, useMemo, useState } from 'react';
import type { FindActionResult } from '@kbn/actions-plugin/server';
import {
getConnectorProvider,
getConnectorFamily,
getConnectorModel,
type InferenceConnector,
type InferenceConnectorType,
type ModelFamily,
type ModelProvider,
} from '@kbn/inference-common';
import useLocalStorage from 'react-use/lib/useLocalStorage';
import type { ObservabilityAIAssistantService } from '../types';
import { useObservabilityAIAssistant } from './use_observability_ai_assistant';
Expand All @@ -21,6 +30,14 @@ export interface UseGenAIConnectorsResult {
error?: Error;
selectConnector: (id: string) => void;
reloadConnectors: () => void;
getConnector: (id: string) => {
connectorId: string;
name: string;
type: InferenceConnectorType;
family: ModelFamily;
provider: ModelProvider;
modelId: string | undefined;
};
}

export function useGenAIConnectors(): UseGenAIConnectorsResult {
Expand Down Expand Up @@ -99,6 +116,30 @@ export function useGenAIConnectorsWithoutContext(
};
}, [assistant, controller, fetchConnectors, setSelectedConnector]);

const getConnector = (id: string) => {
const connector = connectors?.find((_connector) => _connector.id === id);

const inferenceConnector: InferenceConnector = {
connectorId: connector?.id || '',
type: (connector?.actionTypeId || '') as InferenceConnector['type'],
name: connector?.name || '',
config: connector?.config || {},
capabilities: {},
};
const family = getConnectorFamily(inferenceConnector);
const provider = getConnectorProvider(inferenceConnector);
const modelId = getConnectorModel(inferenceConnector);

return {
connectorId: inferenceConnector.connectorId,
name: inferenceConnector.name,
type: inferenceConnector.type,
family,
provider,
modelId,
};
};

return {
connectors,
loading,
Expand All @@ -110,5 +151,6 @@ export function useGenAIConnectorsWithoutContext(
reloadConnectors: () => {
fetchConnectors();
},
getConnector,
};
}