mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[onechat] Add tools page, show registered tools (#224330)
## Summary Implements the tools page in the Onechat UI and retrieves the registered tools from the Kibana API to display a list of all tools and descriptions — descriptions are truncated at the first `\n` character.  ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [ ] ~[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials~ - [ ] ~[Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios~ - [ ] ~If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)~ - [ ] ~This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The `release_note:breaking` label should be applied in these situations.~ - [ ] ~[Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed~ - [ ] ~The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)~ ### Identify risks Does this PR introduce any risks? For example, consider risks like hard to test bugs, performance regression, potential of data loss. __No risks are introduced in this PR.__ --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
6b452c79ae
commit
37c930a542
28 changed files with 592 additions and 41 deletions
|
@ -8,3 +8,4 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const WORKCHAT_APP_ID = 'workchat';
|
export const WORKCHAT_APP_ID = 'workchat';
|
||||||
|
export const ONECHAT_APP_ID = 'onechat';
|
||||||
|
|
|
@ -7,10 +7,16 @@
|
||||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { WORKCHAT_APP_ID } from './constants';
|
import { ONECHAT_APP_ID, WORKCHAT_APP_ID } from './constants';
|
||||||
|
|
||||||
export type WorkchatApp = typeof WORKCHAT_APP_ID;
|
export type WorkchatApp = typeof WORKCHAT_APP_ID;
|
||||||
|
export type OnechatApp = typeof ONECHAT_APP_ID;
|
||||||
|
|
||||||
export type WorkchatLinkId = 'agents' | 'integrations';
|
export type WorkchatLinkId = 'agents' | 'integrations';
|
||||||
|
export type OnechatLinkId = 'conversations' | 'tools';
|
||||||
|
|
||||||
export type DeepLinkId = WorkchatApp | `${WorkchatApp}:${WorkchatLinkId}`;
|
export type DeepLinkId =
|
||||||
|
| WorkchatApp
|
||||||
|
| `${WorkchatApp}:${WorkchatLinkId}`
|
||||||
|
| OnechatApp
|
||||||
|
| `${OnechatApp}:${OnechatLinkId}`;
|
||||||
|
|
|
@ -495,6 +495,14 @@ export const stackManagementSchema: MakeSchemaFrom<UsageStats> = {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
_meta: { description: 'Non-default value of setting.' },
|
_meta: { description: 'Non-default value of setting.' },
|
||||||
},
|
},
|
||||||
|
'onechat:ui:enabled': {
|
||||||
|
type: 'boolean',
|
||||||
|
_meta: { description: 'Non-default value of setting.' },
|
||||||
|
},
|
||||||
|
'onechat:tools:enabled': {
|
||||||
|
type: 'boolean',
|
||||||
|
_meta: { description: 'Non-default value of setting.' },
|
||||||
|
},
|
||||||
'banners:placement': {
|
'banners:placement': {
|
||||||
type: 'keyword',
|
type: 'keyword',
|
||||||
_meta: { description: 'Non-default value of setting.' },
|
_meta: { description: 'Non-default value of setting.' },
|
||||||
|
|
|
@ -50,6 +50,8 @@ export interface UsageStats {
|
||||||
'observability:aiAssistantSimulatedFunctionCalling': boolean;
|
'observability:aiAssistantSimulatedFunctionCalling': boolean;
|
||||||
'observability:aiAssistantSearchConnectorIndexPattern': string;
|
'observability:aiAssistantSearchConnectorIndexPattern': string;
|
||||||
'onechat:mcpServer:enabled': boolean;
|
'onechat:mcpServer:enabled': boolean;
|
||||||
|
'onechat:ui:enabled': boolean;
|
||||||
|
'onechat:tools:enabled': boolean;
|
||||||
'visualization:heatmap:maxBuckets': number;
|
'visualization:heatmap:maxBuckets': number;
|
||||||
'visualization:regionmap:showWarnings': boolean;
|
'visualization:regionmap:showWarnings': boolean;
|
||||||
'visualization:tileMap:maxPrecision': number;
|
'visualization:tileMap:maxPrecision': number;
|
||||||
|
|
|
@ -11039,6 +11039,18 @@
|
||||||
"description": "Non-default value of setting."
|
"description": "Non-default value of setting."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"onechat:ui:enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"_meta": {
|
||||||
|
"description": "Non-default value of setting."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"onechat:tools:enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"_meta": {
|
||||||
|
"description": "Non-default value of setting."
|
||||||
|
}
|
||||||
|
},
|
||||||
"banners:placement": {
|
"banners:placement": {
|
||||||
"type": "keyword",
|
"type": "keyword",
|
||||||
"_meta": {
|
"_meta": {
|
||||||
|
|
|
@ -109,6 +109,7 @@
|
||||||
"xpack.observabilityLogsOverview": [
|
"xpack.observabilityLogsOverview": [
|
||||||
"platform/packages/shared/logs-overview/src/components"
|
"platform/packages/shared/logs-overview/src/components"
|
||||||
],
|
],
|
||||||
|
"xpack.onechat": ["platform/plugins/shared/onechat"],
|
||||||
"xpack.osquery": [
|
"xpack.osquery": [
|
||||||
"platform/plugins/shared/osquery"
|
"platform/plugins/shared/osquery"
|
||||||
],
|
],
|
||||||
|
|
|
@ -9,3 +9,13 @@
|
||||||
* UI Setting ID for enabling / disabling the MCP server
|
* UI Setting ID for enabling / disabling the MCP server
|
||||||
*/
|
*/
|
||||||
export const ONECHAT_MCP_SERVER_UI_SETTING_ID = 'onechat:mcpServer:enabled';
|
export const ONECHAT_MCP_SERVER_UI_SETTING_ID = 'onechat:mcpServer:enabled';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UI Setting ID for enabling / disabling the onechat plugin UI
|
||||||
|
*/
|
||||||
|
export const ONECHAT_UI_SETTING_ID = 'onechat:ui:enabled';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UI Setting ID for enabling / disabling the tools UI
|
||||||
|
*/
|
||||||
|
export const ONECHAT_TOOLS_UI_SETTING_ID = 'onechat:tools:enabled';
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
|
|
||||||
export const ONECHAT_FEATURE_ID = 'onechat';
|
export const ONECHAT_FEATURE_ID = 'onechat';
|
||||||
export const ONECHAT_FEATURE_NAME = 'onechat';
|
export const ONECHAT_FEATURE_NAME = 'onechat';
|
||||||
export const ONECHAT_APP_ID = 'onechat_app';
|
export const ONECHAT_APP_ID = 'onechat';
|
||||||
|
export const ONECHAT_PATH = '/app/chat';
|
||||||
|
export const ONECHAT_TITLE = 'Chat';
|
||||||
|
|
||||||
export const uiPrivileges = {
|
export const uiPrivileges = {
|
||||||
show: 'show',
|
show: 'show',
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"configPath": ["xpack", "onechat"],
|
"configPath": ["xpack", "onechat"],
|
||||||
"requiredPlugins": ["actions", "inference", "features"],
|
"requiredPlugins": ["actions", "inference", "features"],
|
||||||
"requiredBundles": [],
|
"requiredBundles": ["kibanaReact"],
|
||||||
"optionalPlugins": [],
|
"optionalPlugins": [],
|
||||||
"extraPublicDirs": []
|
"extraPublicDirs": []
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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 { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
|
||||||
|
import React from 'react';
|
||||||
|
import { OnechatToolsTable } from './tools_table';
|
||||||
|
export const OnechatTools = () => {
|
||||||
|
return (
|
||||||
|
<KibanaPageTemplate>
|
||||||
|
<KibanaPageTemplate.Header
|
||||||
|
pageTitle={i18n.translate('xpack.onechat.tools.title', {
|
||||||
|
defaultMessage: 'Tools',
|
||||||
|
})}
|
||||||
|
description={i18n.translate('xpack.onechat.tools.toolsDescription', {
|
||||||
|
defaultMessage:
|
||||||
|
'Functionality used to enhance the capabilities of your AI agents in your chat experience by allowing them to perform specific tasks or access additional information.',
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<KibanaPageTemplate.Section>
|
||||||
|
<OnechatToolsTable />
|
||||||
|
</KibanaPageTemplate.Section>
|
||||||
|
</KibanaPageTemplate>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* 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 { EuiBadge, EuiBadgeGroup, EuiBasicTable, EuiBasicTableColumn, EuiText } from '@elastic/eui';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { ToolDescriptor } from '@kbn/onechat-common';
|
||||||
|
import React from 'react';
|
||||||
|
import { useOnechatTools } from '../../hooks/use_tools';
|
||||||
|
|
||||||
|
const parseToolDescription = (description: string): string => {
|
||||||
|
// Truncate at newline
|
||||||
|
const [truncatedDescription] = description.split('\n');
|
||||||
|
return truncatedDescription;
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns: Array<EuiBasicTableColumn<ToolDescriptor>> = [
|
||||||
|
{
|
||||||
|
field: 'id',
|
||||||
|
name: i18n.translate('xpack.onechat.tools.toolIdLabel', { defaultMessage: 'Tool' }),
|
||||||
|
valign: 'top',
|
||||||
|
render: (id: string) => (
|
||||||
|
<EuiText size="s">
|
||||||
|
<strong>{id}</strong>
|
||||||
|
</EuiText>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'description',
|
||||||
|
name: i18n.translate('xpack.onechat.tools.toolDescriptionLabel', {
|
||||||
|
defaultMessage: 'Description',
|
||||||
|
}),
|
||||||
|
width: '60%',
|
||||||
|
valign: 'top',
|
||||||
|
render: (description: string) => {
|
||||||
|
return <EuiText size="s">{parseToolDescription(description)}</EuiText>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'meta.tags',
|
||||||
|
name: i18n.translate('xpack.onechat.tools.tagsLabel', {
|
||||||
|
defaultMessage: 'Tags',
|
||||||
|
}),
|
||||||
|
width: '15%',
|
||||||
|
valign: 'top',
|
||||||
|
render: (tags: string[]) => {
|
||||||
|
return (
|
||||||
|
<EuiBadgeGroup>
|
||||||
|
{tags.map((tag) => (
|
||||||
|
<EuiBadge key={tag} color="primary">
|
||||||
|
{tag}
|
||||||
|
</EuiBadge>
|
||||||
|
))}
|
||||||
|
</EuiBadgeGroup>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const OnechatToolsTable: React.FC = () => {
|
||||||
|
const { tools, isLoading, error } = useOnechatTools();
|
||||||
|
const errorMessage = error
|
||||||
|
? i18n.translate('xpack.onechat.tools.listToolsErrorMessage', {
|
||||||
|
defaultMessage: 'Failed to fetch tools',
|
||||||
|
})
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EuiBasicTable
|
||||||
|
loading={isLoading}
|
||||||
|
columns={columns}
|
||||||
|
items={tools}
|
||||||
|
itemId="id"
|
||||||
|
noItemsMessage={i18n.translate('xpack.onechat.tools.noToolsMessage', {
|
||||||
|
defaultMessage: 'No tools found',
|
||||||
|
})}
|
||||||
|
error={errorMessage}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
|
@ -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 { createContext } from 'react';
|
||||||
|
import { OnechatInternalService } from '../../services';
|
||||||
|
|
||||||
|
export const OnechatServicesContext = createContext<OnechatInternalService | undefined>(undefined);
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* 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 { useEffect, useMemo, useCallback } from 'react';
|
||||||
|
import type { ChromeBreadcrumb } from '@kbn/core/public';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { ONECHAT_APP_ID } from '../../../common/features';
|
||||||
|
import { useKibana } from './use_kibana';
|
||||||
|
|
||||||
|
interface OnechatBreadcrumb {
|
||||||
|
text: string;
|
||||||
|
path?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useBreadcrumb = (breadcrumbs: OnechatBreadcrumb[]) => {
|
||||||
|
const {
|
||||||
|
services: { chrome, application },
|
||||||
|
} = useKibana();
|
||||||
|
|
||||||
|
const getUrl = useCallback(
|
||||||
|
(path: string) => {
|
||||||
|
return application.getUrlForApp(ONECHAT_APP_ID, { path });
|
||||||
|
},
|
||||||
|
[application]
|
||||||
|
);
|
||||||
|
|
||||||
|
const appUrl = useMemo(() => {
|
||||||
|
return getUrl('');
|
||||||
|
}, [getUrl]);
|
||||||
|
|
||||||
|
const baseCrumbs: ChromeBreadcrumb[] = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: i18n.translate('xpack.onechat.breadcrumb.onechat', {
|
||||||
|
defaultMessage: 'OneChat',
|
||||||
|
}),
|
||||||
|
href: appUrl,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}, [appUrl]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const additionalCrumbs = breadcrumbs.map<ChromeBreadcrumb>((crumb) => {
|
||||||
|
return {
|
||||||
|
text: crumb.text,
|
||||||
|
href: crumb.path ? getUrl(crumb.path) : undefined,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
chrome.setBreadcrumbs([...baseCrumbs, ...additionalCrumbs], {
|
||||||
|
project: { value: additionalCrumbs.length ? additionalCrumbs : baseCrumbs, absolute: true },
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
chrome.setBreadcrumbs([]);
|
||||||
|
};
|
||||||
|
}, [chrome, baseCrumbs, breadcrumbs, getUrl]);
|
||||||
|
};
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* 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 { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||||
|
import type { CoreStart } from '@kbn/core/public';
|
||||||
|
import type { OnechatStartDependencies } from '../../types';
|
||||||
|
|
||||||
|
export type StartServices = CoreStart & {
|
||||||
|
plugins: OnechatStartDependencies;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useTypedKibana = () => useKibana<StartServices>();
|
||||||
|
|
||||||
|
export { useTypedKibana as useKibana };
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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 { useContext } from 'react';
|
||||||
|
import { OnechatServicesContext } from '../context/onechat_services_context';
|
||||||
|
|
||||||
|
export const useOnechatServices = () => {
|
||||||
|
const services = useContext(OnechatServicesContext);
|
||||||
|
if (services === undefined) {
|
||||||
|
throw new Error(
|
||||||
|
`OnechatServicesContext not set. Did you wrap your component in <OnechatServicesContext.Provider> ?`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return services;
|
||||||
|
};
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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 { useQuery } from '@tanstack/react-query';
|
||||||
|
import { useOnechatServices } from './use_onechat_service';
|
||||||
|
|
||||||
|
export const useOnechatTools = () => {
|
||||||
|
const { toolsService } = useOnechatServices();
|
||||||
|
|
||||||
|
const { data, isLoading, error } = useQuery({
|
||||||
|
queryKey: ['tools', 'list'],
|
||||||
|
queryFn: () => toolsService.list(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return { tools: data?.tools ?? [], isLoading, error };
|
||||||
|
};
|
|
@ -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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { mountApp } from './mount';
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* 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 { CoreStart, ScopedHistory } from '@kbn/core/public';
|
||||||
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
|
||||||
|
import { I18nProvider } from '@kbn/i18n-react';
|
||||||
|
import { Router } from '@kbn/shared-ux-router';
|
||||||
|
import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
|
||||||
|
import { OnechatRoutes } from './routes';
|
||||||
|
import type { OnechatInternalService } from '../services';
|
||||||
|
import { OnechatStartDependencies } from '../types';
|
||||||
|
import { OnechatServicesContext } from './context/onechat_services_context';
|
||||||
|
|
||||||
|
export const mountApp = async ({
|
||||||
|
core,
|
||||||
|
plugins,
|
||||||
|
element,
|
||||||
|
history,
|
||||||
|
services,
|
||||||
|
}: {
|
||||||
|
core: CoreStart;
|
||||||
|
plugins: OnechatStartDependencies;
|
||||||
|
element: HTMLElement;
|
||||||
|
history: ScopedHistory;
|
||||||
|
services: OnechatInternalService;
|
||||||
|
}) => {
|
||||||
|
const kibanaServices = { ...core, plugins };
|
||||||
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
core.rendering.addContext(
|
||||||
|
<KibanaContextProvider services={kibanaServices}>
|
||||||
|
<I18nProvider>
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
|
<OnechatServicesContext.Provider value={services}>
|
||||||
|
<RedirectAppLinks coreStart={core}>
|
||||||
|
<Router history={history}>
|
||||||
|
<OnechatRoutes />
|
||||||
|
</Router>
|
||||||
|
</RedirectAppLinks>
|
||||||
|
</OnechatServicesContext.Provider>
|
||||||
|
</QueryClientProvider>
|
||||||
|
</I18nProvider>
|
||||||
|
</KibanaContextProvider>
|
||||||
|
),
|
||||||
|
element
|
||||||
|
);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
ReactDOM.unmountComponentAtNode(element);
|
||||||
|
};
|
||||||
|
};
|
|
@ -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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export const OnechatConversationsPage = () => {
|
||||||
|
return <div>OnechatConversationsPage</div>;
|
||||||
|
};
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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 React from 'react';
|
||||||
|
import { OnechatTools } from '../components/tools/tools';
|
||||||
|
import { useBreadcrumb } from '../hooks/use_breadcrumbs';
|
||||||
|
|
||||||
|
export const OnechatToolsPage = () => {
|
||||||
|
useBreadcrumb([
|
||||||
|
{ text: i18n.translate('xpack.onechat.chat.title', { defaultMessage: 'Chat' }) },
|
||||||
|
{ text: i18n.translate('xpack.onechat.tools.title', { defaultMessage: 'Tools' }) },
|
||||||
|
]);
|
||||||
|
return <OnechatTools />;
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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 { Routes, Route } from '@kbn/shared-ux-router';
|
||||||
|
import React from 'react';
|
||||||
|
import { useUiSetting } from '@kbn/kibana-react-plugin/public';
|
||||||
|
import { OnechatToolsPage } from './pages/tools';
|
||||||
|
import { OnechatConversationsPage } from './pages/chat';
|
||||||
|
import { ONECHAT_TOOLS_UI_SETTING_ID } from '../../common/constants';
|
||||||
|
|
||||||
|
export const OnechatRoutes: React.FC<{}> = () => {
|
||||||
|
const isToolsPageEnabled = useUiSetting<boolean>(ONECHAT_TOOLS_UI_SETTING_ID, false);
|
||||||
|
return (
|
||||||
|
<Routes>
|
||||||
|
<Route path="/conversations">
|
||||||
|
<OnechatConversationsPage />
|
||||||
|
</Route>
|
||||||
|
{isToolsPageEnabled && (
|
||||||
|
<Route path="/tools">
|
||||||
|
<OnechatToolsPage />
|
||||||
|
</Route>
|
||||||
|
)}
|
||||||
|
</Routes>
|
||||||
|
);
|
||||||
|
};
|
|
@ -5,8 +5,21 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public';
|
import {
|
||||||
|
type CoreSetup,
|
||||||
|
type CoreStart,
|
||||||
|
type Plugin,
|
||||||
|
type PluginInitializerContext,
|
||||||
|
} from '@kbn/core/public';
|
||||||
import type { Logger } from '@kbn/logging';
|
import type { Logger } from '@kbn/logging';
|
||||||
|
import { registerApp } from './register';
|
||||||
|
import {
|
||||||
|
AgentService,
|
||||||
|
ChatService,
|
||||||
|
ConversationsService,
|
||||||
|
OnechatInternalService,
|
||||||
|
ToolsService,
|
||||||
|
} from './services';
|
||||||
import type {
|
import type {
|
||||||
ConfigSchema,
|
ConfigSchema,
|
||||||
OnechatPluginSetup,
|
OnechatPluginSetup,
|
||||||
|
@ -14,13 +27,7 @@ import type {
|
||||||
OnechatSetupDependencies,
|
OnechatSetupDependencies,
|
||||||
OnechatStartDependencies,
|
OnechatStartDependencies,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {
|
import { ONECHAT_UI_SETTING_ID } from '../common/constants';
|
||||||
AgentService,
|
|
||||||
ChatService,
|
|
||||||
ConversationsService,
|
|
||||||
ToolsService,
|
|
||||||
OnechatInternalService,
|
|
||||||
} from './services';
|
|
||||||
|
|
||||||
export class OnechatPlugin
|
export class OnechatPlugin
|
||||||
implements
|
implements
|
||||||
|
@ -32,16 +39,25 @@ export class OnechatPlugin
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
// @ts-expect-error unused for now
|
|
||||||
private internalServices?: OnechatInternalService;
|
private internalServices?: OnechatInternalService;
|
||||||
|
|
||||||
constructor(context: PluginInitializerContext<ConfigSchema>) {
|
constructor(context: PluginInitializerContext<ConfigSchema>) {
|
||||||
this.logger = context.logger.get();
|
this.logger = context.logger.get();
|
||||||
}
|
}
|
||||||
setup(
|
setup(core: CoreSetup<OnechatStartDependencies, OnechatPluginStart>): OnechatPluginSetup {
|
||||||
coreSetup: CoreSetup<OnechatStartDependencies, OnechatPluginStart>,
|
const isOnechatUiEnabled = core.uiSettings.get<boolean>(ONECHAT_UI_SETTING_ID, false);
|
||||||
pluginsSetup: OnechatSetupDependencies
|
|
||||||
): OnechatPluginSetup {
|
if (isOnechatUiEnabled) {
|
||||||
|
registerApp({
|
||||||
|
core,
|
||||||
|
getServices: () => {
|
||||||
|
if (!this.internalServices) {
|
||||||
|
throw new Error('getServices called before plugin start');
|
||||||
|
}
|
||||||
|
return this.internalServices;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
60
x-pack/platform/plugins/shared/onechat/public/register.ts
Normal file
60
x-pack/platform/plugins/shared/onechat/public/register.ts
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
|
* 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { CoreSetup } from '@kbn/core-lifecycle-browser';
|
||||||
|
import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common';
|
||||||
|
import { AppMountParameters } from '@kbn/core-application-browser';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { OnechatInternalService } from './services';
|
||||||
|
import { OnechatPluginStart } from './types';
|
||||||
|
import { ONECHAT_APP_ID, ONECHAT_PATH, ONECHAT_TITLE } from '../common/features';
|
||||||
|
import { ONECHAT_TOOLS_UI_SETTING_ID } from '../common/constants';
|
||||||
|
|
||||||
|
export const registerApp = ({
|
||||||
|
core,
|
||||||
|
getServices,
|
||||||
|
}: {
|
||||||
|
core: CoreSetup<OnechatPluginStart>;
|
||||||
|
getServices: () => OnechatInternalService;
|
||||||
|
}) => {
|
||||||
|
const isToolsPageEnabled = core.uiSettings.get<boolean>(ONECHAT_TOOLS_UI_SETTING_ID, false);
|
||||||
|
core.application.register({
|
||||||
|
id: ONECHAT_APP_ID,
|
||||||
|
appRoute: ONECHAT_PATH,
|
||||||
|
category: DEFAULT_APP_CATEGORIES.chat,
|
||||||
|
title: ONECHAT_TITLE,
|
||||||
|
euiIconType: 'logoElasticsearch',
|
||||||
|
visibleIn: ['sideNav', 'globalSearch'],
|
||||||
|
deepLinks: [
|
||||||
|
{
|
||||||
|
id: 'conversations',
|
||||||
|
path: '/conversations',
|
||||||
|
title: i18n.translate('xpack.onechat.chat.conversationsTitle', {
|
||||||
|
defaultMessage: 'Conversations',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
...(isToolsPageEnabled
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
id: 'tools',
|
||||||
|
path: '/tools',
|
||||||
|
title: i18n.translate('xpack.onechat.tools.title', { defaultMessage: 'Tools' }),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
],
|
||||||
|
async mount({ element, history }: AppMountParameters) {
|
||||||
|
const { mountApp } = await import('./application');
|
||||||
|
const [coreStart, startPluginDeps] = await core.getStartServices();
|
||||||
|
|
||||||
|
coreStart.chrome.docTitle.change(ONECHAT_TITLE);
|
||||||
|
const services = getServices();
|
||||||
|
|
||||||
|
return mountApp({ core: coreStart, services, element, history, plugins: startPluginDeps });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
|
@ -5,22 +5,20 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Logger } from '@kbn/logging';
|
|
||||||
import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/server';
|
import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/server';
|
||||||
import { i18n } from '@kbn/i18n';
|
import type { Logger } from '@kbn/logging';
|
||||||
import { schema } from '@kbn/config-schema';
|
|
||||||
import type { OnechatConfig } from './config';
|
import type { OnechatConfig } from './config';
|
||||||
|
import { registerFeatures } from './features';
|
||||||
|
import { registerRoutes } from './routes';
|
||||||
|
import { ServiceManager } from './services';
|
||||||
|
import { registerTools } from './tools';
|
||||||
import type {
|
import type {
|
||||||
OnechatPluginSetup,
|
OnechatPluginSetup,
|
||||||
OnechatPluginStart,
|
OnechatPluginStart,
|
||||||
OnechatSetupDependencies,
|
OnechatSetupDependencies,
|
||||||
OnechatStartDependencies,
|
OnechatStartDependencies,
|
||||||
} from './types';
|
} from './types';
|
||||||
import { registerRoutes } from './routes';
|
import { registerUISettings } from './ui_settings';
|
||||||
import { ServiceManager } from './services';
|
|
||||||
import { registerFeatures } from './features';
|
|
||||||
import { registerTools } from './tools';
|
|
||||||
import { ONECHAT_MCP_SERVER_UI_SETTING_ID } from '../common/constants';
|
|
||||||
|
|
||||||
export class OnechatPlugin
|
export class OnechatPlugin
|
||||||
implements
|
implements
|
||||||
|
@ -53,20 +51,7 @@ export class OnechatPlugin
|
||||||
|
|
||||||
registerTools({ tools: serviceSetups.tools });
|
registerTools({ tools: serviceSetups.tools });
|
||||||
|
|
||||||
coreSetup.uiSettings.register({
|
registerUISettings({ uiSettings: coreSetup.uiSettings });
|
||||||
[ONECHAT_MCP_SERVER_UI_SETTING_ID]: {
|
|
||||||
description: i18n.translate('onechat.uiSettings.mcpServer.description', {
|
|
||||||
defaultMessage: 'Enables MCP server with access to tools.',
|
|
||||||
}),
|
|
||||||
name: i18n.translate('onechat.uiSettings.mcpServer.name', {
|
|
||||||
defaultMessage: 'MCP Server',
|
|
||||||
}),
|
|
||||||
schema: schema.boolean(),
|
|
||||||
value: false,
|
|
||||||
readonly: true,
|
|
||||||
readonlyMode: 'ui',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const router = coreSetup.http.createRouter();
|
const router = coreSetup.http.createRouter();
|
||||||
registerRoutes({
|
registerRoutes({
|
||||||
|
|
56
x-pack/platform/plugins/shared/onechat/server/ui_settings.ts
Normal file
56
x-pack/platform/plugins/shared/onechat/server/ui_settings.ts
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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 { schema } from '@kbn/config-schema';
|
||||||
|
import { UiSettingsServiceSetup } from '@kbn/core-ui-settings-server';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import {
|
||||||
|
ONECHAT_UI_SETTING_ID,
|
||||||
|
ONECHAT_MCP_SERVER_UI_SETTING_ID,
|
||||||
|
ONECHAT_TOOLS_UI_SETTING_ID,
|
||||||
|
} from '../common/constants';
|
||||||
|
|
||||||
|
export const registerUISettings = ({ uiSettings }: { uiSettings: UiSettingsServiceSetup }) => {
|
||||||
|
uiSettings.register({
|
||||||
|
[ONECHAT_MCP_SERVER_UI_SETTING_ID]: {
|
||||||
|
description: i18n.translate('xpack.onechat.uiSettings.mcpServer.description', {
|
||||||
|
defaultMessage: 'Enables MCP server with access to tools.',
|
||||||
|
}),
|
||||||
|
name: i18n.translate('xpack.onechat.uiSettings.mcpServer.name', {
|
||||||
|
defaultMessage: 'MCP Server',
|
||||||
|
}),
|
||||||
|
schema: schema.boolean(),
|
||||||
|
value: false,
|
||||||
|
readonly: true,
|
||||||
|
readonlyMode: 'ui',
|
||||||
|
},
|
||||||
|
[ONECHAT_UI_SETTING_ID]: {
|
||||||
|
description: i18n.translate('xpack.onechat.uiSettings.chatUI.description', {
|
||||||
|
defaultMessage: 'Enables the OneChat chat UI.',
|
||||||
|
}),
|
||||||
|
name: i18n.translate('xpack.onechat.uiSettings.chatUI.name', {
|
||||||
|
defaultMessage: 'OneChat Chat UI',
|
||||||
|
}),
|
||||||
|
schema: schema.boolean(),
|
||||||
|
value: false,
|
||||||
|
readonly: true,
|
||||||
|
readonlyMode: 'ui',
|
||||||
|
},
|
||||||
|
[ONECHAT_TOOLS_UI_SETTING_ID]: {
|
||||||
|
description: i18n.translate('xpack.onechat.uiSettings.toolsPage.description', {
|
||||||
|
defaultMessage: 'Enables the OneChat tools page.',
|
||||||
|
}),
|
||||||
|
name: i18n.translate('xpack.onechat.uiSettings.toolsPage.name', {
|
||||||
|
defaultMessage: 'OneChat Tools Page',
|
||||||
|
}),
|
||||||
|
schema: schema.boolean(),
|
||||||
|
value: false,
|
||||||
|
readonly: true,
|
||||||
|
readonlyMode: 'ui',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
|
@ -37,6 +37,15 @@
|
||||||
"@kbn/features-plugin",
|
"@kbn/features-plugin",
|
||||||
"@kbn/core-logging-server-mocks",
|
"@kbn/core-logging-server-mocks",
|
||||||
"@kbn/i18n",
|
"@kbn/i18n",
|
||||||
"@kbn/onechat-genai-utils"
|
"@kbn/onechat-genai-utils",
|
||||||
|
"@kbn/shared-ux-page-kibana-template",
|
||||||
|
"@kbn/kibana-react-plugin",
|
||||||
|
"@kbn/i18n-react",
|
||||||
|
"@kbn/shared-ux-router",
|
||||||
|
"@kbn/shared-ux-link-redirect-app",
|
||||||
|
"@kbn/core-lifecycle-browser",
|
||||||
|
"@kbn/core-application-common",
|
||||||
|
"@kbn/core-application-browser",
|
||||||
|
"@kbn/core-ui-settings-server"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,10 @@
|
||||||
"serverless",
|
"serverless",
|
||||||
"searchHomepage",
|
"searchHomepage",
|
||||||
"share",
|
"share",
|
||||||
"visualizations"
|
"visualizations",
|
||||||
],
|
],
|
||||||
"optionalPlugins": [
|
"optionalPlugins": [
|
||||||
|
"onechat",
|
||||||
"indexManagement",
|
"indexManagement",
|
||||||
"contentConnectors",
|
"contentConnectors",
|
||||||
"searchInferenceEndpoints",
|
"searchInferenceEndpoints",
|
||||||
|
|
|
@ -44,6 +44,20 @@ export const navigationTree = ({ isAppRegistered }: ApplicationStart): Navigatio
|
||||||
{
|
{
|
||||||
link: 'discover',
|
link: 'discover',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: i18n.translate('xpack.serverlessSearch.nav.chat', {
|
||||||
|
defaultMessage: 'Chat',
|
||||||
|
}),
|
||||||
|
renderAs: 'accordion',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
link: 'onechat:conversations',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
link: 'onechat:tools',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
link: 'dashboards',
|
link: 'dashboards',
|
||||||
getIsActive: ({ pathNameSerialized, prepend }) => {
|
getIsActive: ({ pathNameSerialized, prepend }) => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue