mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Obs AI Assistant] Split up plugin in core/app (#178018)
Splits up the Observability AI Assistant plugin so it can be used outside of the context of the Observability apps. Additionally, the following changes were made: - Add the AI Assistant button to the top nav, instead of the header menu. This prevents unmounts and remounts (and makes it much easier to use everywhere). - Contextual messages now use a function request/response to inject the data of the insight. This allows us to remove `startedFrom`. - ML is now an runtime dependency only (via `core.plugins.onStart`). With a static dependency, we'll run into circular dependency issues. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
d793a7ff8a
commit
74386d037d
324 changed files with 2317 additions and 1532 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -569,6 +569,7 @@ test/common/plugins/newsfeed @elastic/kibana-core
|
|||
src/plugins/no_data_page @elastic/appex-sharedux
|
||||
x-pack/plugins/notifications @elastic/appex-sharedux
|
||||
packages/kbn-object-versioning @elastic/appex-sharedux
|
||||
x-pack/plugins/observability_solution/observability_ai_assistant_app @elastic/obs-knowledge-team
|
||||
x-pack/plugins/observability_solution/observability_ai_assistant @elastic/obs-knowledge-team
|
||||
x-pack/packages/observability/alert_details @elastic/obs-ux-management-team
|
||||
x-pack/packages/observability/alerting_test_data @elastic/obs-ux-management-team
|
||||
|
|
|
@ -692,6 +692,10 @@ Elastic.
|
|||
|This document gives an overview of the features of the Observability AI Assistant at the time of writing, and how to use them. At a high level, the Observability AI Assistant offers contextual insights, and a chat functionality that we enrich with function calling, allowing the LLM to hook into the user's data. We also allow the LLM to store things it considers new information as embeddings into Elasticsearch, and query this knowledge base when it decides it needs more information, using ELSER.
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/x-pack/plugins/observability_solution/observability_ai_assistant_app/README.md[observabilityAIAssistantApp]
|
||||
|This app registers defaults functions. It exists as a separate plugin to avoid cyclical dependencies.
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/x-pack/plugins/observability_solution/observability_logs_explorer/README.md[observabilityLogsExplorer]
|
||||
|This plugin provides an app based on the LogsExplorer component from the logs_explorer plugin, but adds observability-specific affordances.
|
||||
|
||||
|
|
|
@ -588,6 +588,7 @@
|
|||
"@kbn/no-data-page-plugin": "link:src/plugins/no_data_page",
|
||||
"@kbn/notifications-plugin": "link:x-pack/plugins/notifications",
|
||||
"@kbn/object-versioning": "link:packages/kbn-object-versioning",
|
||||
"@kbn/observability-ai-assistant-app-plugin": "link:x-pack/plugins/observability_solution/observability_ai_assistant_app",
|
||||
"@kbn/observability-ai-assistant-plugin": "link:x-pack/plugins/observability_solution/observability_ai_assistant",
|
||||
"@kbn/observability-alert-details": "link:x-pack/packages/observability/alert_details",
|
||||
"@kbn/observability-alerting-test-data": "link:x-pack/packages/observability/alerting_test_data",
|
||||
|
|
|
@ -104,7 +104,8 @@ pageLoadAssetSize:
|
|||
newsfeed: 42228
|
||||
noDataPage: 5000
|
||||
observability: 115443
|
||||
observabilityAIAssistant: 25000
|
||||
observabilityAIAssistant: 58230
|
||||
observabilityAIAssistantApp: 27680
|
||||
observabilityLogsExplorer: 46650
|
||||
observabilityOnboarding: 19573
|
||||
observabilityShared: 72039
|
||||
|
|
|
@ -14,8 +14,8 @@ import { ServerlessPluginStart } from '@kbn/serverless/public';
|
|||
import { EnterpriseSearchPublicStart } from '@kbn/enterprise-search-plugin/public';
|
||||
|
||||
import type {
|
||||
ObservabilityAIAssistantPluginSetup,
|
||||
ObservabilityAIAssistantPluginStart,
|
||||
ObservabilityAIAssistantPublicSetup,
|
||||
ObservabilityAIAssistantPublicStart,
|
||||
} from '@kbn/observability-ai-assistant-plugin/public';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
|
@ -27,11 +27,11 @@ export interface AiAssistantManagementObservabilityPluginStart {}
|
|||
export interface SetupDependencies {
|
||||
management: ManagementSetup;
|
||||
home?: HomePublicPluginSetup;
|
||||
observabilityAIAssistant?: ObservabilityAIAssistantPluginSetup;
|
||||
observabilityAIAssistant?: ObservabilityAIAssistantPublicSetup;
|
||||
}
|
||||
|
||||
export interface StartDependencies {
|
||||
observabilityAIAssistant?: ObservabilityAIAssistantPluginStart;
|
||||
observabilityAIAssistant?: ObservabilityAIAssistantPublicStart;
|
||||
serverless?: ServerlessPluginStart;
|
||||
enterpriseSearch?: EnterpriseSearchPublicStart;
|
||||
}
|
||||
|
|
|
@ -1132,6 +1132,8 @@
|
|||
"@kbn/notifications-plugin/*": ["x-pack/plugins/notifications/*"],
|
||||
"@kbn/object-versioning": ["packages/kbn-object-versioning"],
|
||||
"@kbn/object-versioning/*": ["packages/kbn-object-versioning/*"],
|
||||
"@kbn/observability-ai-assistant-app-plugin": ["x-pack/plugins/observability_solution/observability_ai_assistant_app"],
|
||||
"@kbn/observability-ai-assistant-app-plugin/*": ["x-pack/plugins/observability_solution/observability_ai_assistant_app/*"],
|
||||
"@kbn/observability-ai-assistant-plugin": ["x-pack/plugins/observability_solution/observability_ai_assistant"],
|
||||
"@kbn/observability-ai-assistant-plugin/*": ["x-pack/plugins/observability_solution/observability_ai_assistant/*"],
|
||||
"@kbn/observability-alert-details": ["x-pack/packages/observability/alert_details"],
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
"prefix": "xpack",
|
||||
"paths": {
|
||||
"xpack.actions": "plugins/actions",
|
||||
"xpack.aiops": ["packages/ml/aiops_components", "plugins/aiops"],
|
||||
"xpack.aiops": [
|
||||
"packages/ml/aiops_components",
|
||||
"plugins/aiops"
|
||||
],
|
||||
"xpack.alerting": "plugins/alerting",
|
||||
"xpack.eventLog": "plugins/event_log",
|
||||
"xpack.stackAlerts": "plugins/stack_alerts",
|
||||
|
@ -33,9 +36,15 @@
|
|||
"xpack.dataVisualizer": "plugins/data_visualizer",
|
||||
"xpack.exploratoryView": "plugins/observability_solution/exploratory_view",
|
||||
"xpack.fileUpload": "plugins/file_upload",
|
||||
"xpack.globalSearch": ["plugins/global_search"],
|
||||
"xpack.globalSearchBar": ["plugins/global_search_bar"],
|
||||
"xpack.graph": ["plugins/graph"],
|
||||
"xpack.globalSearch": [
|
||||
"plugins/global_search"
|
||||
],
|
||||
"xpack.globalSearchBar": [
|
||||
"plugins/global_search_bar"
|
||||
],
|
||||
"xpack.graph": [
|
||||
"plugins/graph"
|
||||
],
|
||||
"xpack.grokDebugger": "plugins/grokdebugger",
|
||||
"xpack.idxMgmt": "plugins/index_management",
|
||||
"xpack.indexLifecycleMgmt": "plugins/index_lifecycle_management",
|
||||
|
@ -50,9 +59,13 @@
|
|||
"xpack.licenseMgmt": "plugins/license_management",
|
||||
"xpack.licensing": "plugins/licensing",
|
||||
"xpack.lists": "plugins/lists",
|
||||
"xpack.logstash": ["plugins/logstash"],
|
||||
"xpack.logstash": [
|
||||
"plugins/logstash"
|
||||
],
|
||||
"xpack.main": "legacy/plugins/xpack_main",
|
||||
"xpack.maps": ["plugins/maps"],
|
||||
"xpack.maps": [
|
||||
"plugins/maps"
|
||||
],
|
||||
"xpack.metricsData": "plugins/metrics_data_access",
|
||||
"xpack.ml": [
|
||||
"packages/ml/anomaly_utils",
|
||||
|
@ -65,18 +78,31 @@
|
|||
"packages/ml/ui_actions",
|
||||
"plugins/ml"
|
||||
],
|
||||
"xpack.monitoring": ["plugins/monitoring"],
|
||||
"xpack.monitoring": [
|
||||
"plugins/monitoring"
|
||||
],
|
||||
"xpack.observability": "plugins/observability_solution/observability",
|
||||
"xpack.observabilityAiAssistant": "plugins/observability_solution/observability_ai_assistant",
|
||||
"xpack.observabilityAiAssistant": [
|
||||
"plugins/observability_solution/observability_ai_assistant",
|
||||
"plugins/observability_solution/observability_ai_assistant_app"
|
||||
],
|
||||
"xpack.observabilityLogsExplorer": "plugins/observability_solution/observability_logs_explorer",
|
||||
"xpack.observability_onboarding": "plugins/observability_solution/observability_onboarding",
|
||||
"xpack.observabilityShared": "plugins/observability_solution/observability_shared",
|
||||
"xpack.osquery": ["plugins/osquery"],
|
||||
"xpack.osquery": [
|
||||
"plugins/osquery"
|
||||
],
|
||||
"xpack.painlessLab": "plugins/painless_lab",
|
||||
"xpack.profiling": ["plugins/observability_solution/profiling"],
|
||||
"xpack.profiling": [
|
||||
"plugins/observability_solution/profiling"
|
||||
],
|
||||
"xpack.remoteClusters": "plugins/remote_clusters",
|
||||
"xpack.reporting": ["plugins/reporting"],
|
||||
"xpack.rollupJobs": ["plugins/rollup"],
|
||||
"xpack.reporting": [
|
||||
"plugins/reporting"
|
||||
],
|
||||
"xpack.rollupJobs": [
|
||||
"plugins/rollup"
|
||||
],
|
||||
"xpack.runtimeFields": "plugins/runtime_fields",
|
||||
"xpack.screenshotting": "plugins/screenshotting",
|
||||
"xpack.searchProfiler": "plugins/searchprofiler",
|
||||
|
@ -91,20 +117,30 @@
|
|||
"xpack.sessionView": "plugins/session_view",
|
||||
"xpack.snapshotRestore": "plugins/snapshot_restore",
|
||||
"xpack.spaces": "plugins/spaces",
|
||||
"xpack.savedObjectsTagging": ["plugins/saved_objects_tagging"],
|
||||
"xpack.savedObjectsTagging": [
|
||||
"plugins/saved_objects_tagging"
|
||||
],
|
||||
"xpack.taskManager": "legacy/plugins/task_manager",
|
||||
"xpack.threatIntelligence": "plugins/threat_intelligence",
|
||||
"xpack.timelines": "plugins/timelines",
|
||||
"xpack.transform": "plugins/transform",
|
||||
"xpack.triggersActionsUI": "plugins/triggers_actions_ui",
|
||||
"xpack.upgradeAssistant": "plugins/upgrade_assistant",
|
||||
"xpack.uptime": ["plugins/observability_solution/uptime"],
|
||||
"xpack.synthetics": ["plugins/observability_solution/synthetics"],
|
||||
"xpack.ux": ["plugins/observability_solution/ux"],
|
||||
"xpack.uptime": [
|
||||
"plugins/observability_solution/uptime"
|
||||
],
|
||||
"xpack.synthetics": [
|
||||
"plugins/observability_solution/synthetics"
|
||||
],
|
||||
"xpack.ux": [
|
||||
"plugins/observability_solution/ux"
|
||||
],
|
||||
"xpack.urlDrilldown": "plugins/drilldowns/url_drilldown",
|
||||
"xpack.watcher": "plugins/watcher"
|
||||
},
|
||||
"exclude": ["examples"],
|
||||
"exclude": [
|
||||
"examples"
|
||||
],
|
||||
"translations": [
|
||||
"@kbn/translations-plugin/translations/zh-CN.json",
|
||||
"@kbn/translations-plugin/translations/ja-JP.json",
|
||||
|
|
|
@ -56,8 +56,7 @@
|
|||
"kibanaUtils",
|
||||
"ml",
|
||||
"observability",
|
||||
"maps",
|
||||
"observabilityAIAssistant"
|
||||
"maps"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,7 @@
|
|||
*/
|
||||
import { EuiFlexItem, EuiSpacer } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
type Message,
|
||||
MessageRole,
|
||||
} from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import type { Message } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
|
||||
import { APMError } from '../../../../../typings/es_schemas/ui/apm_error';
|
||||
|
@ -25,53 +22,54 @@ export function ErrorSampleContextualInsight({
|
|||
transaction?: Transaction;
|
||||
}) {
|
||||
const {
|
||||
observabilityAIAssistant: { ObservabilityAIAssistantContextualInsight },
|
||||
observabilityAIAssistant: {
|
||||
ObservabilityAIAssistantContextualInsight,
|
||||
getContextualInsightMessages,
|
||||
},
|
||||
} = useApmPluginContext();
|
||||
|
||||
const [logStacktrace, setLogStacktrace] = useState('');
|
||||
const [exceptionStacktrace, setExceptionStacktrace] = useState('');
|
||||
|
||||
const messages = useMemo<Message[]>(() => {
|
||||
const now = new Date().toISOString();
|
||||
|
||||
const serviceName = error.service.name;
|
||||
const languageName = error.service.language?.name ?? '';
|
||||
const runtimeName = error.service.runtime?.name ?? '';
|
||||
const runtimeVersion = error.service.runtime?.version ?? '';
|
||||
const transactionName = transaction?.transaction.name ?? '';
|
||||
|
||||
return [
|
||||
{
|
||||
'@timestamp': now,
|
||||
message: {
|
||||
role: MessageRole.User,
|
||||
content: `I'm an SRE. I am looking at an exception and trying to understand what it means.
|
||||
return getContextualInsightMessages({
|
||||
message: `I'm looking at an exception and trying to understand what it means`,
|
||||
instructions: `I'm an SRE. I am looking at an exception and trying to understand what it means.
|
||||
|
||||
Your task is to describe what the error means and what it could be caused by.
|
||||
|
||||
The error occurred on a service called ${serviceName}, which is a ${runtimeName} service written in ${languageName}. The
|
||||
runtime version is ${runtimeVersion}.
|
||||
|
||||
The request it occurred for is called ${transactionName}.
|
||||
|
||||
${
|
||||
logStacktrace
|
||||
? `The log stacktrace:
|
||||
${logStacktrace}`
|
||||
: ''
|
||||
}
|
||||
|
||||
${
|
||||
exceptionStacktrace
|
||||
? `The exception stacktrace:
|
||||
${exceptionStacktrace}`
|
||||
: ''
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
];
|
||||
}, [error, transaction, logStacktrace, exceptionStacktrace]);
|
||||
Your task is to describe what the error means and what it could be caused by.
|
||||
|
||||
The error occurred on a service called ${serviceName}, which is a ${runtimeName} service written in ${languageName}. The
|
||||
runtime version is ${runtimeVersion}.
|
||||
|
||||
The request it occurred for is called ${transactionName}.
|
||||
|
||||
${
|
||||
logStacktrace
|
||||
? `The log stacktrace:
|
||||
${logStacktrace}`
|
||||
: ''
|
||||
}
|
||||
|
||||
${
|
||||
exceptionStacktrace
|
||||
? `The exception stacktrace:
|
||||
${exceptionStacktrace}`
|
||||
: ''
|
||||
}`,
|
||||
});
|
||||
}, [
|
||||
error,
|
||||
transaction,
|
||||
logStacktrace,
|
||||
exceptionStacktrace,
|
||||
getContextualInsightMessages,
|
||||
]);
|
||||
|
||||
return ObservabilityAIAssistantContextualInsight && messages ? (
|
||||
<>
|
||||
|
|
|
@ -131,7 +131,6 @@ export function ApmAppRoot({
|
|||
function MountApmHeaderActionMenu() {
|
||||
const {
|
||||
appMountParameters: { setHeaderActionMenu, theme$ },
|
||||
observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem },
|
||||
} = useApmPluginContext();
|
||||
|
||||
return (
|
||||
|
@ -140,11 +139,6 @@ function MountApmHeaderActionMenu() {
|
|||
<EuiFlexItem>
|
||||
<ApmHeaderActionMenu />
|
||||
</EuiFlexItem>
|
||||
{ObservabilityAIAssistantActionMenuItem ? (
|
||||
<EuiFlexItem>
|
||||
<ObservabilityAIAssistantActionMenuItem />
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
</EuiFlexGroup>
|
||||
</HeaderMenuPortal>
|
||||
);
|
||||
|
|
|
@ -66,7 +66,7 @@ export function ApmMainTemplate({
|
|||
const basePath = http?.basePath.get();
|
||||
const { config } = useApmPluginContext();
|
||||
|
||||
const aiAssistant = services.observabilityAIAssistant.service;
|
||||
const aiAssistant = services.observabilityAIAssistant;
|
||||
|
||||
const ObservabilityPageTemplate = observabilityShared.navigation.PageTemplate;
|
||||
|
||||
|
@ -119,7 +119,7 @@ export function ApmMainTemplate({
|
|||
});
|
||||
|
||||
useEffect(() => {
|
||||
return aiAssistant.setScreenContext({
|
||||
return aiAssistant.service.setScreenContext({
|
||||
screenDescription: [
|
||||
hasApmData
|
||||
? 'The user has APM data.'
|
||||
|
|
|
@ -25,9 +25,7 @@ const coreMock = {
|
|||
},
|
||||
},
|
||||
observabilityAIAssistant: {
|
||||
service: {
|
||||
setScreenContext: () => noop,
|
||||
},
|
||||
service: { setScreenContext: () => noop },
|
||||
},
|
||||
} as unknown as Partial<CoreStart>;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
|||
import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
|
||||
import type { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { SharePluginSetup } from '@kbn/share-plugin/public';
|
||||
import type { ApmPluginSetupDeps } from '../../plugin';
|
||||
import type { ConfigSchema } from '../..';
|
||||
|
@ -33,7 +33,7 @@ export interface ApmPluginContextValue {
|
|||
data: DataPublicPluginStart;
|
||||
unifiedSearch: UnifiedSearchPublicPluginStart;
|
||||
uiActions: UiActionsStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPublicStart;
|
||||
share: SharePluginSetup;
|
||||
kibanaEnvironment: KibanaEnvContext;
|
||||
}
|
||||
|
|
|
@ -172,9 +172,7 @@ export const mockApmPluginContextValue = {
|
|||
getTriggerCompatibleActions: () => Promise.resolve([]),
|
||||
},
|
||||
observabilityAIAssistant: {
|
||||
service: {
|
||||
setScreenContext: jest.fn().mockImplementation(() => noop),
|
||||
},
|
||||
service: { setScreenContext: jest.fn().mockImplementation(() => noop) },
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -129,9 +129,7 @@ const mockApmPluginContext = {
|
|||
core: mockCore,
|
||||
plugins: mockPlugin,
|
||||
observabilityAIAssistant: {
|
||||
service: {
|
||||
setScreenContext: () => noop,
|
||||
},
|
||||
service: { setScreenContext: () => noop },
|
||||
},
|
||||
} as unknown as ApmPluginContextValue;
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ import { LicenseManagementUIPluginSetup } from '@kbn/license-management-plugin/p
|
|||
import type { LicensingPluginSetup } from '@kbn/licensing-plugin/public';
|
||||
import type { MapsStartApi } from '@kbn/maps-plugin/public';
|
||||
import type { MlPluginSetup, MlPluginStart } from '@kbn/ml-plugin/public';
|
||||
import type { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import {
|
||||
FetchDataParams,
|
||||
ObservabilityPublicSetup,
|
||||
|
@ -137,7 +137,7 @@ export interface ApmPluginStartDeps {
|
|||
lens: LensPublicStart;
|
||||
uiActions: UiActionsStart;
|
||||
profiling?: ProfilingPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPublicStart;
|
||||
dashboard: DashboardStart;
|
||||
metricsDataAccess: MetricsDataPluginStart;
|
||||
uiSettings: IUiSettingsClient;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import type { CoreSetup } from '@kbn/core-lifecycle-server';
|
||||
import type { Logger } from '@kbn/logging';
|
||||
import type {
|
||||
ChatRegistrationFunction,
|
||||
RegistrationCallback,
|
||||
RegisterFunction,
|
||||
} from '@kbn/observability-ai-assistant-plugin/server/service/types';
|
||||
import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server';
|
||||
|
@ -47,8 +47,11 @@ export function registerAssistantFunctions({
|
|||
kibanaVersion: string;
|
||||
ruleDataClient: IRuleDataClient;
|
||||
plugins: APMRouteHandlerResources['plugins'];
|
||||
}): ChatRegistrationFunction {
|
||||
return async ({ resources, registerContext, registerFunction }) => {
|
||||
}): RegistrationCallback {
|
||||
return async ({
|
||||
resources,
|
||||
functions: { registerContext, registerFunction },
|
||||
}) => {
|
||||
const apmRouteHandlerResources: APMRouteHandlerResources = {
|
||||
context: resources.context,
|
||||
request: resources.request,
|
||||
|
|
|
@ -66,8 +66,8 @@ import {
|
|||
ProfilingDataAccessPluginStart,
|
||||
} from '@kbn/profiling-data-access-plugin/server';
|
||||
import type {
|
||||
ObservabilityAIAssistantPluginSetup,
|
||||
ObservabilityAIAssistantPluginStart,
|
||||
ObservabilityAIAssistantServerSetup,
|
||||
ObservabilityAIAssistantServerStart,
|
||||
} from '@kbn/observability-ai-assistant-plugin/server';
|
||||
import { APMConfig } from '.';
|
||||
|
||||
|
@ -86,7 +86,7 @@ export interface APMPluginSetupDependencies {
|
|||
metricsDataAccess: MetricsDataPluginSetup;
|
||||
dataViews: {};
|
||||
share: SharePluginSetup;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPluginSetup;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantServerSetup;
|
||||
// optional dependencies
|
||||
actions?: ActionsPlugin['setup'];
|
||||
alerting?: AlertingPlugin['setup'];
|
||||
|
@ -112,7 +112,7 @@ export interface APMPluginStartDependencies {
|
|||
metricsDataAccess: MetricsDataPluginSetup;
|
||||
dataViews: DataViewsServerPluginStart;
|
||||
share: undefined;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantServerStart;
|
||||
// optional dependencies
|
||||
actions?: ActionsPlugin['start'];
|
||||
alerting?: AlertingPlugin['start'];
|
||||
|
|
|
@ -20,7 +20,7 @@ import { EmbeddableStateTransfer } from '@kbn/embeddable-plugin/public';
|
|||
import { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
|
||||
import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public';
|
||||
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { LensPublicStart } from '@kbn/lens-plugin/public';
|
||||
import { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
|
@ -42,7 +42,7 @@ export interface ObservabilityAppServices {
|
|||
lens: LensPublicStart;
|
||||
navigation: NavigationPublicPluginStart;
|
||||
notifications: NotificationsStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPublicStart;
|
||||
overlays: OverlayStart;
|
||||
savedObjectsClient: SavedObjectsStart['client'];
|
||||
share: SharePluginStart;
|
||||
|
|
|
@ -20,11 +20,7 @@ export function ExpViewActionMenuContent({
|
|||
timeRange?: { from: string; to: string };
|
||||
lensAttributes: TypedLensByValueInput['attributes'] | null;
|
||||
}) {
|
||||
const {
|
||||
lens,
|
||||
isDev,
|
||||
observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem },
|
||||
} = useKibana().services;
|
||||
const { lens, isDev } = useKibana().services;
|
||||
|
||||
const [isSaveOpen, setIsSaveOpen] = useState(false);
|
||||
|
||||
|
@ -94,11 +90,6 @@ export function ExpViewActionMenuContent({
|
|||
})}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
{ObservabilityAIAssistantActionMenuItem ? (
|
||||
<EuiFlexItem>
|
||||
<ObservabilityAIAssistantActionMenuItem />
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
</EuiFlexGroup>
|
||||
|
||||
{isSaveOpen && lensAttributes && (
|
||||
|
|
|
@ -11,7 +11,6 @@ import { HeaderMenuPortal } from '@kbn/observability-shared-plugin/public';
|
|||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { ExpViewActionMenuContent } from './action_menu';
|
||||
import { useExploratoryView } from '../../contexts/exploratory_view_config';
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
|
||||
interface Props {
|
||||
timeRange?: { from: string; to: string };
|
||||
|
@ -20,21 +19,12 @@ interface Props {
|
|||
export function ExpViewActionMenu(props: Props) {
|
||||
const { setHeaderActionMenu, theme$ } = useExploratoryView();
|
||||
|
||||
const {
|
||||
observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem },
|
||||
} = useKibana().services;
|
||||
|
||||
return (
|
||||
<HeaderMenuPortal setHeaderActionMenu={setHeaderActionMenu} theme$={theme$}>
|
||||
<EuiFlexGroup responsive={false} gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
<ExpViewActionMenuContent {...props} />
|
||||
</EuiFlexItem>
|
||||
{ObservabilityAIAssistantActionMenuItem ? (
|
||||
<EuiFlexItem>
|
||||
<ObservabilityAIAssistantActionMenuItem />
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
</EuiFlexGroup>
|
||||
</HeaderMenuPortal>
|
||||
);
|
||||
|
|
|
@ -35,7 +35,7 @@ import { SecurityPluginStart } from '@kbn/security-plugin/public';
|
|||
import { SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
import { LicensingPluginStart } from '@kbn/licensing-plugin/public';
|
||||
import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
|
||||
import { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { getExploratoryViewEmbeddable } from './components/shared/exploratory_view/embeddable';
|
||||
import { createExploratoryViewUrl } from './components/shared/exploratory_view/configurations/exploratory_view_url';
|
||||
import getAppDataView from './utils/observability_data_views/get_app_data_view';
|
||||
|
@ -68,7 +68,7 @@ export interface ExploratoryViewPublicPluginsStart {
|
|||
usageCollection: UsageCollectionSetup;
|
||||
unifiedSearch: UnifiedSearchPublicPluginStart;
|
||||
home?: HomePublicPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPublicStart;
|
||||
}
|
||||
|
||||
export type ExploratoryViewPublicSetup = ReturnType<Plugin['setup']>;
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
"requiredBundles": [
|
||||
"unifiedSearch",
|
||||
"observability",
|
||||
"observabilityAIAssistant",
|
||||
"licenseManagement",
|
||||
"kibanaUtils",
|
||||
"kibanaReact",
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
import { LogRateAnalysisContent, type LogRateAnalysisResultsData } from '@kbn/aiops-plugin/public';
|
||||
import { Rule } from '@kbn/alerting-plugin/common';
|
||||
import { TopAlert } from '@kbn/observability-plugin/public';
|
||||
import { type Message, MessageRole } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import type { Message } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ALERT_END } from '@kbn/rule-data-utils';
|
||||
|
@ -52,7 +52,10 @@ export const LogRateAnalysis: FC<AlertDetailsLogRateAnalysisSectionProps> = ({ r
|
|||
const {
|
||||
dataViews,
|
||||
logsShared,
|
||||
observabilityAIAssistant: { ObservabilityAIAssistantContextualInsight },
|
||||
observabilityAIAssistant: {
|
||||
ObservabilityAIAssistantContextualInsight,
|
||||
getContextualInsightMessages,
|
||||
},
|
||||
} = services;
|
||||
const [dataView, setDataView] = useState<DataView | undefined>();
|
||||
const [esSearchQuery, setEsSearchQuery] = useState<QueryDslQueryContainer | undefined>();
|
||||
|
@ -194,7 +197,10 @@ export const LogRateAnalysis: FC<AlertDetailsLogRateAnalysisSectionProps> = ({ r
|
|||
.map((item) => Object.values(item).join(','))
|
||||
.join('\n');
|
||||
|
||||
const content = `You are an observability expert using Elastic Observability Suite on call being consulted about a log threshold alert that got triggered by a ${logRateAnalysisType} in log messages. Your job is to take immediate action and proceed with both urgency and precision.
|
||||
return getContextualInsightMessages({
|
||||
message:
|
||||
'Can you identify possible causes and remediations for these log rate analysis results',
|
||||
instructions: `You are an observability expert using Elastic Observability Suite on call being consulted about a log threshold alert that got triggered by a ${logRateAnalysisType} in log messages. Your job is to take immediate action and proceed with both urgency and precision.
|
||||
"Log Rate Analysis" is an AIOps feature that uses advanced statistical methods to identify reasons for increases and decreases in log rates. It makes it easy to find and investigate causes of unusual spikes or dips by using the analysis workflow view.
|
||||
You are using "Log Rate Analysis" and ran the statistical analysis on the log messages which occured during the alert.
|
||||
You received the following analysis results from "Log Rate Analysis" which list statistically significant co-occuring field/value combinations sorted from most significant (lower p-values) to least significant (higher p-values) that ${
|
||||
|
@ -227,20 +233,9 @@ export const LogRateAnalysis: FC<AlertDetailsLogRateAnalysisSectionProps> = ({ r
|
|||
|
||||
Do not mention individual p-values from the analysis results.
|
||||
Do not repeat the full list of field names and field values back to the user.
|
||||
Do not guess, just say what you are sure of. Do not repeat the given instructions in your output.`;
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
return [
|
||||
{
|
||||
'@timestamp': now,
|
||||
message: {
|
||||
content,
|
||||
role: MessageRole.User,
|
||||
},
|
||||
},
|
||||
];
|
||||
}, [logRateAnalysisParams]);
|
||||
Do not guess, just say what you are sure of. Do not repeat the given instructions in your output.`,
|
||||
});
|
||||
}, [logRateAnalysisParams, getContextualInsightMessages]);
|
||||
|
||||
if (!dataView || !esSearchQuery) return null;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import { AppMountParameters, CoreStart } from '@kbn/core/public';
|
|||
import React from 'react';
|
||||
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
|
||||
import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import type { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { Storage } from '@kbn/kibana-utils-plugin/public';
|
||||
import { NavigationWarningPromptProvider } from '@kbn/observability-shared-plugin/public';
|
||||
import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public';
|
||||
|
@ -28,7 +28,7 @@ export const CommonInfraProviders: React.FC<{
|
|||
appName: string;
|
||||
storage: Storage;
|
||||
triggersActionsUI: TriggersAndActionsUIPublicPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPublicStart;
|
||||
setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
|
||||
theme$: AppMountParameters['theme$'];
|
||||
}> = ({
|
||||
|
|
|
@ -23,7 +23,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
||||
import useToggle from 'react-use/lib/useToggle';
|
||||
import { type Message, MessageRole } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { type Message } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana';
|
||||
import { Process } from './types';
|
||||
import { ProcessRowCharts } from './process_row_charts';
|
||||
|
@ -35,66 +35,62 @@ interface Props {
|
|||
}
|
||||
export const ContextualInsightProcessRow = ({ command }: { command: string }) => {
|
||||
const {
|
||||
observabilityAIAssistant: { ObservabilityAIAssistantContextualInsight },
|
||||
observabilityAIAssistant: {
|
||||
ObservabilityAIAssistantContextualInsight,
|
||||
getContextualInsightMessages,
|
||||
},
|
||||
} = useKibanaContextForPlugin().services;
|
||||
|
||||
const explainProcessMessages = useMemo<Message[] | undefined>(() => {
|
||||
if (!command) {
|
||||
return undefined;
|
||||
}
|
||||
const now = new Date().toISOString();
|
||||
return [
|
||||
{
|
||||
'@timestamp': now,
|
||||
message: {
|
||||
role: MessageRole.User,
|
||||
content: `I am a software engineer. I am trying to understand what a process running on my
|
||||
machine does.
|
||||
Your task is to first describe what the process is and what its general use cases are. If I also provide you
|
||||
with the arguments to the process you should then explain its arguments and how they influence the behaviour
|
||||
of the process. If I do not provide any arguments then explain the behaviour of the process when no arguments are
|
||||
provided.
|
||||
If you do not recognise the process say "No information available for this process". If I provide an argument
|
||||
to the process that you do not recognise then say "No information available for this argument" when explaining
|
||||
that argument.
|
||||
Here is an example with arguments.
|
||||
Process: metricbeat -c /etc/metricbeat.yml -d autodiscover,kafka -e -system.hostfs=/hostfs
|
||||
Explanation: Metricbeat is part of the Elastic Stack. It is a lightweight shipper that you can install on your
|
||||
servers to periodically collect metrics from the operating system and from services running on the server.
|
||||
Use cases for Metricbeat generally revolve around infrastructure monitoring. You would typically install
|
||||
Metricbeat on your servers to collect metrics from your systems and services. These metrics are then
|
||||
used for performance monitoring, anomaly detection, system status checks, etc.
|
||||
Here is a breakdown of the arguments used:
|
||||
* -c /etc/metricbeat.yml: The -c option is used to specify the configuration file for Metricbeat. In
|
||||
this case, /etc/metricbeat.yml is the configuration file. This file contains configurations for what
|
||||
metrics to collect and where to send them (e.g., to Elasticsearch or Logstash).
|
||||
* -d autodiscover,kafka: The -d option is used to enable debug output for selected components. In
|
||||
this case, debug output is enabled for autodiscover and kafka components. The autodiscover feature
|
||||
allows Metricbeat to automatically discover services as they get started and stopped in your environment,
|
||||
and kafka is presumably a monitored service from which Metricbeat collects metrics.
|
||||
* -e: The -e option is used to log to stderr and disable syslog/file output. This is useful for debugging.
|
||||
* -system.hostfs=/hostfs: The -system.hostfs option is used to set the mount point of the host’s
|
||||
filesystem for use in monitoring a host from within a container. In this case, /hostfs is the mount
|
||||
point. When running Metricbeat inside a container, filesystem metrics would be for the container by
|
||||
default, but with this option, Metricbeat can get metrics for the host system.
|
||||
Here is an example without arguments.
|
||||
Process: metricbeat
|
||||
Explanation: Metricbeat is part of the Elastic Stack. It is a lightweight shipper that you can install on your
|
||||
servers to periodically collect metrics from the operating system and from services running on the server.
|
||||
Use cases for Metricbeat generally revolve around infrastructure monitoring. You would typically install
|
||||
Metricbeat on your servers to collect metrics from your systems and services. These metrics are then
|
||||
used for performance monitoring, anomaly detection, system status checks, etc.
|
||||
Running it without any arguments will start the process with the default configuration file, typically
|
||||
located at /etc/metricbeat/metricbeat.yml. This file specifies the metrics to be collected and where
|
||||
to ship them to.
|
||||
Now explain this process to me.
|
||||
Process: ${command}
|
||||
Explanation:
|
||||
`,
|
||||
},
|
||||
},
|
||||
];
|
||||
}, [command]);
|
||||
|
||||
return getContextualInsightMessages({
|
||||
message: `I am a software engineer. I am trying to understand what this process running on my
|
||||
machine does.`,
|
||||
instructions: `Your task is to first describe what the process is and what its general use cases are. If I also provide you
|
||||
with the arguments to the process you should then explain its arguments and how they influence the behaviour
|
||||
of the process. If I do not provide any arguments then explain the behaviour of the process when no arguments are
|
||||
provided.
|
||||
If you do not recognise the process say "No information available for this process". If I provide an argument
|
||||
to the process that you do not recognise then say "No information available for this argument" when explaining
|
||||
that argument.
|
||||
Here is an example with arguments.
|
||||
Process: metricbeat -c /etc/metricbeat.yml -d autodiscover,kafka -e -system.hostfs=/hostfs
|
||||
Explanation: Metricbeat is part of the Elastic Stack. It is a lightweight shipper that you can install on your
|
||||
servers to periodically collect metrics from the operating system and from services running on the server.
|
||||
Use cases for Metricbeat generally revolve around infrastructure monitoring. You would typically install
|
||||
Metricbeat on your servers to collect metrics from your systems and services. These metrics are then
|
||||
used for performance monitoring, anomaly detection, system status checks, etc.
|
||||
Here is a breakdown of the arguments used:
|
||||
* -c /etc/metricbeat.yml: The -c option is used to specify the configuration file for Metricbeat. In
|
||||
this case, /etc/metricbeat.yml is the configuration file. This file contains configurations for what
|
||||
metrics to collect and where to send them (e.g., to Elasticsearch or Logstash).
|
||||
* -d autodiscover,kafka: The -d option is used to enable debug output for selected components. In
|
||||
this case, debug output is enabled for autodiscover and kafka components. The autodiscover feature
|
||||
allows Metricbeat to automatically discover services as they get started and stopped in your environment,
|
||||
and kafka is presumably a monitored service from which Metricbeat collects metrics.
|
||||
* -e: The -e option is used to log to stderr and disable syslog/file output. This is useful for debugging.
|
||||
* -system.hostfs=/hostfs: The -system.hostfs option is used to set the mount point of the host’s
|
||||
filesystem for use in monitoring a host from within a container. In this case, /hostfs is the mount
|
||||
point. When running Metricbeat inside a container, filesystem metrics would be for the container by
|
||||
default, but with this option, Metricbeat can get metrics for the host system.
|
||||
Here is an example without arguments.
|
||||
Process: metricbeat
|
||||
Explanation: Metricbeat is part of the Elastic Stack. It is a lightweight shipper that you can install on your
|
||||
servers to periodically collect metrics from the operating system and from services running on the server.
|
||||
Use cases for Metricbeat generally revolve around infrastructure monitoring. You would typically install
|
||||
Metricbeat on your servers to collect metrics from your systems and services. These metrics are then
|
||||
used for performance monitoring, anomaly detection, system status checks, etc.
|
||||
Running it without any arguments will start the process with the default configuration file, typically
|
||||
located at /etc/metricbeat/metricbeat.yml. This file specifies the metrics to be collected and where
|
||||
to ship them to.
|
||||
Now explain this process to me.
|
||||
Process: ${command}
|
||||
Explanation:`,
|
||||
});
|
||||
}, [command, getContextualInsightMessages]);
|
||||
return (
|
||||
<>
|
||||
{ObservabilityAIAssistantContextualInsight && explainProcessMessages ? (
|
||||
|
|
|
@ -31,7 +31,6 @@ export const LogsPageContent: React.FunctionComponent = () => {
|
|||
|
||||
const {
|
||||
application: { getUrlForApp },
|
||||
observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem },
|
||||
} = useKibanaContextForPlugin().services;
|
||||
|
||||
const enableDeveloperRoutes = isDevMode();
|
||||
|
@ -90,11 +89,6 @@ export const LogsPageContent: React.FunctionComponent = () => {
|
|||
</EuiHeaderLink>
|
||||
</EuiHeaderLinks>
|
||||
</EuiFlexItem>
|
||||
{ObservabilityAIAssistantActionMenuItem ? (
|
||||
<EuiFlexItem>
|
||||
<ObservabilityAIAssistantActionMenuItem />
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
</EuiFlexGroup>
|
||||
</HeaderMenuPortal>
|
||||
)}
|
||||
|
|
|
@ -20,7 +20,6 @@ import {
|
|||
import { useKibana, useUiSetting } from '@kbn/kibana-react-plugin/public';
|
||||
import { HeaderMenuPortal, useLinkProps } from '@kbn/observability-shared-plugin/public';
|
||||
import { enableInfrastructureHostsView } from '@kbn/observability-plugin/common';
|
||||
import { useKibanaContextForPlugin } from '../../hooks/use_kibana';
|
||||
import { MetricsSourceConfigurationProperties } from '../../../common/metrics_sources';
|
||||
import { HelpCenterContent } from '../../components/help_center_content';
|
||||
import { useReadOnlyBadge } from '../../hooks/use_readonly_badge';
|
||||
|
@ -48,9 +47,6 @@ const ADD_DATA_LABEL = i18n.translate('xpack.infra.metricsHeaderAddDataButtonLab
|
|||
});
|
||||
|
||||
export const InfrastructurePage = () => {
|
||||
const {
|
||||
observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem },
|
||||
} = useKibanaContextForPlugin().services;
|
||||
const config = usePluginConfig();
|
||||
const uiCapabilities = useKibana().services.application?.capabilities;
|
||||
const { setHeaderActionMenu, theme$ } = useContext(HeaderActionMenuContext);
|
||||
|
@ -115,11 +111,6 @@ export const InfrastructurePage = () => {
|
|||
</EuiHeaderLink>
|
||||
</EuiHeaderLinks>
|
||||
</EuiFlexItem>
|
||||
{ObservabilityAIAssistantActionMenuItem ? (
|
||||
<EuiFlexItem>
|
||||
<ObservabilityAIAssistantActionMenuItem />
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
</EuiFlexGroup>
|
||||
</HeaderMenuPortal>
|
||||
)}
|
||||
|
|
|
@ -44,7 +44,7 @@ import {
|
|||
} from '@kbn/logs-shared-plugin/public';
|
||||
import { FieldFormatsSetup, FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
||||
import { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/public';
|
||||
import { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import type { CloudSetup } from '@kbn/cloud-plugin/public';
|
||||
import type { LicenseManagementUIPluginSetup } from '@kbn/license-management-plugin/public';
|
||||
import type { ServerlessPluginStart } from '@kbn/serverless/public';
|
||||
|
@ -96,7 +96,7 @@ export interface InfraClientStartDeps {
|
|||
ml: MlPluginStart;
|
||||
observability: ObservabilityPublicStart;
|
||||
observabilityShared: ObservabilitySharedPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPublicStart;
|
||||
osquery?: unknown; // OsqueryPluginStart - can't be imported due to cyclic dependency;
|
||||
share: SharePluginStart;
|
||||
spaces: SpacesPluginStart;
|
||||
|
|
|
@ -7,10 +7,9 @@
|
|||
|
||||
import React, { useMemo } from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import {
|
||||
type Message,
|
||||
MessageRole,
|
||||
type ObservabilityAIAssistantPluginStart,
|
||||
import type {
|
||||
Message,
|
||||
ObservabilityAIAssistantPublicStart,
|
||||
} from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { LogEntryField } from '../../../common';
|
||||
import { explainLogMessageTitle, similarLogMessagesTitle } from './translations';
|
||||
|
@ -20,53 +19,47 @@ export interface LogAIAssistantDocument {
|
|||
}
|
||||
|
||||
export interface LogAIAssistantProps {
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPublicStart;
|
||||
doc: LogAIAssistantDocument | undefined;
|
||||
}
|
||||
|
||||
export const LogAIAssistant = ({
|
||||
doc,
|
||||
observabilityAIAssistant: { ObservabilityAIAssistantContextualInsight },
|
||||
observabilityAIAssistant: {
|
||||
ObservabilityAIAssistantContextualInsight,
|
||||
getContextualInsightMessages,
|
||||
},
|
||||
}: LogAIAssistantProps) => {
|
||||
const explainLogMessageMessages = useMemo<Message[] | undefined>(() => {
|
||||
if (!doc) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
return [
|
||||
{
|
||||
'@timestamp': now,
|
||||
message: {
|
||||
role: MessageRole.User,
|
||||
content: `I'm looking at a log entry. Can you explain me what the log message means? Where it could be coming from, whether it is expected and whether it is an issue. Here's the context, serialized: ${JSON.stringify(
|
||||
{ logEntry: { fields: doc.fields } }
|
||||
)} `,
|
||||
return getContextualInsightMessages({
|
||||
message:
|
||||
'Can you explain what this log message means? Where it could be coming from, whether it is expected and whether it is an issue.',
|
||||
instructions: JSON.stringify({
|
||||
logEntry: {
|
||||
fields: doc.fields,
|
||||
},
|
||||
},
|
||||
];
|
||||
}, [doc]);
|
||||
}),
|
||||
});
|
||||
}, [doc, getContextualInsightMessages]);
|
||||
|
||||
const similarLogMessageMessages = useMemo<Message[] | undefined>(() => {
|
||||
if (!doc) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
const message = doc.fields.find((field) => field.field === 'message')?.value[0];
|
||||
|
||||
return [
|
||||
{
|
||||
'@timestamp': now,
|
||||
message: {
|
||||
role: MessageRole.User,
|
||||
content: `I'm looking at a log entry. Can you construct a Kibana KQL query that I can enter in the search bar that gives me similar log entries, based on the \`message\` field: ${message}`,
|
||||
},
|
||||
},
|
||||
];
|
||||
}, [doc]);
|
||||
return getContextualInsightMessages({
|
||||
message: `I'm looking at a log entry. Can you construct a Kibana KQL query that I can enter in the search bar that gives me similar log entries, based on the message field?`,
|
||||
instructions: JSON.stringify({
|
||||
message,
|
||||
}),
|
||||
});
|
||||
}, [getContextualInsightMessages, doc]);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup direction="column" gutterSize="m">
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import type { CoreSetup, CoreStart, Plugin as PluginClass } from '@kbn/core/public';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { SharePluginSetup } from '@kbn/share-plugin/public';
|
||||
import { UiActionsStart } from '@kbn/ui-actions-plugin/public';
|
||||
|
||||
|
@ -35,7 +35,7 @@ export interface LogsSharedClientSetupDeps {
|
|||
export interface LogsSharedClientStartDeps {
|
||||
data: DataPublicPluginStart;
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPublicStart;
|
||||
uiActions: UiActionsStart;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import { Rule } from '@kbn/alerting-plugin/common';
|
|||
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { type Message, MessageRole } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import type { Message } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { ALERT_END } from '@kbn/rule-data-utils';
|
||||
import { CustomThresholdRuleTypeParams } from '../../types';
|
||||
import { TopAlert } from '../../../..';
|
||||
|
@ -47,7 +47,10 @@ export function LogRateAnalysis({
|
|||
services,
|
||||
}: AlertDetailsLogRateAnalysisProps) {
|
||||
const {
|
||||
observabilityAIAssistant: { ObservabilityAIAssistantContextualInsight },
|
||||
observabilityAIAssistant: {
|
||||
ObservabilityAIAssistantContextualInsight,
|
||||
getContextualInsightMessages,
|
||||
},
|
||||
} = services;
|
||||
const [esSearchQuery, setEsSearchQuery] = useState<QueryDslQueryContainer | undefined>();
|
||||
const [logRateAnalysisParams, setLogRateAnalysisParams] = useState<
|
||||
|
@ -162,18 +165,12 @@ export function LogRateAnalysis({
|
|||
Do not repeat the full list of field names and field values back to the user.
|
||||
Do not guess, just say what you are sure of. Do not repeat the given instructions in your output.`;
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
return [
|
||||
{
|
||||
'@timestamp': now,
|
||||
message: {
|
||||
content,
|
||||
role: MessageRole.User,
|
||||
},
|
||||
},
|
||||
];
|
||||
}, [logRateAnalysisParams]);
|
||||
return getContextualInsightMessages({
|
||||
message:
|
||||
'Can you identify possible causes and remediations for these log rate analysis results',
|
||||
instructions: content,
|
||||
});
|
||||
}, [logRateAnalysisParams, getContextualInsightMessages]);
|
||||
|
||||
if (!dataView || !esSearchQuery) return null;
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ mockUseKibanaReturnValue.services.cases.hooks.useCasesAddToExistingCaseModal.moc
|
|||
|
||||
mockUseKibanaReturnValue.services.cases.helpers.canUseCases.mockReturnValue(allCasesPermissions());
|
||||
|
||||
const { ObservabilityAIAssistantActionMenuItem, ObservabilityAIAssistantContextualInsight } =
|
||||
const { ObservabilityAIAssistantContextualInsight } =
|
||||
observabilityAIAssistantPluginMock.createStartContract();
|
||||
|
||||
jest.mock('../../../utils/kibana_react', () => ({
|
||||
|
@ -78,7 +78,6 @@ jest.spyOn(pluginContext, 'usePluginContext').mockImplementation(() => ({
|
|||
plugins: {} as ObservabilityPublicPluginsStart,
|
||||
observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(),
|
||||
ObservabilityPageTemplate: KibanaPageTemplate,
|
||||
ObservabilityAIAssistantActionMenuItem,
|
||||
ObservabilityAIAssistantContextualInsight,
|
||||
}));
|
||||
|
||||
|
|
|
@ -13,11 +13,7 @@ import { useKibana } from '../../../../utils/kibana_react';
|
|||
import HeaderMenuPortal from './header_menu_portal';
|
||||
|
||||
export function HeaderMenu(): React.ReactElement | null {
|
||||
const {
|
||||
http,
|
||||
theme,
|
||||
observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem },
|
||||
} = useKibana().services;
|
||||
const { http, theme } = useKibana().services;
|
||||
|
||||
const { appMountParameters } = usePluginContext();
|
||||
|
||||
|
@ -27,11 +23,6 @@ export function HeaderMenu(): React.ReactElement | null {
|
|||
theme$={theme.theme$}
|
||||
>
|
||||
<EuiFlexGroup responsive={false} gutterSize="s">
|
||||
{ObservabilityAIAssistantActionMenuItem && (
|
||||
<EuiFlexItem>
|
||||
<ObservabilityAIAssistantActionMenuItem />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
<EuiFlexItem>
|
||||
<EuiHeaderLinks>
|
||||
<EuiHeaderLink
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
import React from 'react';
|
||||
import * as fetcherHook from '@kbn/observability-shared-plugin/public/hooks/use_fetcher';
|
||||
import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock';
|
||||
import { render, data as dataMock } from '../../../../../utils/test_helper';
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
import { ConfigSchema, ObservabilityPublicPluginsStart } from '../../../../../plugin';
|
||||
|
@ -19,6 +18,7 @@ import { HasDataContextValue } from '../../../../../context/has_data_context/has
|
|||
import { AppMountParameters } from '@kbn/core/public';
|
||||
import { createObservabilityRuleTypeRegistryMock } from '../../../../../rules/observability_rule_type_registry_mock';
|
||||
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
|
||||
import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock';
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
useLocation: () => ({
|
||||
|
@ -28,7 +28,7 @@ jest.mock('react-router-dom', () => ({
|
|||
useHistory: jest.fn(),
|
||||
}));
|
||||
|
||||
const { ObservabilityAIAssistantActionMenuItem, ObservabilityAIAssistantContextualInsight } =
|
||||
const { ObservabilityAIAssistantContextualInsight } =
|
||||
observabilityAIAssistantPluginMock.createStartContract();
|
||||
|
||||
describe('APMSection', () => {
|
||||
|
@ -65,7 +65,6 @@ describe('APMSection', () => {
|
|||
plugins: {} as ObservabilityPublicPluginsStart,
|
||||
observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(),
|
||||
ObservabilityPageTemplate: KibanaPageTemplate,
|
||||
ObservabilityAIAssistantActionMenuItem,
|
||||
ObservabilityAIAssistantContextualInsight,
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -53,8 +53,8 @@ import { ExploratoryViewPublicStart } from '@kbn/exploratory-view-plugin/public'
|
|||
import { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public';
|
||||
import { LicensingPluginStart } from '@kbn/licensing-plugin/public';
|
||||
import {
|
||||
ObservabilityAIAssistantPluginSetup,
|
||||
ObservabilityAIAssistantPluginStart,
|
||||
ObservabilityAIAssistantPublicSetup,
|
||||
ObservabilityAIAssistantPublicStart,
|
||||
} from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { SecurityPluginStart } from '@kbn/security-plugin/public';
|
||||
import { SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
|
@ -119,7 +119,7 @@ export interface ObservabilityPublicPluginsSetup {
|
|||
data: DataPublicPluginSetup;
|
||||
fieldFormats: FieldFormatsSetup;
|
||||
observabilityShared: ObservabilitySharedPluginSetup;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPluginSetup;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPublicSetup;
|
||||
share: SharePluginSetup;
|
||||
triggersActionsUi: TriggersAndActionsUIPublicPluginSetup;
|
||||
home?: HomePublicPluginSetup;
|
||||
|
@ -146,7 +146,7 @@ export interface ObservabilityPublicPluginsStart {
|
|||
lens: LensPublicStart;
|
||||
licensing: LicensingPluginStart;
|
||||
observabilityShared: ObservabilitySharedPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPluginStart;
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPublicStart;
|
||||
ruleTypeRegistry: RuleTypeRegistryContract;
|
||||
security: SecurityPluginStart;
|
||||
share: SharePluginStart;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Message } from './types';
|
||||
import type { Message } from './types';
|
||||
|
||||
export enum StreamingChatResponseEventType {
|
||||
ChatCompletionChunk = 'chatCompletionChunk',
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export enum FunctionVisibility {
|
||||
AssistantOnly = 'assistantOnly',
|
||||
UserOnly = 'userOnly',
|
||||
Internal = 'internal',
|
||||
All = 'all',
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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 { JSONSchema } from 'json-schema-to-ts';
|
||||
import type { Observable } from 'rxjs';
|
||||
import { ChatCompletionChunkEvent, MessageAddEvent } from '../conversation_complete';
|
||||
import { FunctionVisibility } from './function_visibility';
|
||||
export { FunctionVisibility };
|
||||
|
||||
export type CompatibleJSONSchema = Exclude<JSONSchema, boolean>;
|
||||
|
||||
export interface ContextDefinition {
|
||||
name: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export type FunctionResponse =
|
||||
| {
|
||||
content?: any;
|
||||
data?: any;
|
||||
}
|
||||
| Observable<ChatCompletionChunkEvent | MessageAddEvent>;
|
||||
|
||||
export interface FunctionDefinition<
|
||||
TParameters extends CompatibleJSONSchema = CompatibleJSONSchema
|
||||
> {
|
||||
name: string;
|
||||
description: string;
|
||||
visibility?: FunctionVisibility;
|
||||
descriptionForUser?: string;
|
||||
parameters: TParameters;
|
||||
contexts: string[];
|
||||
}
|
||||
|
||||
export type RegisterContextDefinition = (options: ContextDefinition) => void;
|
||||
|
||||
export type ContextRegistry = Map<string, ContextDefinition>;
|
||||
export type FunctionRegistry = Map<string, FunctionDefinition>;
|
|
@ -4,8 +4,6 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { FromSchema } from 'json-schema-to-ts';
|
||||
import { FunctionVisibility } from '../types';
|
||||
|
||||
export enum VisualizeESQLUserIntention {
|
||||
generateQueryOnly = 'generateQueryOnly',
|
||||
|
@ -26,27 +24,3 @@ export enum VisualizeESQLUserIntention {
|
|||
export const VISUALIZE_ESQL_USER_INTENTIONS: VisualizeESQLUserIntention[] = Object.values(
|
||||
VisualizeESQLUserIntention
|
||||
);
|
||||
|
||||
export const visualizeESQLFunction = {
|
||||
name: 'visualize_query',
|
||||
visibility: FunctionVisibility.UserOnly,
|
||||
description: 'Use this function to visualize charts for ES|QL queries.',
|
||||
descriptionForUser: 'Use this function to visualize charts for ES|QL queries.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
additionalProperties: true,
|
||||
properties: {
|
||||
query: {
|
||||
type: 'string',
|
||||
},
|
||||
intention: {
|
||||
type: 'string',
|
||||
enum: VISUALIZE_ESQL_USER_INTENTIONS,
|
||||
},
|
||||
},
|
||||
required: ['query', 'intention'],
|
||||
} as const,
|
||||
contexts: ['core'],
|
||||
};
|
||||
|
||||
export type VisualizeESQLFunctionArguments = FromSchema<typeof visualizeESQLFunction['parameters']>;
|
||||
|
|
|
@ -6,5 +6,34 @@
|
|||
*/
|
||||
|
||||
export type { Message, Conversation, KnowledgeBaseEntry } from './types';
|
||||
export { KnowledgeBaseEntryRole } from './types';
|
||||
export { MessageRole } from './types';
|
||||
export type { ConversationCreateRequest } from './types';
|
||||
export { KnowledgeBaseEntryRole, MessageRole } from './types';
|
||||
export type { FunctionDefinition } from './functions/types';
|
||||
export { FunctionVisibility } from './functions/function_visibility';
|
||||
export {
|
||||
VISUALIZE_ESQL_USER_INTENTIONS,
|
||||
VisualizeESQLUserIntention,
|
||||
} from './functions/visualize_esql';
|
||||
|
||||
export type {
|
||||
ChatCompletionChunkEvent,
|
||||
ConversationCreateEvent,
|
||||
ConversationUpdateEvent,
|
||||
MessageAddEvent,
|
||||
ChatCompletionErrorEvent,
|
||||
BufferFlushEvent,
|
||||
StreamingChatResponseEvent,
|
||||
StreamingChatResponseEventWithoutError,
|
||||
} from './conversation_complete';
|
||||
export {
|
||||
StreamingChatResponseEventType,
|
||||
ChatCompletionErrorCode,
|
||||
ChatCompletionError,
|
||||
createTokenLimitReachedError,
|
||||
createConversationNotFoundError,
|
||||
createInternalServerError,
|
||||
isTokenLimitReachedError,
|
||||
isChatCompletionError,
|
||||
} from './conversation_complete';
|
||||
|
||||
export { isSupportedConnectorType } from './connectors';
|
||||
|
|
|
@ -5,19 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { JSONSchema } from 'json-schema-to-ts';
|
||||
import type OpenAI from 'openai';
|
||||
import type { Observable } from 'rxjs';
|
||||
import { ChatCompletionChunkEvent, MessageAddEvent } from './conversation_complete';
|
||||
|
||||
export type CreateChatCompletionResponseChunk = Omit<OpenAI.ChatCompletionChunk, 'choices'> & {
|
||||
choices: Array<
|
||||
Omit<OpenAI.ChatCompletionChunk.Choice, 'message'> & {
|
||||
delta: { content?: string; function_call?: { name?: string; arguments?: string } };
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
export enum MessageRole {
|
||||
System = 'system',
|
||||
Assistant = 'assistant',
|
||||
|
@ -90,43 +77,6 @@ export interface KnowledgeBaseEntry {
|
|||
role: KnowledgeBaseEntryRole;
|
||||
}
|
||||
|
||||
export type CompatibleJSONSchema = Exclude<JSONSchema, boolean>;
|
||||
|
||||
export interface ContextDefinition {
|
||||
name: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export type FunctionResponse =
|
||||
| {
|
||||
content?: any;
|
||||
data?: any;
|
||||
}
|
||||
| Observable<ChatCompletionChunkEvent | MessageAddEvent>;
|
||||
|
||||
export enum FunctionVisibility {
|
||||
AssistantOnly = 'assistantOnly',
|
||||
UserOnly = 'userOnly',
|
||||
Internal = 'internal',
|
||||
All = 'all',
|
||||
}
|
||||
|
||||
export interface FunctionDefinition<
|
||||
TParameters extends CompatibleJSONSchema = CompatibleJSONSchema
|
||||
> {
|
||||
name: string;
|
||||
description: string;
|
||||
visibility?: FunctionVisibility;
|
||||
descriptionForUser?: string;
|
||||
parameters: TParameters;
|
||||
contexts: string[];
|
||||
}
|
||||
|
||||
export type RegisterContextDefinition = (options: ContextDefinition) => void;
|
||||
|
||||
export type ContextRegistry = Map<string, ContextDefinition>;
|
||||
export type FunctionRegistry = Map<string, FunctionDefinition>;
|
||||
|
||||
export interface ObservabilityAIAssistantScreenContext {
|
||||
screenDescription?: string;
|
||||
data?: Array<{
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FunctionDefinition } from '../types';
|
||||
import type { FunctionDefinition } from '../functions/types';
|
||||
|
||||
export function filterFunctionDefinitions({
|
||||
contexts,
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import OpenAI from 'openai';
|
||||
import { filter, map, Observable, tap } from 'rxjs';
|
||||
import { v4 } from 'uuid';
|
||||
import {
|
||||
|
@ -12,7 +13,14 @@ import {
|
|||
createTokenLimitReachedError,
|
||||
StreamingChatResponseEventType,
|
||||
} from '../conversation_complete';
|
||||
import type { CreateChatCompletionResponseChunk } from '../types';
|
||||
|
||||
export type CreateChatCompletionResponseChunk = Omit<OpenAI.ChatCompletionChunk, 'choices'> & {
|
||||
choices: Array<
|
||||
Omit<OpenAI.ChatCompletionChunk.Choice, 'message'> & {
|
||||
delta: { content?: string; function_call?: { name?: string; arguments?: string } };
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
export function processOpenAiStream() {
|
||||
return (source: Observable<string>): Observable<ChatCompletionChunkEvent> => {
|
||||
|
|
|
@ -8,25 +8,15 @@
|
|||
"browser": true,
|
||||
"configPath": ["xpack", "observabilityAIAssistant"],
|
||||
"requiredPlugins": [
|
||||
"alerting",
|
||||
"actions",
|
||||
"data",
|
||||
"dataViews",
|
||||
"features",
|
||||
"lens",
|
||||
"licensing",
|
||||
"observabilityShared",
|
||||
"ruleRegistry",
|
||||
"security",
|
||||
"share",
|
||||
"taskManager",
|
||||
"triggersActionsUi",
|
||||
"uiActions",
|
||||
"dataViews",
|
||||
"ml"
|
||||
],
|
||||
"requiredBundles": ["kibanaReact", "kibanaUtils"],
|
||||
"optionalPlugins": ["cloud", "serverless"],
|
||||
"extraPublicDirs": []
|
||||
"extraPublicDirs": [],
|
||||
"runtimePluginDependencies": [ "ml" ]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,33 +7,17 @@
|
|||
|
||||
import type { AnalyticsServiceSetup, AnalyticsServiceStart } from '@kbn/core-analytics-browser';
|
||||
import type { Message } from '../../common';
|
||||
import {
|
||||
eventType as chatFeedbackEventType,
|
||||
chatFeedbackEventSchema,
|
||||
ChatFeedback,
|
||||
} from './schemas/chat_feedback';
|
||||
import {
|
||||
eventType as insightFeedbackEventType,
|
||||
insightFeedbackEventSchema,
|
||||
InsightFeedback,
|
||||
} from './schemas/insight_feedback';
|
||||
import {
|
||||
eventType as userSentPromptEventType,
|
||||
userSentPromptEventSchema,
|
||||
} from './schemas/user_sent_prompt';
|
||||
import { chatFeedbackEventSchema, ChatFeedback } from './schemas/chat_feedback';
|
||||
import { insightFeedbackEventSchema, InsightFeedback } from './schemas/insight_feedback';
|
||||
import { userSentPromptEventSchema } from './schemas/user_sent_prompt';
|
||||
import { ObservabilityAIAssistantTelemetryEventType } from './telemetry_event_type';
|
||||
|
||||
const schemas = [chatFeedbackEventSchema, insightFeedbackEventSchema, userSentPromptEventSchema];
|
||||
|
||||
export const TELEMETRY = {
|
||||
[chatFeedbackEventType]: chatFeedbackEventType,
|
||||
[insightFeedbackEventType]: insightFeedbackEventType,
|
||||
[userSentPromptEventType]: userSentPromptEventType,
|
||||
} as const;
|
||||
|
||||
export type TelemetryEventTypeWithPayload =
|
||||
| { type: typeof chatFeedbackEventType; payload: ChatFeedback }
|
||||
| { type: typeof insightFeedbackEventType; payload: InsightFeedback }
|
||||
| { type: typeof userSentPromptEventType; payload: Message };
|
||||
| { type: ObservabilityAIAssistantTelemetryEventType.ChatFeedback; payload: ChatFeedback }
|
||||
| { type: ObservabilityAIAssistantTelemetryEventType.InsightFeedback; payload: InsightFeedback }
|
||||
| { type: ObservabilityAIAssistantTelemetryEventType.UserSentPromptInChat; payload: Message };
|
||||
|
||||
export const registerTelemetryEventTypes = (analytics: AnalyticsServiceSetup) => {
|
||||
schemas.forEach((schema) => {
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
import type { EventTypeOpts } from '@kbn/analytics-client';
|
||||
import type { Message, Conversation } from '../../../common';
|
||||
import type { Feedback } from '../../components/feedback_buttons';
|
||||
import type { Feedback } from '../../components/buttons/feedback_buttons';
|
||||
import { ObservabilityAIAssistantTelemetryEventType } from '../telemetry_event_type';
|
||||
import { messageSchema } from './common';
|
||||
|
||||
export interface ChatFeedback {
|
||||
|
@ -18,10 +19,8 @@ export interface ChatFeedback {
|
|||
conversation: Conversation;
|
||||
}
|
||||
|
||||
export const eventType = 'observability_ai_assistant_chat_feedback';
|
||||
|
||||
export const chatFeedbackEventSchema: EventTypeOpts<ChatFeedback> = {
|
||||
eventType,
|
||||
eventType: ObservabilityAIAssistantTelemetryEventType.ChatFeedback,
|
||||
schema: {
|
||||
messageWithFeedback: {
|
||||
properties: {
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
import type { EventTypeOpts } from '@kbn/analytics-client';
|
||||
import type { Message } from '../../../common';
|
||||
import type { Feedback } from '../../components/feedback_buttons';
|
||||
import type { Feedback } from '../../components/buttons/feedback_buttons';
|
||||
import { ObservabilityAIAssistantTelemetryEventType } from '../telemetry_event_type';
|
||||
import { messageSchema } from './common';
|
||||
|
||||
export interface InsightFeedback {
|
||||
|
@ -15,10 +16,8 @@ export interface InsightFeedback {
|
|||
message: Message;
|
||||
}
|
||||
|
||||
export const eventType = 'observability_ai_assistant_insight_feedback';
|
||||
|
||||
export const insightFeedbackEventSchema: EventTypeOpts<InsightFeedback> = {
|
||||
eventType,
|
||||
eventType: ObservabilityAIAssistantTelemetryEventType.InsightFeedback,
|
||||
schema: {
|
||||
feedback: {
|
||||
type: 'text',
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
import type { EventTypeOpts } from '@kbn/analytics-client';
|
||||
import type { Message } from '../../../common';
|
||||
import { ObservabilityAIAssistantTelemetryEventType } from '../telemetry_event_type';
|
||||
import { messageSchema } from './common';
|
||||
|
||||
export const eventType = 'observability_ai_assistant_user_sent_prompt_in_chat';
|
||||
export const userSentPromptEventSchema: EventTypeOpts<Message> = {
|
||||
eventType,
|
||||
eventType: ObservabilityAIAssistantTelemetryEventType.UserSentPromptInChat,
|
||||
schema: messageSchema,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export enum ObservabilityAIAssistantTelemetryEventType {
|
||||
ChatFeedback = 'observability_ai_assistant_chat_feedback',
|
||||
InsightFeedback = 'observability_ai_assistant_insight_feedback',
|
||||
UserSentPromptInChat = 'observability_ai_assistant_user_sent_prompt_in_chat',
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* 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 React, { useEffect, useMemo, useState } from 'react';
|
||||
import datemath from '@elastic/datemath';
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiHeaderLink,
|
||||
EuiLoadingSpinner,
|
||||
useCurrentEuiBreakpoint,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { css } from '@emotion/css';
|
||||
import moment from 'moment';
|
||||
import { ObservabilityAIAssistantChatServiceProvider } from '../../context/observability_ai_assistant_chat_service_provider';
|
||||
import { useAbortableAsync } from '../../hooks/use_abortable_async';
|
||||
import { useObservabilityAIAssistant } from '../../hooks/use_observability_ai_assistant';
|
||||
import { AssistantAvatar } from '../assistant_avatar';
|
||||
import { ChatFlyout } from '../chat/chat_flyout';
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
|
||||
const buttonLabelClassName = css`
|
||||
display: none;
|
||||
`;
|
||||
|
||||
export function ObservabilityAIAssistantActionMenuItem() {
|
||||
const service = useObservabilityAIAssistant();
|
||||
const breakpoint = useCurrentEuiBreakpoint();
|
||||
|
||||
const { plugins } = useKibana().services;
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const chatService = useAbortableAsync(
|
||||
({ signal }) => {
|
||||
if (!isOpen) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
return service.start({ signal });
|
||||
},
|
||||
[service, isOpen]
|
||||
);
|
||||
|
||||
const initialMessages = useMemo(() => [], []);
|
||||
|
||||
useEffect(() => {
|
||||
const keyboardListener = (event: KeyboardEvent) => {
|
||||
if (event.ctrlKey && event.code === 'Semicolon') {
|
||||
setIsOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('keypress', keyboardListener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('keypress', keyboardListener);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const { from, to } = plugins.start.data.query.timefilter.timefilter.getTime();
|
||||
useEffect(() => {
|
||||
const start = datemath.parse(from)?.format() ?? moment().subtract(1, 'day').toISOString();
|
||||
const end = datemath.parse(to)?.format() ?? moment().toISOString();
|
||||
|
||||
return service.setScreenContext({
|
||||
screenDescription: `The user is looking at ${window.location.href}. The current time range is ${start} - ${end}.`,
|
||||
});
|
||||
}, [service, from, to]);
|
||||
|
||||
if (!service.isEnabled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiHeaderLink
|
||||
color="primary"
|
||||
data-test-subj="observabilityAiAssistantNewChatHeaderLink"
|
||||
onClick={() => {
|
||||
setIsOpen(() => true);
|
||||
}}
|
||||
>
|
||||
<EuiFlexGroup gutterSize="s" alignItems="center" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
{!isOpen || chatService.value ? (
|
||||
<AssistantAvatar size="xs" />
|
||||
) : (
|
||||
<EuiLoadingSpinner size="m" />
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false} className={breakpoint === 'xs' ? buttonLabelClassName : ''}>
|
||||
{i18n.translate('xpack.observabilityAiAssistant.actionMenuItemLabel', {
|
||||
defaultMessage: 'AI Assistant',
|
||||
})}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiHeaderLink>
|
||||
{chatService.value ? (
|
||||
<ObservabilityAIAssistantChatServiceProvider value={chatService.value}>
|
||||
<ChatFlyout
|
||||
initialTitle=""
|
||||
initialMessages={initialMessages}
|
||||
isOpen={isOpen}
|
||||
startedFrom="appTopNavbar"
|
||||
onClose={() => {
|
||||
setIsOpen(false);
|
||||
}}
|
||||
/>
|
||||
</ObservabilityAIAssistantChatServiceProvider>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -9,6 +9,7 @@ import React, { ReactNode } from 'react';
|
|||
export interface AssistantAvatarProps {
|
||||
size?: keyof typeof sizeMap;
|
||||
children?: ReactNode;
|
||||
css?: React.SVGProps<SVGElement>['css'];
|
||||
}
|
||||
|
||||
export const sizeMap = {
|
||||
|
@ -19,14 +20,16 @@ export const sizeMap = {
|
|||
xs: 16,
|
||||
};
|
||||
|
||||
export function AssistantAvatar({ size = 's' }: AssistantAvatarProps) {
|
||||
export function AssistantAvatar({ size = 's', css }: AssistantAvatarProps) {
|
||||
const sizePx = sizeMap[size];
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={sizeMap[size]}
|
||||
height={sizeMap[size]}
|
||||
width={sizePx}
|
||||
height={sizePx}
|
||||
viewBox="0 0 64 64"
|
||||
fill="none"
|
||||
css={css}
|
||||
>
|
||||
<path fill="#F04E98" d="M36 28h24v36H36V28Z" />
|
||||
<path fill="#00BFB3" d="M4 46c0-9.941 8.059-18 18-18h6v36h-6c-9.941 0-18-8.059-18-18Z" />
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import React, { useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
|
||||
import { useKibana } from '../hooks/use_kibana';
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
|
||||
export type Feedback = 'positive' | 'negative';
|
||||
|
|
@ -8,9 +8,9 @@
|
|||
import React from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiPanel, useEuiTheme } from '@elastic/eui';
|
||||
import { css } from '@emotion/css';
|
||||
import { Feedback, FeedbackButtons } from '../feedback_buttons';
|
||||
import { RegenerateResponseButton } from '../buttons/regenerate_response_button';
|
||||
import { Feedback, FeedbackButtons } from '../buttons/feedback_buttons';
|
||||
import { StopGeneratingButton } from '../buttons/stop_generating_button';
|
||||
import { RegenerateResponseButton } from '../buttons/regenerate_response_button';
|
||||
|
||||
const containerClassName = css`
|
||||
padding-top: 4px;
|
||||
|
|
|
@ -18,8 +18,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { cloneDeep, last } from 'lodash';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { MessageRole, type Message } from '../../../common/types';
|
||||
import { sendEvent, TELEMETRY } from '../../analytics';
|
||||
import { ObservabilityAIAssistantChatServiceProvider } from '../../context/observability_ai_assistant_chat_service_provider';
|
||||
import { ObservabilityAIAssistantChatServiceContext } from '../../context/observability_ai_assistant_chat_service_context';
|
||||
import { useAbortableAsync } from '../../hooks/use_abortable_async';
|
||||
import { ChatState, useChat } from '../../hooks/use_chat';
|
||||
import { useGenAIConnectors } from '../../hooks/use_genai_connectors';
|
||||
|
@ -30,13 +29,13 @@ import { getConnectorsManagementHref } from '../../utils/get_connectors_manageme
|
|||
import { RegenerateResponseButton } from '../buttons/regenerate_response_button';
|
||||
import { StartChatButton } from '../buttons/start_chat_button';
|
||||
import { StopGeneratingButton } from '../buttons/stop_generating_button';
|
||||
import { ChatFlyout } from '../chat/chat_flyout';
|
||||
import { FeedbackButtons } from '../feedback_buttons';
|
||||
import { FeedbackButtons } from '../buttons/feedback_buttons';
|
||||
import { MessagePanel } from '../message_panel/message_panel';
|
||||
import { MessageText } from '../message_panel/message_text';
|
||||
import { MissingCredentialsCallout } from '../missing_credentials_callout';
|
||||
import { InsightBase } from './insight_base';
|
||||
import { ActionsMenu } from './actions_menu';
|
||||
import { ObservabilityAIAssistantTelemetryEventType } from '../../analytics/telemetry_event_type';
|
||||
|
||||
function getLastMessageOfType(messages: Message[], role: MessageRole) {
|
||||
return last(messages.filter((msg) => msg.message.role === role));
|
||||
|
@ -64,14 +63,15 @@ function ChatContent({
|
|||
persist: false,
|
||||
});
|
||||
|
||||
const lastAssistantResponse = getLastMessageOfType(messages, MessageRole.Assistant);
|
||||
const lastAssistantResponse = getLastMessageOfType(
|
||||
messages.slice(initialMessagesRef.current.length + 1),
|
||||
MessageRole.Assistant
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
next(initialMessagesRef.current);
|
||||
}, [next]);
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<MessagePanel
|
||||
|
@ -95,8 +95,8 @@ function ChatContent({
|
|||
<FeedbackButtons
|
||||
onClickFeedback={(feedback) => {
|
||||
if (lastAssistantResponse) {
|
||||
sendEvent(chatService.analytics, {
|
||||
type: TELEMETRY.observability_ai_assistant_insight_feedback,
|
||||
chatService.sendAnalyticsEvent({
|
||||
type: ObservabilityAIAssistantTelemetryEventType.InsightFeedback,
|
||||
payload: {
|
||||
feedback,
|
||||
message: lastAssistantResponse,
|
||||
|
@ -115,7 +115,10 @@ function ChatContent({
|
|||
<EuiFlexItem grow={false}>
|
||||
<StartChatButton
|
||||
onClick={() => {
|
||||
setIsOpen(() => true);
|
||||
service.conversations.openNewConversation({
|
||||
messages,
|
||||
title: defaultTitle,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
|
@ -123,15 +126,6 @@ function ChatContent({
|
|||
)
|
||||
}
|
||||
/>
|
||||
<ChatFlyout
|
||||
isOpen={isOpen}
|
||||
onClose={() => {
|
||||
setIsOpen(false);
|
||||
}}
|
||||
initialMessages={messages}
|
||||
initialTitle={defaultTitle}
|
||||
startedFrom="contextualInsight"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -328,9 +322,9 @@ export function Insight({ messages, title, dataTestSubj }: InsightProps) {
|
|||
isOpen={isInsightOpen}
|
||||
>
|
||||
{chatService.value ? (
|
||||
<ObservabilityAIAssistantChatServiceProvider value={chatService.value}>
|
||||
<ObservabilityAIAssistantChatServiceContext.Provider value={chatService.value}>
|
||||
{children}
|
||||
</ObservabilityAIAssistantChatServiceProvider>
|
||||
</ObservabilityAIAssistantChatServiceContext.Provider>
|
||||
) : null}
|
||||
</InsightBase>
|
||||
);
|
||||
|
|
|
@ -14,7 +14,7 @@ import { InsightBase as Component, InsightBaseProps } from './insight_base';
|
|||
import { KibanaReactStorybookDecorator } from '../../utils/storybook_decorator';
|
||||
import { MessagePanel } from '../message_panel/message_panel';
|
||||
import { MessageText } from '../message_panel/message_text';
|
||||
import { FeedbackButtons } from '../feedback_buttons';
|
||||
import { FeedbackButtons } from '../buttons/feedback_buttons';
|
||||
import { RegenerateResponseButton } from '../buttons/regenerate_response_button';
|
||||
import { StartChatButton } from '../buttons/start_chat_button';
|
||||
import { ActionsMenu } from './actions_menu';
|
||||
|
|
|
@ -8,7 +8,7 @@ import { EuiPanel } from '@elastic/eui';
|
|||
import { ComponentMeta, ComponentStoryObj } from '@storybook/react';
|
||||
import dedent from 'dedent';
|
||||
import React from 'react';
|
||||
import { FeedbackButtons } from '../feedback_buttons';
|
||||
import { FeedbackButtons } from '../buttons/feedback_buttons';
|
||||
import { MessagePanel as Component } from './message_panel';
|
||||
import { MessageText } from './message_text';
|
||||
|
||||
|
|
|
@ -11,6 +11,3 @@ import type { ObservabilityAIAssistantChatService } from '../types';
|
|||
export const ObservabilityAIAssistantChatServiceContext = createContext<
|
||||
ObservabilityAIAssistantChatService | undefined
|
||||
>(undefined);
|
||||
|
||||
export const ObservabilityAIAssistantChatServiceProvider =
|
||||
ObservabilityAIAssistantChatServiceContext.Provider;
|
|
@ -11,6 +11,3 @@ import type { ChatFlyoutSecondSlotHandler } from '../components/chat/types';
|
|||
export const ObservabilityAIAssistantMultipaneFlyoutContext = createContext<
|
||||
ChatFlyoutSecondSlotHandler | undefined
|
||||
>(undefined);
|
||||
|
||||
export const ObservabilityAIAssistantMultipaneFlyoutProvider =
|
||||
ObservabilityAIAssistantMultipaneFlyoutContext.Provider;
|
|
@ -6,15 +6,17 @@
|
|||
*/
|
||||
import type { DeeplyMockedKeys } from '@kbn/utility-types-jest';
|
||||
import { act, renderHook, type RenderHookResult } from '@testing-library/react-hooks';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { MessageRole } from '../../common';
|
||||
import { Subject } from 'rxjs';
|
||||
import {
|
||||
MessageRole,
|
||||
type ObservabilityAIAssistantChatService,
|
||||
type ObservabilityAIAssistantService,
|
||||
} from '..';
|
||||
import {
|
||||
createInternalServerError,
|
||||
StreamingChatResponseEventType,
|
||||
StreamingChatResponseEventWithoutError,
|
||||
} from '../../common/conversation_complete';
|
||||
import { mockService } from '../mock';
|
||||
import type { ObservabilityAIAssistantChatService } from '../types';
|
||||
type StreamingChatResponseEventWithoutError,
|
||||
} from '../../common';
|
||||
import { ChatState, useChat, type UseChatProps, type UseChatResult } from './use_chat';
|
||||
import * as useKibanaModule from './use_kibana';
|
||||
|
||||
|
@ -23,11 +25,7 @@ type MockedChatService = DeeplyMockedKeys<ObservabilityAIAssistantChatService>;
|
|||
const mockChatService: MockedChatService = {
|
||||
chat: jest.fn(),
|
||||
complete: jest.fn(),
|
||||
analytics: {
|
||||
optIn: jest.fn(),
|
||||
reportEvent: jest.fn(),
|
||||
telemetryCounter$: new Observable() as any,
|
||||
},
|
||||
sendAnalyticsEvent: jest.fn(),
|
||||
getContexts: jest.fn().mockReturnValue([{ name: 'core', description: '' }]),
|
||||
getFunctions: jest.fn().mockReturnValue([]),
|
||||
hasFunction: jest.fn().mockReturnValue(false),
|
||||
|
@ -70,7 +68,9 @@ describe('useChat', () => {
|
|||
},
|
||||
],
|
||||
persist: false,
|
||||
service: mockService,
|
||||
service: {
|
||||
getScreenContexts: () => [],
|
||||
} as unknown as ObservabilityAIAssistantService,
|
||||
} as UseChatProps,
|
||||
});
|
||||
});
|
||||
|
@ -97,7 +97,9 @@ describe('useChat', () => {
|
|||
chatService: mockChatService,
|
||||
initialMessages: [],
|
||||
persist: false,
|
||||
service: mockService,
|
||||
service: {
|
||||
getScreenContexts: () => [],
|
||||
} as unknown as ObservabilityAIAssistantService,
|
||||
} as UseChatProps,
|
||||
});
|
||||
|
||||
|
|
|
@ -9,18 +9,20 @@ import { i18n } from '@kbn/i18n';
|
|||
import { merge } from 'lodash';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { AbortError } from '@kbn/kibana-utils-plugin/common';
|
||||
import { MessageRole, type Message } from '../../common';
|
||||
import type { NotificationsStart } from '@kbn/core/public';
|
||||
import {
|
||||
MessageRole,
|
||||
type Message,
|
||||
ConversationCreateEvent,
|
||||
ConversationUpdateEvent,
|
||||
isTokenLimitReachedError,
|
||||
StreamingChatResponseEventType,
|
||||
} from '../../common/conversation_complete';
|
||||
import { getAssistantSetupMessage } from '../service/get_assistant_setup_message';
|
||||
import type {
|
||||
ObservabilityAIAssistantChatService,
|
||||
ObservabilityAIAssistantService,
|
||||
} from '../types';
|
||||
} from '../../common';
|
||||
import {
|
||||
getAssistantSystemMessage,
|
||||
type ObservabilityAIAssistantChatService,
|
||||
type ObservabilityAIAssistantService,
|
||||
} from '..';
|
||||
import { useKibana } from './use_kibana';
|
||||
import { useOnce } from './use_once';
|
||||
import { useUserPreferredLanguage } from './use_user_preferred_language';
|
||||
|
@ -47,7 +49,8 @@ export interface UseChatResult {
|
|||
stop: () => void;
|
||||
}
|
||||
|
||||
export interface UseChatProps {
|
||||
interface UseChatPropsWithoutContext {
|
||||
notifications: NotificationsStart;
|
||||
initialMessages: Message[];
|
||||
initialConversationId?: string;
|
||||
service: ObservabilityAIAssistantService;
|
||||
|
@ -58,20 +61,23 @@ export interface UseChatProps {
|
|||
onChatComplete?: (messages: Message[]) => void;
|
||||
}
|
||||
|
||||
export function useChat({
|
||||
export type UseChatProps = Omit<UseChatPropsWithoutContext, 'notifications'>;
|
||||
|
||||
function useChatWithoutContext({
|
||||
initialMessages,
|
||||
initialConversationId,
|
||||
notifications,
|
||||
service,
|
||||
chatService,
|
||||
connectorId,
|
||||
onConversationUpdate,
|
||||
onChatComplete,
|
||||
persist,
|
||||
}: UseChatProps): UseChatResult {
|
||||
}: UseChatPropsWithoutContext): UseChatResult {
|
||||
const [chatState, setChatState] = useState(ChatState.Ready);
|
||||
|
||||
const systemMessage = useMemo(() => {
|
||||
return getAssistantSetupMessage({ contexts: chatService.getContexts() });
|
||||
return getAssistantSystemMessage({ contexts: chatService.getContexts() });
|
||||
}, [chatService]);
|
||||
|
||||
useOnce(initialMessages);
|
||||
|
@ -86,10 +92,6 @@ export function useChat({
|
|||
|
||||
const abortControllerRef = useRef(new AbortController());
|
||||
|
||||
const {
|
||||
services: { notifications },
|
||||
} = useKibana();
|
||||
|
||||
const { getPreferredLanguage } = useUserPreferredLanguage();
|
||||
|
||||
const onChatCompleteRef = useRef(onChatComplete);
|
||||
|
@ -294,3 +296,23 @@ export function useChat({
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function useChat(props: UseChatProps) {
|
||||
const {
|
||||
services: { notifications },
|
||||
} = useKibana();
|
||||
|
||||
return useChatWithoutContext({
|
||||
...props,
|
||||
notifications,
|
||||
});
|
||||
}
|
||||
|
||||
export function createUseChat({ notifications }: { notifications: NotificationsStart }) {
|
||||
return (parameters: Omit<UseChatProps, 'notifications'>) => {
|
||||
return useChatWithoutContext({
|
||||
...parameters,
|
||||
notifications,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,16 +5,22 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { useContext } from 'react';
|
||||
import { ObservabilityAIAssistantChatServiceContext } from '../context/observability_ai_assistant_chat_service_provider';
|
||||
import { ObservabilityAIAssistantChatServiceContext } from '../context/observability_ai_assistant_chat_service_context';
|
||||
import type { ObservabilityAIAssistantChatService } from '../types';
|
||||
|
||||
export function useObservabilityAIAssistantChatService() {
|
||||
const services = useContext(ObservabilityAIAssistantChatServiceContext);
|
||||
|
||||
if (!services) {
|
||||
const service = useContext(ObservabilityAIAssistantChatServiceContext);
|
||||
if (!service) {
|
||||
throw new Error(
|
||||
'ObservabilityAIAssistantChatServiceContext not set. Did you wrap your component in `<ObservabilityAIAssistantChatServiceProvider/>`?'
|
||||
'ObservabilityAIAssistantChatServiceContext not set. Did you wrap your component in `<ObservabilityAIAssistantChatServiceContext.Provider/>`?'
|
||||
);
|
||||
}
|
||||
|
||||
return services;
|
||||
return useObservabilityAIAssistantChatServiceWithService(service);
|
||||
}
|
||||
|
||||
function useObservabilityAIAssistantChatServiceWithService(
|
||||
service: ObservabilityAIAssistantChatService
|
||||
) {
|
||||
return service;
|
||||
}
|
||||
|
|
|
@ -7,20 +7,60 @@
|
|||
import type { PluginInitializer, PluginInitializerContext } from '@kbn/core/public';
|
||||
import { ObservabilityAIAssistantPlugin } from './plugin';
|
||||
import type {
|
||||
ObservabilityAIAssistantPluginSetup,
|
||||
ObservabilityAIAssistantPluginStart,
|
||||
ObservabilityAIAssistantPublicSetup,
|
||||
ObservabilityAIAssistantPublicStart,
|
||||
ObservabilityAIAssistantPluginSetupDependencies,
|
||||
ObservabilityAIAssistantPluginStartDependencies,
|
||||
ConfigSchema,
|
||||
ObservabilityAIAssistantService,
|
||||
ObservabilityAIAssistantChatService,
|
||||
RegisterRenderFunctionDefinition,
|
||||
RenderFunction,
|
||||
} from './types';
|
||||
|
||||
export type {
|
||||
ObservabilityAIAssistantPluginSetup,
|
||||
ObservabilityAIAssistantPluginStart,
|
||||
ObservabilityAIAssistantPublicSetup,
|
||||
ObservabilityAIAssistantPublicStart,
|
||||
ObservabilityAIAssistantService,
|
||||
ObservabilityAIAssistantChatService,
|
||||
RegisterRenderFunctionDefinition,
|
||||
RenderFunction,
|
||||
};
|
||||
|
||||
export { AssistantAvatar } from './components/assistant_avatar';
|
||||
export { ConnectorSelectorBase } from './components/connector_selector/connector_selector_base';
|
||||
export { useAbortableAsync, type AbortableAsyncState } from './hooks/use_abortable_async';
|
||||
|
||||
export { createStorybookChatService, createStorybookService } from './storybook_mock';
|
||||
|
||||
export { ChatState } from './hooks/use_chat';
|
||||
|
||||
export { FeedbackButtons, type Feedback } from './components/buttons/feedback_buttons';
|
||||
export { ChatItemControls } from './components/chat/chat_item_controls';
|
||||
|
||||
export { FailedToLoadResponse } from './components/message_panel/failed_to_load_response';
|
||||
|
||||
export { MessageText } from './components/message_panel/message_text';
|
||||
|
||||
export {
|
||||
type ChatActionClickHandler,
|
||||
ChatActionClickType,
|
||||
type ChatActionClickPayload,
|
||||
} from './components/chat/types';
|
||||
|
||||
export {
|
||||
VisualizeESQLUserIntention,
|
||||
VISUALIZE_ESQL_USER_INTENTIONS,
|
||||
} from '../common/functions/visualize_esql';
|
||||
|
||||
export { getAssistantSystemMessage } from './service/get_assistant_system_message';
|
||||
|
||||
export { isSupportedConnectorType } from '../common';
|
||||
export { FunctionVisibility } from '../common';
|
||||
|
||||
export type { TelemetryEventTypeWithPayload } from './analytics';
|
||||
export { ObservabilityAIAssistantTelemetryEventType } from './analytics/telemetry_event_type';
|
||||
|
||||
export type { Conversation, Message, KnowledgeBaseEntry } from '../common';
|
||||
export { MessageRole, KnowledgeBaseEntryRole } from '../common';
|
||||
|
||||
|
@ -30,9 +70,11 @@ export type {
|
|||
APIReturnType,
|
||||
} from './api';
|
||||
|
||||
export type { UseChatResult } from './hooks/use_chat';
|
||||
|
||||
export const plugin: PluginInitializer<
|
||||
ObservabilityAIAssistantPluginSetup,
|
||||
ObservabilityAIAssistantPluginStart,
|
||||
ObservabilityAIAssistantPublicSetup,
|
||||
ObservabilityAIAssistantPublicStart,
|
||||
ObservabilityAIAssistantPluginSetupDependencies,
|
||||
ObservabilityAIAssistantPluginStartDependencies
|
||||
> = (pluginInitializerContext: PluginInitializerContext<ConfigSchema>) =>
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { AuthenticatedUser } from '@kbn/security-plugin-types-common';
|
||||
import type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { noop } from 'lodash';
|
||||
import React from 'react';
|
||||
import { Observable } from 'rxjs';
|
||||
|
@ -14,18 +12,14 @@ import type { StreamingChatResponseEventWithoutError } from '../common/conversat
|
|||
import type { ObservabilityAIAssistantAPIClient } from './api';
|
||||
import type {
|
||||
ObservabilityAIAssistantChatService,
|
||||
ObservabilityAIAssistantPluginSetup,
|
||||
ObservabilityAIAssistantPluginStart,
|
||||
ObservabilityAIAssistantPublicSetup,
|
||||
ObservabilityAIAssistantPublicStart,
|
||||
ObservabilityAIAssistantService,
|
||||
} from './types';
|
||||
import { buildFunctionElasticsearch, buildFunctionServiceSummary } from './utils/builders';
|
||||
|
||||
export const mockChatService: ObservabilityAIAssistantChatService = {
|
||||
analytics: {
|
||||
optIn: () => {},
|
||||
reportEvent: () => {},
|
||||
telemetryCounter$: new Observable(),
|
||||
},
|
||||
sendAnalyticsEvent: noop,
|
||||
chat: (options) => new Observable<StreamingChatResponseEventWithoutError>(),
|
||||
complete: (options) => new Observable<StreamingChatResponseEventWithoutError>(),
|
||||
getContexts: () => [],
|
||||
|
@ -48,43 +42,27 @@ export const mockService: ObservabilityAIAssistantService = {
|
|||
return mockChatService;
|
||||
},
|
||||
callApi: {} as ObservabilityAIAssistantAPIClient,
|
||||
getCurrentUser: async (): Promise<AuthenticatedUser> => ({
|
||||
username: 'user',
|
||||
roles: [],
|
||||
enabled: true,
|
||||
authentication_realm: { name: 'foo', type: '' },
|
||||
lookup_realm: { name: 'foo', type: '' },
|
||||
authentication_provider: { name: '', type: '' },
|
||||
authentication_type: '',
|
||||
elastic_cloud_user: false,
|
||||
}),
|
||||
getLicense: () => new Observable(),
|
||||
getLicenseManagementLocator: () =>
|
||||
({
|
||||
url: {},
|
||||
navigate: () => {},
|
||||
} as unknown as SharePluginStart),
|
||||
register: () => {},
|
||||
setScreenContext: () => noop,
|
||||
getScreenContexts: () => [],
|
||||
conversations: {
|
||||
openNewConversation: noop,
|
||||
predefinedConversation$: new Observable(),
|
||||
},
|
||||
};
|
||||
|
||||
function createSetupContract(): ObservabilityAIAssistantPluginSetup {
|
||||
function createSetupContract(): ObservabilityAIAssistantPublicSetup {
|
||||
return {};
|
||||
}
|
||||
|
||||
function createStartContract(): ObservabilityAIAssistantPluginStart {
|
||||
function createStartContract(): ObservabilityAIAssistantPublicStart {
|
||||
return {
|
||||
service: mockService,
|
||||
|
||||
ObservabilityAIAssistantActionMenuItem: (() => (
|
||||
// eslint-disable-next-line @kbn/i18n/strings_should_be_translated_with_i18n
|
||||
<div>Im a button</div>
|
||||
)) as unknown as ObservabilityAIAssistantPluginStart['ObservabilityAIAssistantActionMenuItem'],
|
||||
ObservabilityAIAssistantContextualInsight: (
|
||||
// eslint-disable-next-line @kbn/i18n/strings_should_be_translated_with_i18n
|
||||
<div>I give insight</div>
|
||||
) as unknown as ObservabilityAIAssistantPluginStart['ObservabilityAIAssistantContextualInsight'],
|
||||
ObservabilityAIAssistantContextualInsight: (() => <></>) as any,
|
||||
ObservabilityAIAssistantChatServiceContext: React.createContext<any>(undefined),
|
||||
ObservabilityAIAssistantMultipaneFlyoutContext: React.createContext<any>(undefined),
|
||||
useChat: () => ({} as any),
|
||||
useObservabilityAIAssistantChatService: () => mockChatService,
|
||||
useGenAIConnectors: () => ({
|
||||
loading: false,
|
||||
selectConnector: () => {},
|
||||
|
@ -96,6 +74,7 @@ function createStartContract(): ObservabilityAIAssistantPluginStart {
|
|||
setSelectedLanguage: () => {},
|
||||
getPreferredLanguage: () => 'English',
|
||||
}),
|
||||
getContextualInsightMessages: () => [],
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -4,39 +4,36 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import React, { ComponentType, lazy, Ref } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {
|
||||
DEFAULT_APP_CATEGORIES,
|
||||
type AppMountParameters,
|
||||
type CoreSetup,
|
||||
type CoreStart,
|
||||
type Plugin,
|
||||
type PluginInitializerContext,
|
||||
} from '@kbn/core/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { Logger } from '@kbn/logging';
|
||||
|
||||
import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public';
|
||||
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import type { Logger } from '@kbn/logging';
|
||||
import { withSuspense } from '@kbn/shared-ux-utility';
|
||||
import { createService } from './service/create_service';
|
||||
import React, { type ComponentType, lazy, type Ref } from 'react';
|
||||
import { registerTelemetryEventTypes } from './analytics';
|
||||
import { ObservabilityAIAssistantChatServiceContext } from './context/observability_ai_assistant_chat_service_context';
|
||||
import { ObservabilityAIAssistantMultipaneFlyoutContext } from './context/observability_ai_assistant_multipane_flyout_context';
|
||||
import { ObservabilityAIAssistantProvider } from './context/observability_ai_assistant_provider';
|
||||
import { createUseChat } from './hooks/use_chat';
|
||||
import { useGenAIConnectorsWithoutContext } from './hooks/use_genai_connectors';
|
||||
import { useObservabilityAIAssistantChatService } from './hooks/use_observability_ai_assistant_chat_service';
|
||||
import { createService } from './service/create_service';
|
||||
import type {
|
||||
ConfigSchema,
|
||||
ObservabilityAIAssistantPluginSetup,
|
||||
ObservabilityAIAssistantPluginSetupDependencies,
|
||||
ObservabilityAIAssistantPluginStart,
|
||||
ObservabilityAIAssistantPluginStartDependencies,
|
||||
ObservabilityAIAssistantPublicSetup,
|
||||
ObservabilityAIAssistantPublicStart,
|
||||
ObservabilityAIAssistantService,
|
||||
} from './types';
|
||||
import { registerTelemetryEventTypes } from './analytics';
|
||||
import { ObservabilityAIAssistantProvider } from './context/observability_ai_assistant_provider';
|
||||
import { useUserPreferredLanguage } from './hooks/use_user_preferred_language';
|
||||
import { getContextualInsightMessages } from './utils/get_contextual_insight_messages';
|
||||
|
||||
export class ObservabilityAIAssistantPlugin
|
||||
implements
|
||||
Plugin<
|
||||
ObservabilityAIAssistantPluginSetup,
|
||||
ObservabilityAIAssistantPluginStart,
|
||||
ObservabilityAIAssistantPublicSetup,
|
||||
ObservabilityAIAssistantPublicStart,
|
||||
ObservabilityAIAssistantPluginSetupDependencies,
|
||||
ObservabilityAIAssistantPluginStartDependencies
|
||||
>
|
||||
|
@ -50,48 +47,7 @@ export class ObservabilityAIAssistantPlugin
|
|||
setup(
|
||||
coreSetup: CoreSetup,
|
||||
pluginsSetup: ObservabilityAIAssistantPluginSetupDependencies
|
||||
): ObservabilityAIAssistantPluginSetup {
|
||||
coreSetup.application.register({
|
||||
id: 'observabilityAIAssistant',
|
||||
title: i18n.translate('xpack.observabilityAiAssistant.appTitle', {
|
||||
defaultMessage: 'Observability AI Assistant',
|
||||
}),
|
||||
euiIconType: 'logoObservability',
|
||||
appRoute: '/app/observabilityAIAssistant',
|
||||
category: DEFAULT_APP_CATEGORIES.observability,
|
||||
visibleIn: [],
|
||||
deepLinks: [
|
||||
{
|
||||
id: 'conversations',
|
||||
title: i18n.translate('xpack.observabilityAiAssistant.conversationsDeepLinkTitle', {
|
||||
defaultMessage: 'Conversations',
|
||||
}),
|
||||
path: '/conversations/new',
|
||||
},
|
||||
],
|
||||
mount: async (appMountParameters: AppMountParameters<unknown>) => {
|
||||
// Load application bundle and Get start services
|
||||
const [{ Application }, [coreStart, pluginsStart]] = await Promise.all([
|
||||
import('./application'),
|
||||
coreSetup.getStartServices(),
|
||||
]);
|
||||
|
||||
ReactDOM.render(
|
||||
<Application
|
||||
{...appMountParameters}
|
||||
service={this.service!}
|
||||
coreStart={coreStart}
|
||||
pluginsStart={pluginsStart as ObservabilityAIAssistantPluginStartDependencies}
|
||||
/>,
|
||||
appMountParameters.element
|
||||
);
|
||||
|
||||
return () => {
|
||||
ReactDOM.unmountComponentAtNode(appMountParameters.element);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
): ObservabilityAIAssistantPublicSetup {
|
||||
registerTelemetryEventTypes(coreSetup.analytics);
|
||||
|
||||
return {};
|
||||
|
@ -100,26 +56,13 @@ export class ObservabilityAIAssistantPlugin
|
|||
start(
|
||||
coreStart: CoreStart,
|
||||
pluginsStart: ObservabilityAIAssistantPluginStartDependencies
|
||||
): ObservabilityAIAssistantPluginStart {
|
||||
): ObservabilityAIAssistantPublicStart {
|
||||
const service = (this.service = createService({
|
||||
analytics: coreStart.analytics,
|
||||
coreStart,
|
||||
enabled: coreStart.application.capabilities.observabilityAIAssistant.show === true,
|
||||
licenseStart: pluginsStart.licensing,
|
||||
securityStart: pluginsStart.security,
|
||||
shareStart: pluginsStart.share,
|
||||
}));
|
||||
|
||||
service.register(async ({ registerRenderFunction }) => {
|
||||
const mod = await import('./functions');
|
||||
|
||||
return mod.registerFunctions({
|
||||
service,
|
||||
pluginsStart,
|
||||
registerRenderFunction,
|
||||
});
|
||||
});
|
||||
|
||||
const withProviders = <P extends {}, R = {}>(
|
||||
Component: ComponentType<P>,
|
||||
services: Omit<CoreStart, 'plugins'> & {
|
||||
|
@ -146,7 +89,13 @@ export class ObservabilityAIAssistantPlugin
|
|||
return {
|
||||
service,
|
||||
useGenAIConnectors: () => useGenAIConnectorsWithoutContext(service),
|
||||
useChat: createUseChat({
|
||||
notifications: coreStart.notifications,
|
||||
}),
|
||||
useUserPreferredLanguage,
|
||||
ObservabilityAIAssistantMultipaneFlyoutContext,
|
||||
ObservabilityAIAssistantChatServiceContext,
|
||||
useObservabilityAIAssistantChatService,
|
||||
ObservabilityAIAssistantContextualInsight: isEnabled
|
||||
? withSuspense(
|
||||
withProviders(
|
||||
|
@ -157,18 +106,7 @@ export class ObservabilityAIAssistantPlugin
|
|||
)
|
||||
)
|
||||
: null,
|
||||
ObservabilityAIAssistantActionMenuItem: isEnabled
|
||||
? withSuspense(
|
||||
withProviders(
|
||||
lazy(() =>
|
||||
import('./components/action_menu_item/action_menu_item').then((m) => ({
|
||||
default: m.ObservabilityAIAssistantActionMenuItem,
|
||||
}))
|
||||
),
|
||||
services
|
||||
)
|
||||
)
|
||||
: null,
|
||||
getContextualInsightMessages,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,13 +17,14 @@ import {
|
|||
type StreamingChatResponseEvent,
|
||||
} from '../../common/conversation_complete';
|
||||
import {
|
||||
FunctionRegistry,
|
||||
FunctionResponse,
|
||||
FunctionVisibility,
|
||||
type FunctionRegistry,
|
||||
type FunctionResponse,
|
||||
type Message,
|
||||
} from '../../common/types';
|
||||
} from '../../common/functions/types';
|
||||
import { type Message } from '../../common/types';
|
||||
import { filterFunctionDefinitions } from '../../common/utils/filter_function_definitions';
|
||||
import { throwSerializedChatCompletionErrors } from '../../common/utils/throw_serialized_chat_completion_errors';
|
||||
import { sendEvent } from '../analytics';
|
||||
import type { ObservabilityAIAssistantAPIClient } from '../api';
|
||||
import type {
|
||||
ChatRegistrationRenderFunction,
|
||||
|
@ -117,7 +118,9 @@ export async function createChatService({
|
|||
};
|
||||
|
||||
return {
|
||||
analytics,
|
||||
sendAnalyticsEvent: (event) => {
|
||||
sendEvent(analytics, event);
|
||||
},
|
||||
renderFunction: (name, args, response, onActionClick) => {
|
||||
const fn = renderFunctionRegistry.get(name);
|
||||
|
||||
|
|
|
@ -5,9 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { TelemetryCounter } from '@kbn/analytics-client';
|
||||
import type { DeeplyMockedKeys } from '@kbn/utility-types-jest';
|
||||
import { Observable } from 'rxjs';
|
||||
import type { ObservabilityAIAssistantChatService } from '../types';
|
||||
|
||||
type MockedChatService = DeeplyMockedKeys<ObservabilityAIAssistantChatService>;
|
||||
|
@ -16,11 +14,7 @@ export const createMockChatService = (): MockedChatService => {
|
|||
const mockChatService: MockedChatService = {
|
||||
chat: jest.fn(),
|
||||
complete: jest.fn(),
|
||||
analytics: {
|
||||
optIn: jest.fn(),
|
||||
reportEvent: jest.fn(),
|
||||
telemetryCounter$: new Observable<TelemetryCounter>() as any,
|
||||
},
|
||||
sendAnalyticsEvent: jest.fn(),
|
||||
getContexts: jest.fn().mockReturnValue([{ name: 'core', description: '' }]),
|
||||
getFunctions: jest.fn().mockReturnValue([]),
|
||||
hasFunction: jest.fn().mockReturnValue(false),
|
||||
|
|
|
@ -6,11 +6,9 @@
|
|||
*/
|
||||
|
||||
import type { AnalyticsServiceStart, CoreStart } from '@kbn/core/public';
|
||||
import type { LicensingPluginStart } from '@kbn/licensing-plugin/public';
|
||||
import type { SecurityPluginStart } from '@kbn/security-plugin/public';
|
||||
import type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { remove } from 'lodash';
|
||||
import { ObservabilityAIAssistantScreenContext } from '../../common/types';
|
||||
import { without } from 'lodash';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import type { Message, ObservabilityAIAssistantScreenContext } from '../../common/types';
|
||||
import { createCallObservabilityAIAssistantAPI } from '../api';
|
||||
import type { ChatRegistrationRenderFunction, ObservabilityAIAssistantService } from '../types';
|
||||
|
||||
|
@ -18,22 +16,17 @@ export function createService({
|
|||
analytics,
|
||||
coreStart,
|
||||
enabled,
|
||||
licenseStart,
|
||||
securityStart,
|
||||
shareStart,
|
||||
}: {
|
||||
analytics: AnalyticsServiceStart;
|
||||
coreStart: CoreStart;
|
||||
enabled: boolean;
|
||||
licenseStart: LicensingPluginStart;
|
||||
securityStart: SecurityPluginStart;
|
||||
shareStart: SharePluginStart;
|
||||
}): ObservabilityAIAssistantService {
|
||||
const client = createCallObservabilityAIAssistantAPI(coreStart);
|
||||
|
||||
const registrations: ChatRegistrationRenderFunction[] = [];
|
||||
|
||||
const screenContexts: ObservabilityAIAssistantScreenContext[] = [];
|
||||
const screenContexts$ = new BehaviorSubject<ObservabilityAIAssistantScreenContext[]>([]);
|
||||
const predefinedConversation$ = new Subject<{ messages: Message[]; title?: string }>();
|
||||
|
||||
return {
|
||||
isEnabled: () => {
|
||||
|
@ -47,17 +40,20 @@ export function createService({
|
|||
return await mod.createChatService({ analytics, client, signal, registrations });
|
||||
},
|
||||
callApi: client,
|
||||
getCurrentUser: () => securityStart.authc.getCurrentUser(),
|
||||
getLicense: () => licenseStart.license$,
|
||||
getLicenseManagementLocator: () => shareStart,
|
||||
getScreenContexts() {
|
||||
return screenContexts$.value;
|
||||
},
|
||||
setScreenContext: (context: ObservabilityAIAssistantScreenContext) => {
|
||||
screenContexts.push(context);
|
||||
screenContexts$.next(screenContexts$.value.concat(context));
|
||||
return () => {
|
||||
remove(screenContexts, context);
|
||||
screenContexts$.next(without(screenContexts$.value, context));
|
||||
};
|
||||
},
|
||||
getScreenContexts: () => {
|
||||
return screenContexts;
|
||||
conversations: {
|
||||
openNewConversation: ({ messages, title }: { messages: Message[]; title?: string }) => {
|
||||
predefinedConversation$.next({ messages, title });
|
||||
},
|
||||
predefinedConversation$: predefinedConversation$.asObservable(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,9 +7,14 @@
|
|||
|
||||
import { without } from 'lodash';
|
||||
import { MessageRole } from '../../common';
|
||||
import type { ContextDefinition, Message } from '../../common/types';
|
||||
import { ContextDefinition } from '../../common/functions/types';
|
||||
import type { Message } from '../../common/types';
|
||||
|
||||
export function getAssistantSetupMessage({ contexts }: { contexts: ContextDefinition[] }): Message {
|
||||
export function getAssistantSystemMessage({
|
||||
contexts,
|
||||
}: {
|
||||
contexts: ContextDefinition[];
|
||||
}): Message {
|
||||
const coreContext = contexts.find((context) => context.name === 'core')!;
|
||||
|
||||
const otherContexts = without(contexts.concat(), coreContext);
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { noop } from 'lodash';
|
||||
import React from 'react';
|
||||
import { Observable } from 'rxjs';
|
||||
import type { StreamingChatResponseEventWithoutError } from '../common/conversation_complete';
|
||||
import type { ObservabilityAIAssistantAPIClient } from './api';
|
||||
import type { ObservabilityAIAssistantChatService, ObservabilityAIAssistantService } from './types';
|
||||
import { buildFunctionElasticsearch, buildFunctionServiceSummary } from './utils/builders';
|
||||
|
||||
export const createStorybookChatService = (): ObservabilityAIAssistantChatService => ({
|
||||
sendAnalyticsEvent: () => {},
|
||||
chat: (options) => new Observable<StreamingChatResponseEventWithoutError>(),
|
||||
complete: (options) => new Observable<StreamingChatResponseEventWithoutError>(),
|
||||
getContexts: () => [],
|
||||
getFunctions: () => [buildFunctionElasticsearch(), buildFunctionServiceSummary()],
|
||||
renderFunction: (name) => (
|
||||
<div>
|
||||
{i18n.translate('xpack.observabilityAiAssistant.chatService.div.helloLabel', {
|
||||
defaultMessage: 'Hello',
|
||||
})}
|
||||
{name}
|
||||
</div>
|
||||
),
|
||||
hasFunction: () => true,
|
||||
hasRenderFunction: () => true,
|
||||
});
|
||||
|
||||
export const createStorybookService = (): ObservabilityAIAssistantService => ({
|
||||
isEnabled: () => true,
|
||||
start: async () => {
|
||||
return createStorybookChatService();
|
||||
},
|
||||
callApi: {} as ObservabilityAIAssistantAPIClient,
|
||||
register: () => {},
|
||||
setScreenContext: () => noop,
|
||||
getScreenContexts: () => [],
|
||||
conversations: {
|
||||
openNewConversation: noop,
|
||||
predefinedConversation$: new Observable(),
|
||||
},
|
||||
});
|
|
@ -5,56 +5,38 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { ForwardRefExoticComponent, RefAttributes } from 'react';
|
||||
import type { LicensingPluginStart } from '@kbn/licensing-plugin/public';
|
||||
import type { MlPluginSetup, MlPluginStart } from '@kbn/ml-plugin/public';
|
||||
import type { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/public';
|
||||
import type { Observable } from 'rxjs';
|
||||
import type { AnalyticsServiceStart } from '@kbn/core/public';
|
||||
import type { FeaturesPluginStart, FeaturesPluginSetup } from '@kbn/features-plugin/public';
|
||||
import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
|
||||
import type {
|
||||
DataViewsPublicPluginSetup,
|
||||
DataViewsPublicPluginStart,
|
||||
} from '@kbn/data-views-plugin/public';
|
||||
import type { LensPublicSetup, LensPublicStart } from '@kbn/lens-plugin/public';
|
||||
import type { ILicense, LicensingPluginStart } from '@kbn/licensing-plugin/public';
|
||||
import { MlPluginSetup, MlPluginStart } from '@kbn/ml-plugin/public';
|
||||
import type {
|
||||
ObservabilitySharedPluginSetup,
|
||||
ObservabilitySharedPluginStart,
|
||||
} from '@kbn/observability-shared-plugin/public';
|
||||
import type {
|
||||
AuthenticatedUser,
|
||||
SecurityPluginSetup,
|
||||
SecurityPluginStart,
|
||||
} from '@kbn/security-plugin/public';
|
||||
import type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { WithSuspenseExtendedDeps } from '@kbn/shared-ux-utility';
|
||||
import type {
|
||||
TriggersAndActionsUIPublicPluginSetup,
|
||||
TriggersAndActionsUIPublicPluginStart,
|
||||
} from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { StreamingChatResponseEventWithoutError } from '../common/conversation_complete';
|
||||
import type {
|
||||
ContextDefinition,
|
||||
FunctionDefinition,
|
||||
FunctionResponse,
|
||||
} from '../common/functions/types';
|
||||
import type {
|
||||
Message,
|
||||
ObservabilityAIAssistantScreenContext,
|
||||
PendingMessage,
|
||||
} from '../common/types';
|
||||
import type { ChatActionClickHandler } from './components/chat/types';
|
||||
import type { TelemetryEventTypeWithPayload } from './analytics';
|
||||
import type { ObservabilityAIAssistantAPIClient } from './api';
|
||||
import type { ChatActionClickHandler } from './components/chat/types';
|
||||
import type { InsightProps } from './components/insight/insight';
|
||||
import { ObservabilityAIAssistantChatServiceContext } from './context/observability_ai_assistant_chat_service_context';
|
||||
import { ObservabilityAIAssistantMultipaneFlyoutContext } from './context/observability_ai_assistant_multipane_flyout_context';
|
||||
import { useChat } from './hooks/use_chat';
|
||||
import type { UseGenAIConnectorsResult } from './hooks/use_genai_connectors';
|
||||
import { useObservabilityAIAssistantChatService } from './hooks/use_observability_ai_assistant_chat_service';
|
||||
import type { UseUserPreferredLanguageResult } from './hooks/use_user_preferred_language';
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface*/
|
||||
|
||||
export type { CreateChatCompletionResponseChunk } from '../common/types';
|
||||
export type { PendingMessage };
|
||||
|
||||
export interface ObservabilityAIAssistantChatService {
|
||||
analytics: AnalyticsServiceStart;
|
||||
sendAnalyticsEvent: (event: TelemetryEventTypeWithPayload) => void;
|
||||
chat: (
|
||||
name: string,
|
||||
options: {
|
||||
|
@ -85,16 +67,19 @@ export interface ObservabilityAIAssistantChatService {
|
|||
) => React.ReactNode;
|
||||
}
|
||||
|
||||
export interface ObservabilityAIAssistantConversationService {
|
||||
openNewConversation: ({}: { messages: Message[]; title?: string }) => void;
|
||||
predefinedConversation$: Observable<{ messages: Message[]; title?: string }>;
|
||||
}
|
||||
|
||||
export interface ObservabilityAIAssistantService {
|
||||
isEnabled: () => boolean;
|
||||
callApi: ObservabilityAIAssistantAPIClient;
|
||||
getCurrentUser: () => Promise<AuthenticatedUser>;
|
||||
getLicense: () => Observable<ILicense>;
|
||||
getLicenseManagementLocator: () => SharePluginStart;
|
||||
isEnabled: () => boolean;
|
||||
start: ({}: { signal: AbortSignal }) => Promise<ObservabilityAIAssistantChatService>;
|
||||
register: (fn: ChatRegistrationRenderFunction) => void;
|
||||
setScreenContext: (screenContext: ObservabilityAIAssistantScreenContext) => () => void;
|
||||
getScreenContexts: () => ObservabilityAIAssistantScreenContext[];
|
||||
conversations: ObservabilityAIAssistantConversationService;
|
||||
}
|
||||
|
||||
export type RenderFunction<TArguments, TResponse extends FunctionResponse> = (options: {
|
||||
|
@ -115,39 +100,27 @@ export type ChatRegistrationRenderFunction = ({}: {
|
|||
export interface ConfigSchema {}
|
||||
|
||||
export interface ObservabilityAIAssistantPluginSetupDependencies {
|
||||
data: DataPublicPluginSetup;
|
||||
dataViews: DataViewsPublicPluginSetup;
|
||||
features: FeaturesPluginSetup;
|
||||
lens: LensPublicSetup;
|
||||
observabilityShared: ObservabilitySharedPluginSetup;
|
||||
licensing: {};
|
||||
security: SecurityPluginSetup;
|
||||
triggersActionsUi: TriggersAndActionsUIPublicPluginSetup;
|
||||
ml: MlPluginSetup;
|
||||
}
|
||||
|
||||
export interface ObservabilityAIAssistantPluginStartDependencies {
|
||||
data: DataPublicPluginStart;
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
features: FeaturesPluginStart;
|
||||
lens: LensPublicStart;
|
||||
licensing: LicensingPluginStart;
|
||||
observabilityShared: ObservabilitySharedPluginStart;
|
||||
security: SecurityPluginStart;
|
||||
share: SharePluginStart;
|
||||
triggersActionsUi: TriggersAndActionsUIPublicPluginStart;
|
||||
uiActions: UiActionsStart;
|
||||
ml: MlPluginStart;
|
||||
}
|
||||
|
||||
export interface ObservabilityAIAssistantPluginSetup {}
|
||||
export interface ObservabilityAIAssistantPublicSetup {}
|
||||
|
||||
export interface ObservabilityAIAssistantPluginStart {
|
||||
export interface ObservabilityAIAssistantPublicStart {
|
||||
service: ObservabilityAIAssistantService;
|
||||
ObservabilityAIAssistantContextualInsight: React.ForwardRefExoticComponent<InsightProps> | null;
|
||||
ObservabilityAIAssistantActionMenuItem: ForwardRefExoticComponent<
|
||||
Pick<RefAttributes<{}> & WithSuspenseExtendedDeps, 'css' | 'key' | 'analytics'> &
|
||||
RefAttributes<{}>
|
||||
> | null;
|
||||
ObservabilityAIAssistantMultipaneFlyoutContext: typeof ObservabilityAIAssistantMultipaneFlyoutContext;
|
||||
ObservabilityAIAssistantChatServiceContext: typeof ObservabilityAIAssistantChatServiceContext;
|
||||
useObservabilityAIAssistantChatService: typeof useObservabilityAIAssistantChatService;
|
||||
useGenAIConnectors: () => UseGenAIConnectorsResult;
|
||||
useChat: typeof useChat;
|
||||
useUserPreferredLanguage: () => UseUserPreferredLanguageResult;
|
||||
getContextualInsightMessages: ({}: { message: string; instructions: string }) => Message[];
|
||||
}
|
||||
|
|
|
@ -5,124 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { merge, uniqueId } from 'lodash';
|
||||
import { DeepPartial } from 'utility-types';
|
||||
import {
|
||||
type Conversation,
|
||||
type FunctionDefinition,
|
||||
type Message,
|
||||
MessageRole,
|
||||
} from '../../common/types';
|
||||
import { getAssistantSetupMessage } from '../service/get_assistant_setup_message';
|
||||
|
||||
type BuildMessageProps = DeepPartial<Message> & {
|
||||
message: {
|
||||
role: MessageRole;
|
||||
function_call?: {
|
||||
name: string;
|
||||
trigger: MessageRole.Assistant | MessageRole.User | MessageRole.Elastic;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export function buildMessage(params: BuildMessageProps): Message {
|
||||
return merge(
|
||||
{
|
||||
'@timestamp': new Date().toISOString(),
|
||||
},
|
||||
params
|
||||
);
|
||||
}
|
||||
|
||||
export function buildSystemMessage(
|
||||
params?: Omit<BuildMessageProps, 'message'> & {
|
||||
message: DeepPartial<Omit<Message['message'], 'role'>>;
|
||||
}
|
||||
) {
|
||||
return buildMessage(
|
||||
merge({}, params, {
|
||||
message: { role: MessageRole.System },
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function buildUserMessage(
|
||||
params?: Omit<BuildMessageProps, 'message'> & {
|
||||
message?: DeepPartial<Omit<Message['message'], 'role'>>;
|
||||
}
|
||||
) {
|
||||
return buildMessage(
|
||||
merge(
|
||||
{
|
||||
message: {
|
||||
content: "What's a function?",
|
||||
},
|
||||
},
|
||||
params,
|
||||
{
|
||||
message: { role: MessageRole.User },
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function buildAssistantMessage(
|
||||
params?: Omit<BuildMessageProps, 'message'> & {
|
||||
message: DeepPartial<Omit<Message['message'], 'role'>>;
|
||||
}
|
||||
) {
|
||||
return buildMessage(
|
||||
merge(
|
||||
{
|
||||
message: {
|
||||
content: `In computer programming and mathematics, a function is a fundamental concept that represents a relationship between input values and output values. It takes one or more input values (also known as arguments or parameters) and processes them to produce a result, which is the output of the function. The input values are passed to the function, and the function performs a specific set of operations or calculations on those inputs to produce the desired output.
|
||||
A function is often defined with a name, which serves as an identifier to call and use the function in the code. It can be thought of as a reusable block of code that can be executed whenever needed, and it helps in organizing code and making it more modular and maintainable.`,
|
||||
},
|
||||
},
|
||||
params,
|
||||
{
|
||||
message: { role: MessageRole.Assistant },
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function buildFunctionResponseMessage(
|
||||
params?: Omit<BuildMessageProps, 'message'> & {
|
||||
message: DeepPartial<Omit<Message['message'], 'role'>>;
|
||||
}
|
||||
) {
|
||||
return buildUserMessage(
|
||||
merge(
|
||||
{},
|
||||
{
|
||||
message: {
|
||||
name: 'leftpad',
|
||||
},
|
||||
...params,
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function buildConversation(params?: Partial<Conversation>) {
|
||||
return {
|
||||
'@timestamp': '',
|
||||
user: {
|
||||
name: 'foo',
|
||||
},
|
||||
conversation: {
|
||||
id: uniqueId(),
|
||||
title: '',
|
||||
last_updated: '',
|
||||
},
|
||||
messages: [getAssistantSetupMessage({ contexts: [] })],
|
||||
labels: {},
|
||||
numeric_labels: {},
|
||||
namespace: '',
|
||||
...params,
|
||||
};
|
||||
}
|
||||
import type { FunctionDefinition } from '../../common/functions/types';
|
||||
|
||||
export function buildFunction(): FunctionDefinition {
|
||||
return {
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 Message, MessageRole } from '../../common';
|
||||
|
||||
export function getContextualInsightMessages({
|
||||
message,
|
||||
instructions,
|
||||
}: {
|
||||
message: string;
|
||||
instructions: string;
|
||||
}): Message[] {
|
||||
return [
|
||||
{
|
||||
'@timestamp': new Date().toISOString(),
|
||||
message: {
|
||||
role: MessageRole.User,
|
||||
content: message,
|
||||
},
|
||||
},
|
||||
{
|
||||
'@timestamp': new Date().toISOString(),
|
||||
message: {
|
||||
role: MessageRole.Assistant,
|
||||
function_call: {
|
||||
name: 'get_contextual_insight_instructions',
|
||||
trigger: MessageRole.Assistant,
|
||||
arguments: JSON.stringify({}),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
'@timestamp': new Date().toISOString(),
|
||||
message: {
|
||||
role: MessageRole.User,
|
||||
content: JSON.stringify({
|
||||
instructions,
|
||||
}),
|
||||
name: 'get_contextual_insight_instructions',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
|
@ -6,29 +6,20 @@
|
|||
*/
|
||||
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import React, { ComponentType } from 'react';
|
||||
import { ObservabilityAIAssistantChatServiceProvider } from '../context/observability_ai_assistant_chat_service_provider';
|
||||
import { ObservabilityAIAssistantChatServiceContext } from '../context/observability_ai_assistant_chat_service_context';
|
||||
import { ObservabilityAIAssistantProvider } from '../context/observability_ai_assistant_provider';
|
||||
// eslint-disable-next-line @kbn/imports/no_boundary_crossing
|
||||
import { mockChatService, mockService } from '../mock';
|
||||
import { createStorybookService, createStorybookChatService } from '../storybook_mock';
|
||||
|
||||
const mockService = createStorybookService();
|
||||
const mockChatService = createStorybookChatService();
|
||||
|
||||
export function KibanaReactStorybookDecorator(Story: ComponentType) {
|
||||
return (
|
||||
<KibanaContextProvider
|
||||
services={{
|
||||
triggersActionsUi: { getAddRuleFlyout: {} },
|
||||
uiSettings: {
|
||||
get: (setting: string) => {
|
||||
if (setting === 'dateFormat') {
|
||||
return 'MMM D, YYYY HH:mm';
|
||||
}
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<KibanaContextProvider>
|
||||
<ObservabilityAIAssistantProvider value={mockService}>
|
||||
<ObservabilityAIAssistantChatServiceProvider value={mockChatService}>
|
||||
<ObservabilityAIAssistantChatServiceContext.Provider value={mockChatService}>
|
||||
<Story />
|
||||
</ObservabilityAIAssistantChatServiceProvider>
|
||||
</ObservabilityAIAssistantChatServiceContext.Provider>
|
||||
</ObservabilityAIAssistantProvider>
|
||||
</KibanaContextProvider>
|
||||
);
|
||||
|
|
|
@ -22,13 +22,14 @@ import {
|
|||
StreamingChatResponseEvent,
|
||||
StreamingChatResponseEventType,
|
||||
} from '../../common/conversation_complete';
|
||||
import { FunctionDefinition, ObservabilityAIAssistantScreenContext } from '../../common/types';
|
||||
import { ObservabilityAIAssistantScreenContext } from '../../common/types';
|
||||
import { concatenateChatCompletionChunks } from '../../common/utils/concatenate_chat_completion_chunks';
|
||||
import { throwSerializedChatCompletionErrors } from '../../common/utils/throw_serialized_chat_completion_errors';
|
||||
import { APIReturnType, ObservabilityAIAssistantAPIClientRequestParamsOf } from '../../public';
|
||||
import { getAssistantSetupMessage } from '../../public/service/get_assistant_setup_message';
|
||||
import { getAssistantSystemMessage } from '../../public/service/get_assistant_system_message';
|
||||
import { streamIntoObservable } from '../../server/service/util/stream_into_observable';
|
||||
import { EvaluationResult } from './types';
|
||||
import { FunctionDefinition } from '../../common/functions/types';
|
||||
|
||||
// eslint-disable-next-line spaced-comment
|
||||
/// <reference types="@kbn/ambient-ftr-types"/>
|
||||
|
@ -260,7 +261,7 @@ export class KibanaClient {
|
|||
chat: async (message) => {
|
||||
const { functionDefinitions, contextDefinitions } = await getFunctions();
|
||||
const messages = [
|
||||
getAssistantSetupMessage({ contexts: contextDefinitions }),
|
||||
getAssistantSystemMessage({ contexts: contextDefinitions }),
|
||||
...getMessages(message).map((msg) => ({
|
||||
message: msg,
|
||||
'@timestamp': new Date().toISOString(),
|
||||
|
@ -297,7 +298,7 @@ export class KibanaClient {
|
|||
|
||||
const { contextDefinitions } = await getFunctions();
|
||||
const messages = [
|
||||
getAssistantSetupMessage({ contexts: contextDefinitions }),
|
||||
getAssistantSystemMessage({ contexts: contextDefinitions }),
|
||||
...getMessages(messagesArg!).map((msg) => ({
|
||||
message: msg,
|
||||
'@timestamp': new Date().toISOString(),
|
||||
|
|
|
@ -15,7 +15,8 @@ import { compact, last, omit } from 'lodash';
|
|||
import { lastValueFrom, Observable } from 'rxjs';
|
||||
import { FunctionRegistrationParameters } from '.';
|
||||
import { MessageAddEvent } from '../../common/conversation_complete';
|
||||
import { FunctionVisibility, MessageRole, type Message } from '../../common/types';
|
||||
import { FunctionVisibility } from '../../common/functions/types';
|
||||
import { MessageRole, type Message } from '../../common/types';
|
||||
import { concatenateChatCompletionChunks } from '../../common/utils/concatenate_chat_completion_chunks';
|
||||
import type { ObservabilityAIAssistantClient } from '../service/client';
|
||||
import { createFunctionResponseMessage } from '../service/util/create_function_response_message';
|
||||
|
@ -25,11 +26,11 @@ const MAX_TOKEN_COUNT_FOR_DATA_ON_SCREEN = 1000;
|
|||
|
||||
export function registerContextFunction({
|
||||
client,
|
||||
registerFunction,
|
||||
functions,
|
||||
resources,
|
||||
isKnowledgeBaseAvailable,
|
||||
}: FunctionRegistrationParameters & { isKnowledgeBaseAvailable: boolean }) {
|
||||
registerFunction(
|
||||
functions.registerFunction(
|
||||
{
|
||||
name: 'context',
|
||||
contexts: ['core'],
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
import type { FunctionRegistrationParameters } from '.';
|
||||
|
||||
export function registerElasticsearchFunction({
|
||||
registerFunction,
|
||||
functions,
|
||||
resources,
|
||||
}: FunctionRegistrationParameters) {
|
||||
registerFunction(
|
||||
functions.registerFunction(
|
||||
{
|
||||
name: 'elasticsearch',
|
||||
contexts: ['core'],
|
||||
|
|
|
@ -8,15 +8,16 @@
|
|||
import { chunk, groupBy, uniq } from 'lodash';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { FunctionRegistrationParameters } from '.';
|
||||
import { FunctionVisibility, MessageRole } from '../../common/types';
|
||||
import { FunctionVisibility } from '../../common/functions/types';
|
||||
import { MessageRole } from '../../common/types';
|
||||
import { concatenateChatCompletionChunks } from '../../common/utils/concatenate_chat_completion_chunks';
|
||||
|
||||
export function registerGetDatasetInfoFunction({
|
||||
client,
|
||||
resources,
|
||||
registerFunction,
|
||||
functions,
|
||||
}: FunctionRegistrationParameters) {
|
||||
registerFunction(
|
||||
functions.registerFunction(
|
||||
{
|
||||
name: 'get_dataset_info',
|
||||
contexts: ['core'],
|
||||
|
|
|
@ -8,31 +8,25 @@
|
|||
import dedent from 'dedent';
|
||||
import { registerContextFunction } from './context';
|
||||
import { registerSummarizationFunction } from './summarize';
|
||||
import { ChatRegistrationFunction } from '../service/types';
|
||||
import { registerAlertsFunction } from './alerts';
|
||||
import type { RegistrationCallback } from '../service/types';
|
||||
import { registerElasticsearchFunction } from './elasticsearch';
|
||||
import { registerQueryFunction } from './query';
|
||||
import { registerGetDatasetInfoFunction } from './get_dataset_info';
|
||||
import { registerLensFunction } from './lens';
|
||||
import { registerKibanaFunction } from './kibana';
|
||||
import { registerVisualizeESQLFunction } from './visualize_esql';
|
||||
|
||||
export type FunctionRegistrationParameters = Omit<
|
||||
Parameters<ChatRegistrationFunction>[0],
|
||||
Parameters<RegistrationCallback>[0],
|
||||
'registerContext' | 'hasFunction'
|
||||
>;
|
||||
|
||||
export const registerFunctions: ChatRegistrationFunction = async ({
|
||||
export const registerFunctions: RegistrationCallback = async ({
|
||||
client,
|
||||
registerContext,
|
||||
registerFunction,
|
||||
hasFunction,
|
||||
functions,
|
||||
resources,
|
||||
signal,
|
||||
}) => {
|
||||
const registrationParameters: FunctionRegistrationParameters = {
|
||||
client,
|
||||
registerFunction,
|
||||
functions,
|
||||
resources,
|
||||
signal,
|
||||
};
|
||||
|
@ -79,7 +73,7 @@ export const registerFunctions: ChatRegistrationFunction = async ({
|
|||
If the "get_dataset_info" function returns no data, and the user asks for a query, generate a query anyway with the "query" function, but be explicit about it potentially being incorrect.
|
||||
|
||||
${
|
||||
hasFunction('get_data_on_screen')
|
||||
functions.hasFunction('get_data_on_screen')
|
||||
? `You have access to data on the screen by calling the "get_data_on_screen" function.
|
||||
Use it to help the user understand what they are looking at. A short summary of what they are looking at is available in the return of the "context" function.
|
||||
Data that is compact enough automatically gets included in the response for the "context" function.
|
||||
|
@ -103,7 +97,6 @@ export const registerFunctions: ChatRegistrationFunction = async ({
|
|||
`;
|
||||
|
||||
registerSummarizationFunction(registrationParameters);
|
||||
registerLensFunction(registrationParameters);
|
||||
} else {
|
||||
description += `You do not have a working memory. If the user expects you to remember the previous conversations, tell them they can set up the knowledge base.`;
|
||||
}
|
||||
|
@ -111,13 +104,20 @@ export const registerFunctions: ChatRegistrationFunction = async ({
|
|||
registerContextFunction({ ...registrationParameters, isKnowledgeBaseAvailable: isReady });
|
||||
|
||||
registerElasticsearchFunction(registrationParameters);
|
||||
registerKibanaFunction(registrationParameters);
|
||||
registerQueryFunction(registrationParameters);
|
||||
registerVisualizeESQLFunction(registrationParameters);
|
||||
registerAlertsFunction(registrationParameters);
|
||||
const request = registrationParameters.resources.request;
|
||||
|
||||
if ('id' in request) {
|
||||
registerKibanaFunction({
|
||||
...registrationParameters,
|
||||
resources: {
|
||||
...registrationParameters.resources,
|
||||
request,
|
||||
},
|
||||
});
|
||||
}
|
||||
registerGetDatasetInfoFunction(registrationParameters);
|
||||
|
||||
registerContext({
|
||||
functions.registerContext({
|
||||
name: 'core',
|
||||
description: dedent(description),
|
||||
});
|
||||
|
|
|
@ -8,13 +8,16 @@
|
|||
import axios from 'axios';
|
||||
import { format, parse } from 'url';
|
||||
import { castArray, first, pick, pickBy } from 'lodash';
|
||||
import type { KibanaRequest } from '@kbn/core/server';
|
||||
import type { FunctionRegistrationParameters } from '.';
|
||||
|
||||
export function registerKibanaFunction({
|
||||
registerFunction,
|
||||
functions,
|
||||
resources,
|
||||
}: FunctionRegistrationParameters) {
|
||||
registerFunction(
|
||||
}: FunctionRegistrationParameters & {
|
||||
resources: { request: KibanaRequest };
|
||||
}) {
|
||||
functions.registerFunction(
|
||||
{
|
||||
name: 'kibana',
|
||||
contexts: ['core'],
|
||||
|
|
|
@ -10,9 +10,9 @@ import { KnowledgeBaseEntryRole } from '../../common';
|
|||
|
||||
export function registerSummarizationFunction({
|
||||
client,
|
||||
registerFunction,
|
||||
functions,
|
||||
}: FunctionRegistrationParameters) {
|
||||
registerFunction(
|
||||
functions.registerFunction(
|
||||
{
|
||||
name: 'summarize',
|
||||
contexts: ['core'],
|
||||
|
|
|
@ -11,9 +11,10 @@ import type { ObservabilityAIAssistantConfig } from './config';
|
|||
export type { ObservabilityAIAssistantServerRouteRepository } from './routes/get_global_observability_ai_assistant_route_repository';
|
||||
|
||||
import { config as configSchema } from './config';
|
||||
export type { RegistrationCallback } from './service/types';
|
||||
export type {
|
||||
ObservabilityAIAssistantPluginStart,
|
||||
ObservabilityAIAssistantPluginSetup,
|
||||
ObservabilityAIAssistantServerStart,
|
||||
ObservabilityAIAssistantServerSetup,
|
||||
} from './types';
|
||||
|
||||
export const config: PluginConfigDescriptor<ObservabilityAIAssistantConfig> = {
|
||||
|
|
|
@ -26,8 +26,8 @@ import { registerServerRoutes } from './routes/register_routes';
|
|||
import { ObservabilityAIAssistantRouteHandlerResources } from './routes/types';
|
||||
import { ObservabilityAIAssistantService } from './service';
|
||||
import {
|
||||
ObservabilityAIAssistantPluginSetup,
|
||||
ObservabilityAIAssistantPluginStart,
|
||||
ObservabilityAIAssistantServerSetup,
|
||||
ObservabilityAIAssistantServerStart,
|
||||
ObservabilityAIAssistantPluginSetupDependencies,
|
||||
ObservabilityAIAssistantPluginStartDependencies,
|
||||
} from './types';
|
||||
|
@ -37,8 +37,8 @@ import { registerFunctions } from './functions';
|
|||
export class ObservabilityAIAssistantPlugin
|
||||
implements
|
||||
Plugin<
|
||||
ObservabilityAIAssistantPluginSetup,
|
||||
ObservabilityAIAssistantPluginStart,
|
||||
ObservabilityAIAssistantServerSetup,
|
||||
ObservabilityAIAssistantServerStart,
|
||||
ObservabilityAIAssistantPluginSetupDependencies,
|
||||
ObservabilityAIAssistantPluginStartDependencies
|
||||
>
|
||||
|
@ -52,10 +52,10 @@ export class ObservabilityAIAssistantPlugin
|
|||
public setup(
|
||||
core: CoreSetup<
|
||||
ObservabilityAIAssistantPluginStartDependencies,
|
||||
ObservabilityAIAssistantPluginStart
|
||||
ObservabilityAIAssistantServerStart
|
||||
>,
|
||||
plugins: ObservabilityAIAssistantPluginSetupDependencies
|
||||
): ObservabilityAIAssistantPluginSetup {
|
||||
): ObservabilityAIAssistantServerSetup {
|
||||
plugins.features.registerKibanaFeature({
|
||||
id: OBSERVABILITY_AI_ASSISTANT_FEATURE_ID,
|
||||
name: i18n.translate('xpack.observabilityAiAssistant.featureRegistry.featureName', {
|
||||
|
@ -113,10 +113,23 @@ export class ObservabilityAIAssistantPlugin
|
|||
// Wait for the ML plugin's dependency on the internal saved objects client to be ready
|
||||
const [_, pluginsStart] = await core.getStartServices();
|
||||
|
||||
const { ml } = await core.plugins.onSetup('ml');
|
||||
|
||||
if (!ml.found) {
|
||||
throw new Error('Could not find ML plugin');
|
||||
}
|
||||
|
||||
// Wait for the license to be available so the ML plugin's guards pass once we ask for ELSER stats
|
||||
await firstValueFrom(pluginsStart.licensing.license$);
|
||||
|
||||
const elserModelDefinition = await plugins.ml
|
||||
const elserModelDefinition = await (
|
||||
ml.contract as {
|
||||
trainedModelsProvider: (
|
||||
request: {},
|
||||
soClient: {}
|
||||
) => { getELSER: () => Promise<{ model_id: string }> };
|
||||
}
|
||||
)
|
||||
.trainedModelsProvider({} as any, {} as any) // request, savedObjectsClient (but we fake it to use the internal user)
|
||||
.getELSER();
|
||||
|
||||
|
@ -154,7 +167,7 @@ export class ObservabilityAIAssistantPlugin
|
|||
};
|
||||
}
|
||||
|
||||
public start(): ObservabilityAIAssistantPluginStart {
|
||||
public start(): ObservabilityAIAssistantServerStart {
|
||||
return {
|
||||
service: this.service!,
|
||||
};
|
||||
|
|
|
@ -7,11 +7,8 @@
|
|||
import { notImplemented } from '@hapi/boom';
|
||||
import { nonEmptyStringRt, toBooleanRt } from '@kbn/io-ts-utils';
|
||||
import * as t from 'io-ts';
|
||||
import {
|
||||
ContextDefinition,
|
||||
FunctionDefinition,
|
||||
KnowledgeBaseEntryRole,
|
||||
} from '../../../common/types';
|
||||
import { ContextDefinition, FunctionDefinition } from '../../../common/functions/types';
|
||||
import { KnowledgeBaseEntryRole } from '../../../common/types';
|
||||
import type { RecalledEntry } from '../../service/knowledge_base_service';
|
||||
import { createObservabilityAIAssistantServerRoute } from '../create_observability_ai_assistant_server_route';
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
import type { CustomRequestHandlerContext, KibanaRequest } from '@kbn/core/server';
|
||||
import type { Logger } from '@kbn/logging';
|
||||
import type { RacApiRequestHandlerContext } from '@kbn/rule-registry-plugin/server';
|
||||
import type { LicensingApiRequestHandlerContext } from '@kbn/licensing-plugin/server/types';
|
||||
import type { AlertingApiRequestHandlerContext } from '@kbn/alerting-plugin/server/types';
|
||||
import type { RacApiRequestHandlerContext } from '@kbn/rule-registry-plugin/server';
|
||||
import type { AlertingApiRequestHandlerContext } from '@kbn/alerting-plugin/server';
|
||||
import type { ObservabilityAIAssistantService } from '../service';
|
||||
import type {
|
||||
ObservabilityAIAssistantPluginSetupDependencies,
|
||||
|
@ -17,8 +17,9 @@ import type {
|
|||
} from '../types';
|
||||
|
||||
export type ObservabilityAIAssistantRequestHandlerContext = CustomRequestHandlerContext<{
|
||||
rac: RacApiRequestHandlerContext;
|
||||
licensing: LicensingApiRequestHandlerContext;
|
||||
// these two are here for compatibility with APM functions
|
||||
rac: RacApiRequestHandlerContext;
|
||||
alerting: AlertingApiRequestHandlerContext;
|
||||
}>;
|
||||
|
||||
|
|
|
@ -4,11 +4,9 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import Ajv, { type ValidateFunction } from 'ajv';
|
||||
import dedent from 'dedent';
|
||||
import { ChatFunctionClient } from '.';
|
||||
import { ContextRegistry, FunctionVisibility } from '../../../common/types';
|
||||
import type { FunctionHandlerRegistry } from '../types';
|
||||
import { FunctionVisibility } from '../../../common/functions/types';
|
||||
|
||||
describe('chatFunctionClient', () => {
|
||||
describe('when executing a function with invalid arguments', () => {
|
||||
|
@ -17,43 +15,10 @@ describe('chatFunctionClient', () => {
|
|||
let respondFn: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
const contextRegistry: ContextRegistry = new Map();
|
||||
contextRegistry.set('core', {
|
||||
description: '',
|
||||
name: 'core',
|
||||
});
|
||||
|
||||
respondFn = jest.fn().mockImplementationOnce(async () => {
|
||||
return {};
|
||||
});
|
||||
|
||||
const functionRegistry: FunctionHandlerRegistry = new Map();
|
||||
functionRegistry.set('myFunction', {
|
||||
respond: respondFn,
|
||||
definition: {
|
||||
contexts: ['core'],
|
||||
description: '',
|
||||
name: 'myFunction',
|
||||
parameters: {
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
required: ['foo'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const validators = new Map<string, ValidateFunction>();
|
||||
|
||||
validators.set(
|
||||
'myFunction',
|
||||
new Ajv({ strict: false }).compile(
|
||||
functionRegistry.get('myFunction')!.definition.parameters
|
||||
)
|
||||
);
|
||||
|
||||
client = new ChatFunctionClient([]);
|
||||
client.registerContext({
|
||||
description: '',
|
||||
|
|
|
@ -10,14 +10,13 @@ import Ajv, { type ErrorObject, type ValidateFunction } from 'ajv';
|
|||
import dedent from 'dedent';
|
||||
import { compact, keyBy } from 'lodash';
|
||||
import {
|
||||
ContextDefinition,
|
||||
ContextRegistry,
|
||||
FunctionResponse,
|
||||
type ContextRegistry,
|
||||
FunctionVisibility,
|
||||
Message,
|
||||
ObservabilityAIAssistantScreenContext,
|
||||
RegisterContextDefinition,
|
||||
} from '../../../common/types';
|
||||
type RegisterContextDefinition,
|
||||
type ContextDefinition,
|
||||
type FunctionResponse,
|
||||
} from '../../../common/functions/types';
|
||||
import type { Message, ObservabilityAIAssistantScreenContext } from '../../../common/types';
|
||||
import { filterFunctionDefinitions } from '../../../common/utils/filter_function_definitions';
|
||||
import type { FunctionHandler, FunctionHandlerRegistry, RegisterFunction } from '../types';
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import type { Observable } from 'rxjs';
|
|||
import type { Logger } from '@kbn/logging';
|
||||
import type { Message } from '../../../../common';
|
||||
import type { ChatCompletionChunkEvent } from '../../../../common/conversation_complete';
|
||||
import type { CompatibleJSONSchema } from '../../../../common/types';
|
||||
import { CompatibleJSONSchema } from '../../../../common/functions/types';
|
||||
|
||||
export type LlmApiAdapterFactory = (options: {
|
||||
logger: Logger;
|
||||
|
|
|
@ -23,7 +23,7 @@ import {
|
|||
MessageAddEvent,
|
||||
StreamingChatResponseEventType,
|
||||
} from '../../../common/conversation_complete';
|
||||
import type { CreateChatCompletionResponseChunk } from '../../../public/types';
|
||||
import type { CreateChatCompletionResponseChunk } from '../../../common/utils/process_openai_stream';
|
||||
import type { ChatFunctionClient } from '../chat_function_client';
|
||||
import type { KnowledgeBaseService } from '../knowledge_base_service';
|
||||
import { createFunctionResponseMessage } from '../util/create_function_response_message';
|
||||
|
|
|
@ -35,10 +35,12 @@ import {
|
|||
type StreamingChatResponseEvent,
|
||||
} from '../../../common/conversation_complete';
|
||||
import {
|
||||
CompatibleJSONSchema,
|
||||
FunctionResponse,
|
||||
FunctionVisibility,
|
||||
} from '../../../common/functions/types';
|
||||
import {
|
||||
MessageRole,
|
||||
type CompatibleJSONSchema,
|
||||
type Conversation,
|
||||
type ConversationCreateRequest,
|
||||
type ConversationUpdateRequest,
|
||||
|
|
|
@ -21,7 +21,7 @@ import { conversationComponentTemplate } from './conversation_component_template
|
|||
import { kbComponentTemplate } from './kb_component_template';
|
||||
import { KnowledgeBaseEntryOperationType, KnowledgeBaseService } from './knowledge_base_service';
|
||||
import type {
|
||||
ChatRegistrationFunction,
|
||||
RegistrationCallback,
|
||||
ObservabilityAIAssistantResourceNames,
|
||||
RespondFunctionResources,
|
||||
} from './types';
|
||||
|
@ -76,7 +76,7 @@ export class ObservabilityAIAssistantService {
|
|||
|
||||
private readonly resourceNames: ObservabilityAIAssistantResourceNames = createResourceNamesMap();
|
||||
|
||||
private readonly registrations: ChatRegistrationFunction[] = [];
|
||||
private readonly registrations: RegistrationCallback[] = [];
|
||||
|
||||
constructor({
|
||||
logger,
|
||||
|
@ -300,9 +300,7 @@ export class ObservabilityAIAssistantService {
|
|||
|
||||
const params = {
|
||||
signal,
|
||||
registerContext: fnClient.registerContext.bind(fnClient),
|
||||
registerFunction: fnClient.registerFunction.bind(fnClient),
|
||||
hasFunction: fnClient.hasFunction.bind(fnClient),
|
||||
functions: fnClient,
|
||||
resources,
|
||||
client,
|
||||
};
|
||||
|
@ -373,7 +371,7 @@ export class ObservabilityAIAssistantService {
|
|||
);
|
||||
}
|
||||
|
||||
register(fn: ChatRegistrationFunction) {
|
||||
this.registrations.push(fn);
|
||||
register(cb: RegistrationCallback) {
|
||||
this.registrations.push(cb);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,10 +10,8 @@ import type {
|
|||
CompatibleJSONSchema,
|
||||
FunctionDefinition,
|
||||
FunctionResponse,
|
||||
Message,
|
||||
ObservabilityAIAssistantScreenContext,
|
||||
RegisterContextDefinition,
|
||||
} from '../../common/types';
|
||||
} from '../../common/functions/types';
|
||||
import type { Message, ObservabilityAIAssistantScreenContext } from '../../common/types';
|
||||
import type { ObservabilityAIAssistantRouteHandlerResources } from '../routes/types';
|
||||
import { ChatFunctionClient } from './chat_function_client';
|
||||
import type { ObservabilityAIAssistantClient } from './client';
|
||||
|
@ -48,13 +46,11 @@ export type RegisterFunction = <
|
|||
) => void;
|
||||
export type FunctionHandlerRegistry = Map<string, FunctionHandler>;
|
||||
|
||||
export type ChatRegistrationFunction = ({}: {
|
||||
export type RegistrationCallback = ({}: {
|
||||
signal: AbortSignal;
|
||||
resources: RespondFunctionResources;
|
||||
client: ObservabilityAIAssistantClient;
|
||||
registerFunction: RegisterFunction;
|
||||
registerContext: RegisterContextDefinition;
|
||||
hasFunction: ChatFunctionClient['hasFunction'];
|
||||
functions: ChatFunctionClient;
|
||||
}) => Promise<void>;
|
||||
|
||||
export interface ObservabilityAIAssistantResourceNames {
|
||||
|
|
|
@ -21,20 +21,19 @@ import type {
|
|||
DataViewsServerPluginSetup,
|
||||
DataViewsServerPluginStart,
|
||||
} from '@kbn/data-views-plugin/server';
|
||||
import type { MlPluginSetup, MlPluginStart } from '@kbn/ml-plugin/server';
|
||||
import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server';
|
||||
import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/server';
|
||||
import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/server';
|
||||
import type { ObservabilityAIAssistantService } from './service';
|
||||
|
||||
export interface ObservabilityAIAssistantPluginSetup {
|
||||
export interface ObservabilityAIAssistantServerSetup {
|
||||
/**
|
||||
* Returns a Observability AI Assistant service instance
|
||||
*/
|
||||
service: ObservabilityAIAssistantService;
|
||||
}
|
||||
|
||||
export interface ObservabilityAIAssistantPluginStart {
|
||||
export interface ObservabilityAIAssistantServerStart {
|
||||
/**
|
||||
* Returns a Observability AI Assistant service instance
|
||||
*/
|
||||
|
@ -47,18 +46,17 @@ export interface ObservabilityAIAssistantPluginSetupDependencies {
|
|||
features: FeaturesPluginSetup;
|
||||
taskManager: TaskManagerSetupContract;
|
||||
dataViews: DataViewsServerPluginSetup;
|
||||
ml: MlPluginSetup;
|
||||
licensing: LicensingPluginSetup;
|
||||
cloud?: CloudSetup;
|
||||
serverless?: ServerlessPluginSetup;
|
||||
}
|
||||
|
||||
export interface ObservabilityAIAssistantPluginStartDependencies {
|
||||
actions: ActionsPluginStart;
|
||||
security: SecurityPluginStart;
|
||||
features: FeaturesPluginStart;
|
||||
taskManager: TaskManagerStartContract;
|
||||
dataViews: DataViewsServerPluginStart;
|
||||
ml: MlPluginStart;
|
||||
licensing: LicensingPluginStart;
|
||||
cloud?: CloudStart;
|
||||
serverless?: ServerlessPluginStart;
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
"@kbn/utility-types",
|
||||
"@kbn/server-route-repository",
|
||||
"@kbn/logging",
|
||||
"@kbn/triggers-actions-ui-plugin",
|
||||
"@kbn/config-schema",
|
||||
"@kbn/security-plugin",
|
||||
"@kbn/i18n",
|
||||
|
@ -26,50 +25,28 @@
|
|||
"@kbn/kibana-react-plugin",
|
||||
"@kbn/shared-ux-utility",
|
||||
"@kbn/alerting-plugin",
|
||||
"@kbn/shared-ux-link-redirect-app",
|
||||
"@kbn/typed-react-router-config",
|
||||
"@kbn/ui-theme",
|
||||
"@kbn/user-profile-components",
|
||||
"@kbn/observability-shared-plugin",
|
||||
"@kbn/kibana-utils-plugin",
|
||||
"@kbn/monaco",
|
||||
"@kbn/io-ts-utils",
|
||||
"@kbn/std",
|
||||
"@kbn/alerting-plugin",
|
||||
"@kbn/features-plugin",
|
||||
"@kbn/react-kibana-context-theme",
|
||||
"@kbn/lens-embeddable-utils",
|
||||
"@kbn/i18n-react",
|
||||
"@kbn/field-formats-plugin",
|
||||
"@kbn/lens-plugin",
|
||||
"@kbn/data-views-plugin",
|
||||
"@kbn/task-manager-plugin",
|
||||
"@kbn/es-query",
|
||||
"@kbn/rule-registry-plugin",
|
||||
"@kbn/licensing-plugin",
|
||||
"@kbn/share-plugin",
|
||||
"@kbn/utility-types-jest",
|
||||
"@kbn/analytics-client",
|
||||
"@kbn/tooling-log",
|
||||
"@kbn/babel-register",
|
||||
"@kbn/dev-cli-runner",
|
||||
"@kbn/core-analytics-browser",
|
||||
"@kbn/core-http-browser",
|
||||
"@kbn/security-plugin-types-common",
|
||||
"@kbn/ml-plugin",
|
||||
"@kbn/expect",
|
||||
"@kbn/apm-synthtrace-client",
|
||||
"@kbn/apm-synthtrace",
|
||||
"@kbn/code-editor",
|
||||
"@kbn/safer-lodash-set",
|
||||
"@kbn/cloud-plugin",
|
||||
"@kbn/ui-actions-plugin",
|
||||
"@kbn/expressions-plugin",
|
||||
"@kbn/visualization-utils",
|
||||
"@kbn/field-types",
|
||||
"@kbn/es-types",
|
||||
"@kbn/esql-utils",
|
||||
"@kbn/data-plugin",
|
||||
"@kbn/serverless"
|
||||
],
|
||||
"exclude": ["target/**/*"]
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* 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 { setGlobalConfig } from '@storybook/testing-react';
|
||||
import * as globalStorybookConfig from './preview';
|
||||
|
||||
setGlobalConfig(globalStorybookConfig);
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
module.exports = require('@kbn/storybook').defaultConfig;
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* 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 { EuiThemeProviderDecorator } from '@kbn/kibana-react-plugin/common';
|
||||
|
||||
export const decorators = [EuiThemeProviderDecorator];
|
|
@ -0,0 +1,3 @@
|
|||
#### Observability AI Assistant App
|
||||
|
||||
This app registers defaults functions. It exists as a separate plugin to avoid cyclical dependencies.
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { FromSchema } from 'json-schema-to-ts';
|
||||
import { FIELD_FORMAT_IDS } from '@kbn/field-formats-plugin/common';
|
||||
import { FunctionVisibility } from '../types';
|
||||
import { FunctionVisibility } from '@kbn/observability-ai-assistant-plugin/common';
|
||||
|
||||
export enum SeriesType {
|
||||
Bar = 'bar',
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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 { FromSchema } from 'json-schema-to-ts';
|
||||
import { FunctionVisibility } from '@kbn/observability-ai-assistant-plugin/common';
|
||||
import { VISUALIZE_ESQL_USER_INTENTIONS } from '@kbn/observability-ai-assistant-plugin/common/functions/visualize_esql';
|
||||
|
||||
export const visualizeESQLFunction = {
|
||||
name: 'visualize_query',
|
||||
visibility: FunctionVisibility.UserOnly,
|
||||
description: 'Use this function to visualize charts for ES|QL queries.',
|
||||
descriptionForUser: 'Use this function to visualize charts for ES|QL queries.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
additionalProperties: true,
|
||||
properties: {
|
||||
query: {
|
||||
type: 'string',
|
||||
},
|
||||
intention: {
|
||||
type: 'string',
|
||||
enum: VISUALIZE_ESQL_USER_INTENTIONS,
|
||||
},
|
||||
},
|
||||
required: ['query', 'intention'],
|
||||
} as const,
|
||||
contexts: ['core'],
|
||||
};
|
||||
|
||||
export type VisualizeESQLFunctionArguments = FromSchema<typeof visualizeESQLFunction['parameters']>;
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue