Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[securityAssistant] LangGraph ES|QL query generation tool #186489

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
0b03e98
Migrates to LangSmith and adds KB Tools
spong May 30, 2024
b888052
Merge branch 'main' of github.com:elastic/kibana into kb-tools
spong May 30, 2024
de9d530
yarn.lock update
spong May 31, 2024
b862a29
Port title generation into langgraph node
spong May 31, 2024
0b0bdab
Merge branch 'main' of github.com:elastic/kibana into kb-tools
spong Jun 3, 2024
6451142
yarn.lock update
spong Jun 3, 2024
14b0c65
Primes initial context with required kb docs and updates kb retrieval…
spong Jun 4, 2024
62754d3
Merge branch 'main' of github.com:elastic/kibana into kb-tools
spong Jun 4, 2024
83cdc37
Remove chat title generation node
spong Jun 4, 2024
b04da0e
yarn.lock update
spong Jun 4, 2024
c564e2e
Merge branch 'main' into kb-tools
spong Jun 4, 2024
5bc866b
yarn.lock update2
spong Jun 4, 2024
8477e13
fix types
patrykkopycinski Jun 4, 2024
9875273
Bump
patrykkopycinski Jun 6, 2024
bfee899
Merge branch 'kb-tools' of github.com:spong/kibana into feat/esql-lan…
patrykkopycinski Jun 6, 2024
5ba88d8
WIP
patrykkopycinski Jun 10, 2024
80698c0
Merge branch 'main' of github.com:elastic/kibana into feat/esql-langg…
patrykkopycinski Jun 10, 2024
ae32a5d
Merge branch 'main' of github.com:elastic/kibana into feat/esql-langg…
patrykkopycinski Jun 10, 2024
aa97cc0
WIP
patrykkopycinski Jun 14, 2024
799fcf5
Merge branch 'main' of github.com:elastic/kibana into feat/esql-langg…
patrykkopycinski Jun 19, 2024
22d4952
Merge branch 'main' of github.com:elastic/kibana into feat/esql-langg…
patrykkopycinski Jun 19, 2024
825afe3
add cases
patrykkopycinski Jun 19, 2024
6468286
cleanup
patrykkopycinski Jun 20, 2024
fc6404d
Merge branch 'main' of github.com:elastic/kibana into feat/esql-langg…
patrykkopycinski Jun 22, 2024
5421b42
WIP
patrykkopycinski Jun 23, 2024
2e88bfe
cleanup
patrykkopycinski Jun 24, 2024
48259c9
fix
patrykkopycinski Jun 24, 2024
a46732b
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Jun 24, 2024
04140f9
cleanup
patrykkopycinski Jun 24, 2024
234dedd
Merge branch 'feat/esql-langgraph' of github.com:patrykkopycinski/kib…
patrykkopycinski Jun 24, 2024
55bd7c5
fix
patrykkopycinski Jun 24, 2024
5b1a8db
fix
patrykkopycinski Jun 24, 2024
3878d63
Merge branch 'main' of github.com:elastic/kibana into feat/esql-langg…
patrykkopycinski Jun 26, 2024
652891a
fix
patrykkopycinski Jun 26, 2024
36a6834
Merge branch 'main' of github.com:elastic/kibana into feat/esql-langg…
patrykkopycinski Jun 26, 2024
f70dbf3
fix
patrykkopycinski Jun 26, 2024
c4a5804
fix
patrykkopycinski Jun 26, 2024
af26d67
fix
patrykkopycinski Jun 26, 2024
2ff191f
fix
patrykkopycinski Jun 26, 2024
d0b1ac7
fix
patrykkopycinski Jun 26, 2024
c075b4a
fix
patrykkopycinski Jun 26, 2024
1e65fbf
cleanup
patrykkopycinski Jun 26, 2024
3ae0385
fix
patrykkopycinski Jun 27, 2024
77073b2
fix
patrykkopycinski Jun 27, 2024
8f1e362
fix
patrykkopycinski Jun 27, 2024
d70622f
fix
patrykkopycinski Jun 27, 2024
d4d7063
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Jun 27, 2024
1b12104
fix
patrykkopycinski Jun 28, 2024
4c99f31
Merge branch 'main' into feat/esql-langgraph
patrykkopycinski Jun 28, 2024
fa2e5e7
Merge branch 'feat/esql-langgraph' of github.com:patrykkopycinski/kib…
patrykkopycinski Jun 28, 2024
3dd6812
bump elser memory
patrykkopycinski Jun 28, 2024
a1e8dcc
Fix lint
peluja1012 Jun 28, 2024
4a8e974
rely on knowledgebase
patrykkopycinski Jun 28, 2024
dc309da
Merge branch 'feat/esql-langgraph' of github.com:patrykkopycinski/kib…
patrykkopycinski Jun 28, 2024
60c07df
fix
patrykkopycinski Jun 29, 2024
afff8e7
test
patrykkopycinski Jun 29, 2024
36646db
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Jun 29, 2024
90f1991
bump
patrykkopycinski Jun 30, 2024
e04f80b
Merge branch 'main' of github.com:elastic/kibana into feat/esql-langg…
patrykkopycinski Jun 30, 2024
a2a829f
add KB retriever
patrykkopycinski Jul 1, 2024
aa7ff2b
fix system message
patrykkopycinski Jul 1, 2024
c4d85dc
cleanup
patrykkopycinski Jul 1, 2024
b4a1168
i18n
patrykkopycinski Jul 1, 2024
53b998a
fix types
patrykkopycinski Jul 1, 2024
9bcdf68
Merge branch 'main' of github.com:elastic/kibana into feat/esql-langg…
patrykkopycinski Jul 2, 2024
45e586b
Up ML node memory for ci-cloud-deploy, and enable assistantKnowledgeB…
spong Jul 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .buildkite/scripts/steps/cloud/deploy.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
],
"id": "ml",
"size": {
"value": 1024,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

afaik, this is no longer needed, with the autoscaling we have in place

"value": 4096,
"resource": "memory"
}
}
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,14 @@
"resolutions": {
"**/@bazel/typescript/protobufjs": "6.11.4",
"**/@hello-pangea/dnd": "16.6.0",
"**/@langchain/core": "0.2.3",
"**/@types/node": "20.10.5",
"**/@typescript-eslint/utils": "5.62.0",
"**/chokidar": "^3.5.3",
"**/d3-scale/**/d3-color": "npm:@elastic/kibana-d3-color@2.0.1",
"**/globule/minimatch": "^3.1.2",
"**/hoist-non-react-statics": "^3.3.2",
"**/isomorphic-fetch/node-fetch": "^2.6.7",
"**/langchain": "0.2.8",
"**/react-intl/**/@types/react": "^17.0.45",
"**/remark-parse/trim": "1.0.1",
"**/sharp": "0.32.6",
Expand Down Expand Up @@ -932,10 +932,10 @@
"@kbn/watcher-plugin": "link:x-pack/plugins/watcher",
"@kbn/xstate-utils": "link:packages/kbn-xstate-utils",
"@kbn/zod-helpers": "link:packages/kbn-zod-helpers",
"@langchain/community": "^0.2.4",
"@langchain/core": "0.2.3",
"@langchain/langgraph": "^0.0.23",
"@langchain/openai": "^0.0.34",
"@langchain/community": "^0.2.16",
"@langchain/core": "^0.2.11",
"@langchain/langgraph": "^0.0.25",
"@langchain/openai": "^0.1.3",
"@langtrase/trace-attributes": "^3.0.8",
"@launchdarkly/node-server-sdk": "^9.4.6",
"@loaders.gl/core": "^3.4.7",
Expand Down Expand Up @@ -1072,7 +1072,7 @@
"jsonwebtoken": "^9.0.2",
"jsts": "^1.6.2",
"kea": "^2.6.0",
"langchain": "0.2.3",
"langchain": "^0.2.8",
"langsmith": "^0.1.30",
"launchdarkly-js-client-sdk": "^3.4.0",
"launchdarkly-node-server-sdk": "^7.0.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
*/

import React, { useCallback, useEffect, useRef, useState } from 'react';
import { EuiModal, EuiFlyoutResizable, useEuiTheme } from '@elastic/eui';

import { EuiModal, EuiFlyoutResizable } from '@elastic/eui';
import useEvent from 'react-use/lib/useEvent';
// eslint-disable-next-line @kbn/eslint/module_migration
import styled from 'styled-components';
import styled, { createGlobalStyle } from 'styled-components';
import { css } from '@emotion/react';
import {
ShowAssistantOverlayProps,
Expand All @@ -37,8 +36,13 @@ export interface Props {
currentUserAvatar?: UserAvatar;
}

export const UnifiedTimelineGlobalStyles = createGlobalStyle`
body:has(.timeline-portal-overlay-mask) .euiOverlayMask {
z-index: 1003 !important;
}
`;

export const AssistantOverlay = React.memo<Props>(({ isFlyoutMode, currentUserAvatar }) => {
const { euiTheme } = useEuiTheme();
const [isModalVisible, setIsModalVisible] = useState(false);
const [conversationTitle, setConversationTitle] = useState<string | undefined>(
WELCOME_CONVERSATION_TITLE
Expand Down Expand Up @@ -132,32 +136,33 @@ export const AssistantOverlay = React.memo<Props>(({ isFlyoutMode, currentUserAv

if (isFlyoutMode) {
return (
<EuiFlyoutResizable
ref={flyoutRef}
css={css`
max-inline-size: calc(100% - 20px);
min-inline-size: 400px;
> div {
height: 100%;
}
`}
onClose={handleCloseModal}
data-test-subj="ai-assistant-flyout"
paddingSize="none"
hideCloseButton
// EUI TODO: This z-index override of EuiOverlayMask is a workaround, and ideally should be resolved with a cleaner UI/UX flow long-term
maskProps={{ style: `z-index: ${(euiTheme.levels.flyout as number) + 3}` }} // we need this flyout to be above the timeline flyout (which has a z-index of 1002)
>
<Assistant
conversationTitle={conversationTitle}
promptContextId={promptContextId}
onCloseFlyout={handleCloseModal}
isFlyoutMode={isFlyoutMode}
chatHistoryVisible={chatHistoryVisible}
setChatHistoryVisible={toggleChatHistory}
currentUserAvatar={currentUserAvatar}
/>
</EuiFlyoutResizable>
<>
<EuiFlyoutResizable
ref={flyoutRef}
css={css`
max-inline-size: calc(100% - 20px);
min-inline-size: 400px;
> div {
height: 100%;
}
`}
onClose={handleCloseModal}
data-test-subj="ai-assistant-flyout"
paddingSize="none"
hideCloseButton
>
<Assistant
conversationTitle={conversationTitle}
promptContextId={promptContextId}
onCloseFlyout={handleCloseModal}
isFlyoutMode={isFlyoutMode}
chatHistoryVisible={chatHistoryVisible}
setChatHistoryVisible={toggleChatHistory}
currentUserAvatar={currentUserAvatar}
/>
</EuiFlyoutResizable>
<UnifiedTimelineGlobalStyles />
</>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -519,14 +519,6 @@ const AssistantComponent: React.FC<Props> = ({
isFetchedAnonymizationFields,
]);

useEffect(() => {}, [
areConnectorsFetched,
connectors,
conversationsLoaded,
currentConversation,
isLoading,
]);

const createCodeBlockPortals = useCallback(
() =>
messageCodeBlocks?.map((codeBlocks: CodeBlockDetails[], i: number) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ describe('useConversation helpers', () => {

describe('analyzeMarkdown', () => {
it('should identify dsl Query successfully.', () => {
const result = analyzeMarkdown(markDownWithDSLQuery);
const result = analyzeMarkdown(markDownWithDSLQuery, new Date().toISOString());
expect(result[0].type).toBe('dsl');
});
it('should identify kql Query successfully.', () => {
const result = analyzeMarkdown(markDownWithKQLQuery);
const result = analyzeMarkdown(markDownWithKQLQuery, new Date().toISOString());
expect(result[0].type).toBe('kql');
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { getGenAiConfig } from '../../connectorland/helpers';
export interface CodeBlockDetails {
type: QueryType;
content: string;
timestamp: string;
start: number;
end: number;
getControlContainer?: () => Element | undefined;
Expand All @@ -22,6 +23,20 @@ export interface CodeBlockDetails {

export type QueryType = 'eql' | 'esql' | 'kql' | 'dsl' | 'json' | 'no-type' | 'sql';

// If your codeblocks aren't getting tagged with the right language, add keywords to the array.
export const MARKDOWN_TYPES = {
eql: ['Event Query Language', 'EQL sequence query', 'EQL'],
esql: ['Elasticsearch Query Language', 'ESQL', 'ES|QL', 'SQL'],
kql: ['Kibana Query Language', 'KQL Query', 'KQL'],
dsl: [
'Elasticsearch QueryDSL',
'Elasticsearch Query DSL',
'Elasticsearch DSL',
'Query DSL',
'DSL',
],
};

/**
* `analyzeMarkdown` is a helper that enriches content returned from a query
* with action buttons
Expand All @@ -31,29 +46,16 @@ export type QueryType = 'eql' | 'esql' | 'kql' | 'dsl' | 'json' | 'no-type' | 's
*
* @param markdown
*/
export const analyzeMarkdown = (markdown: string): CodeBlockDetails[] => {
export const analyzeMarkdown = (markdown: string, timestamp: string): CodeBlockDetails[] => {
const codeBlockRegex = /```(\w+)?\s([\s\S]*?)```/g;
const matches = [...markdown.matchAll(codeBlockRegex)];
// If your codeblocks aren't getting tagged with the right language, add keywords to the array.
const types = {
eql: ['Event Query Language', 'EQL sequence query', 'EQL'],
esql: ['Elasticsearch Query Language', 'ESQL', 'ES|QL', 'SQL'],
kql: ['Kibana Query Language', 'KQL Query', 'KQL'],
dsl: [
'Elasticsearch QueryDSL',
'Elasticsearch Query DSL',
'Elasticsearch DSL',
'Query DSL',
'DSL',
],
};

const result: CodeBlockDetails[] = matches.map((match) => {
let type = match[1] || 'no-type';
if (type === 'no-type' || type === 'json') {
const start = match.index || 0;
const precedingText = markdown.slice(0, start);
for (const [typeKey, keywords] of Object.entries(types)) {
for (const [typeKey, keywords] of Object.entries(MARKDOWN_TYPES)) {
if (keywords.some((kw) => precedingText.toLowerCase().includes(kw.toLowerCase()))) {
type = typeKey;
break;
Expand All @@ -64,7 +66,7 @@ export const analyzeMarkdown = (markdown: string): CodeBlockDetails[] => {
const content = match[2].trim();
const start = match.index || 0;
const end = start + match[0].length;
return { type: type as QueryType, content, start, end };
return { type: type as QueryType, content, start, end, timestamp };
});

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface InvokeAIActionParamsSchema {
function_call?: {
arguments: string;
name: string;
};
} | null;
tool_calls?: Array<{
id: string;

Expand Down
11 changes: 9 additions & 2 deletions x-pack/plugins/cases/public/components/__mock__/timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@ const mockTimelineComponent = (name: string) => <span data-test-subj={name}>{nam

export const timelineIntegrationMock = {
editor_plugins: {
parsingPlugin: jest.fn(),
processingPluginRenderer: () => mockTimelineComponent('plugin-renderer'),
parsingPlugins: {
timeline: jest.fn(),
customCodeBlock: jest.fn(),
},
processingPluginRenderer: {
timeline: () => mockTimelineComponent('plugin-renderer'),
esql: () => mockTimelineComponent('esql-plugin-renderer'),
customCodeBlock: () => mockTimelineComponent('custom-code-block-plugin-renderer'),
},
uiPlugin: {
name: 'mock-timeline',
button: { label: 'mock-timeline-button', iconType: 'mock-timeline-icon' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ const MarkdownEditorComponent = forwardRef<MarkdownEditorRef, MarkdownEditorProp
astRef.current = ast;
}, []);

const { parsingPlugins, processingPlugins, uiPlugins } = usePlugins(disabledUiPlugins);
const { parsingPlugins, processingPlugins, uiPlugins } = usePlugins({
disabledPlugins: disabledUiPlugins,
});
const editorRef = useRef<EuiMarkdownEditorRef>(null);

useLensButtonToggle({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface Props {
children: string;
disableLinks?: boolean;
textSize?: EuiMarkdownFormatProps['textSize'];
timestamp?: string;
}

const withDisabledLinks = (disableLinks?: boolean): React.FC<EuiLinkAnchorProps> => {
Expand All @@ -28,8 +29,13 @@ const withDisabledLinks = (disableLinks?: boolean): React.FC<EuiLinkAnchorProps>
return MarkdownLinkProcessingComponent;
};

const MarkdownRendererComponent: React.FC<Props> = ({ children, disableLinks, textSize }) => {
const { processingPlugins, parsingPlugins } = usePlugins();
const MarkdownRendererComponent: React.FC<Props> = ({
children,
disableLinks,
textSize,
timestamp,
}) => {
const { processingPlugins, parsingPlugins } = usePlugins({ timestamp });
// Deep clone of the processing plugins to prevent affecting the markdown editor.
const processingPluginList = cloneDeep(processingPlugins);
// This line of code is TS-compatible and it will break if [1][1] change in the future.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,21 @@ export const getContentWrapperCss = (euiTheme: EuiThemeComputed<{}>) => css`
-webkit-box-orient: vertical;
`;

const ScrollableMarkdownRenderer = ({ content }: { content: string }) => {
const ScrollableMarkdownRenderer = ({
content,
timestamp,
}: {
content: string;
timestamp?: string;
}) => {
const { euiTheme } = useEuiTheme();
return (
<div
className={'eui-xScroll'}
css={getContentWrapperCss(euiTheme)}
data-test-subj="scrollable-markdown"
>
<MarkdownRenderer>{content}</MarkdownRenderer>
<MarkdownRenderer timestamp={timestamp}>{content}</MarkdownRenderer>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ export type TemporaryProcessingPluginsType = [
[
typeof rehype2react,
Parameters<typeof rehype2react>[0] & {
components: { a: FunctionComponent<EuiLinkAnchorProps>; lens: unknown; timeline: unknown };
components: {
a: FunctionComponent<EuiLinkAnchorProps>;
lens: unknown;
timeline: unknown;
customCodeBlock: unknown;
esql: unknown;
};
}
],
...PluggableList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ import { KibanaServices, useApplicationCapabilities } from '../../common/lib/kib
import * as lensMarkdownPlugin from './plugins/lens';
import { ID as LensPluginId } from './plugins/lens/constants';

export const usePlugins = (disabledPlugins?: string[]) => {
export const usePlugins = ({
disabledPlugins,
timestamp,
}: {
disabledPlugins?: string[];
timestamp?: string;
} = {}) => {
const kibanaConfig = KibanaServices.getConfig();
const timelinePlugins = useTimelineContext()?.editor_plugins;
const appCapabilities = useApplicationCapabilities();
Expand All @@ -31,10 +37,18 @@ export const usePlugins = (disabledPlugins?: string[]) => {
if (timelinePlugins) {
uiPlugins.push(timelinePlugins.uiPlugin);

parsingPlugins.push(timelinePlugins.parsingPlugin);
parsingPlugins.unshift(timelinePlugins.parsingPlugins.customCodeBlock);
parsingPlugins.push(timelinePlugins.parsingPlugins.timeline);

// This line of code is TS-compatible and it will break if [1][1] change in the future.
processingPlugins[1][1].components.timeline = timelinePlugins.processingPluginRenderer;
processingPlugins[1][1].components.timeline =
timelinePlugins.processingPluginRenderer.timeline;
processingPlugins[1][1].components.esql = (props: {
value: string;
actionsDisabled: boolean;
}) => timelinePlugins.processingPluginRenderer.esql({ timestamp: timestamp ?? '', ...props });
processingPlugins[1][1].components.customCodeBlock =
timelinePlugins.processingPluginRenderer.customCodeBlock;
}

if (
Expand All @@ -59,5 +73,6 @@ export const usePlugins = (disabledPlugins?: string[]) => {
disabledPlugins,
kibanaConfig?.markdownPlugins?.lens,
timelinePlugins,
timestamp,
]);
};
Loading