[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.

![Screenshot 2025-06-24 at 2 10
37 PM](https://github.com/user-attachments/assets/f4ea70bd-0675-4d39-b120-123d2185752b)


### 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:
Dennis Tismenko 2025-06-26 09:34:53 -04:00 committed by GitHub
parent 6b452c79ae
commit 37c930a542
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 592 additions and 41 deletions

View file

@ -8,3 +8,4 @@
*/
export const WORKCHAT_APP_ID = 'workchat';
export const ONECHAT_APP_ID = 'onechat';

View file

@ -7,10 +7,16 @@
* 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 OnechatApp = typeof ONECHAT_APP_ID;
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}`;

View file

@ -495,6 +495,14 @@ export const stackManagementSchema: MakeSchemaFrom<UsageStats> = {
type: 'boolean',
_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': {
type: 'keyword',
_meta: { description: 'Non-default value of setting.' },

View file

@ -50,6 +50,8 @@ export interface UsageStats {
'observability:aiAssistantSimulatedFunctionCalling': boolean;
'observability:aiAssistantSearchConnectorIndexPattern': string;
'onechat:mcpServer:enabled': boolean;
'onechat:ui:enabled': boolean;
'onechat:tools:enabled': boolean;
'visualization:heatmap:maxBuckets': number;
'visualization:regionmap:showWarnings': boolean;
'visualization:tileMap:maxPrecision': number;

View file

@ -11039,6 +11039,18 @@
"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": {
"type": "keyword",
"_meta": {

View file

@ -109,6 +109,7 @@
"xpack.observabilityLogsOverview": [
"platform/packages/shared/logs-overview/src/components"
],
"xpack.onechat": ["platform/plugins/shared/onechat"],
"xpack.osquery": [
"platform/plugins/shared/osquery"
],

View file

@ -9,3 +9,13 @@
* UI Setting ID for enabling / disabling the MCP server
*/
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';

View file

@ -7,7 +7,9 @@
export const ONECHAT_FEATURE_ID = '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 = {
show: 'show',

View file

@ -10,7 +10,7 @@
"browser": true,
"configPath": ["xpack", "onechat"],
"requiredPlugins": ["actions", "inference", "features"],
"requiredBundles": [],
"requiredBundles": ["kibanaReact"],
"optionalPlugins": [],
"extraPublicDirs": []
}

View file

@ -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>
);
};

View file

@ -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}
/>
);
};

View file

@ -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);

View file

@ -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]);
};

View file

@ -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 };

View file

@ -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;
};

View file

@ -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 };
};

View file

@ -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';

View file

@ -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);
};
};

View file

@ -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>;
};

View file

@ -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 />;
};

View file

@ -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>
);
};

View file

@ -5,8 +5,21 @@
* 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 { registerApp } from './register';
import {
AgentService,
ChatService,
ConversationsService,
OnechatInternalService,
ToolsService,
} from './services';
import type {
ConfigSchema,
OnechatPluginSetup,
@ -14,13 +27,7 @@ import type {
OnechatSetupDependencies,
OnechatStartDependencies,
} from './types';
import {
AgentService,
ChatService,
ConversationsService,
ToolsService,
OnechatInternalService,
} from './services';
import { ONECHAT_UI_SETTING_ID } from '../common/constants';
export class OnechatPlugin
implements
@ -32,16 +39,25 @@ export class OnechatPlugin
>
{
logger: Logger;
// @ts-expect-error unused for now
private internalServices?: OnechatInternalService;
constructor(context: PluginInitializerContext<ConfigSchema>) {
this.logger = context.logger.get();
}
setup(
coreSetup: CoreSetup<OnechatStartDependencies, OnechatPluginStart>,
pluginsSetup: OnechatSetupDependencies
): OnechatPluginSetup {
setup(core: CoreSetup<OnechatStartDependencies, OnechatPluginStart>): OnechatPluginSetup {
const isOnechatUiEnabled = core.uiSettings.get<boolean>(ONECHAT_UI_SETTING_ID, false);
if (isOnechatUiEnabled) {
registerApp({
core,
getServices: () => {
if (!this.internalServices) {
throw new Error('getServices called before plugin start');
}
return this.internalServices;
},
});
}
return {};
}

View 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 });
},
});
};

View file

@ -5,22 +5,20 @@
* 2.0.
*/
import type { Logger } from '@kbn/logging';
import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/server';
import { i18n } from '@kbn/i18n';
import { schema } from '@kbn/config-schema';
import type { Logger } from '@kbn/logging';
import type { OnechatConfig } from './config';
import { registerFeatures } from './features';
import { registerRoutes } from './routes';
import { ServiceManager } from './services';
import { registerTools } from './tools';
import type {
OnechatPluginSetup,
OnechatPluginStart,
OnechatSetupDependencies,
OnechatStartDependencies,
} from './types';
import { registerRoutes } from './routes';
import { ServiceManager } from './services';
import { registerFeatures } from './features';
import { registerTools } from './tools';
import { ONECHAT_MCP_SERVER_UI_SETTING_ID } from '../common/constants';
import { registerUISettings } from './ui_settings';
export class OnechatPlugin
implements
@ -53,20 +51,7 @@ export class OnechatPlugin
registerTools({ tools: serviceSetups.tools });
coreSetup.uiSettings.register({
[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',
},
});
registerUISettings({ uiSettings: coreSetup.uiSettings });
const router = coreSetup.http.createRouter();
registerRoutes({

View 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',
},
});
};

View file

@ -37,6 +37,15 @@
"@kbn/features-plugin",
"@kbn/core-logging-server-mocks",
"@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"
]
}

View file

@ -30,9 +30,10 @@
"serverless",
"searchHomepage",
"share",
"visualizations"
"visualizations",
],
"optionalPlugins": [
"onechat",
"indexManagement",
"contentConnectors",
"searchInferenceEndpoints",

View file

@ -44,6 +44,20 @@ export const navigationTree = ({ isAppRegistered }: ApplicationStart): Navigatio
{
link: 'discover',
},
{
title: i18n.translate('xpack.serverlessSearch.nav.chat', {
defaultMessage: 'Chat',
}),
renderAs: 'accordion',
children: [
{
link: 'onechat:conversations',
},
{
link: 'onechat:tools',
},
],
},
{
link: 'dashboards',
getIsActive: ({ pathNameSerialized, prepend }) => {