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

[Security solution] AI Assistant, replace LLM with SimpleChatModel + Bedrock streaming #182041

Merged
merged 44 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
4c82b22
wip
stephmilovic Apr 29, 2024
08dfd30
esql tool
stephmilovic Apr 29, 2024
e823543
alert tools
stephmilovic Apr 30, 2024
3908f40
fix merge
stephmilovic May 9, 2024
699abbb
rm structured
stephmilovic May 9, 2024
dc3d12c
stream wip
stephmilovic May 9, 2024
3e37927
Merge branch 'main' into simple_chat_model
stephmilovic May 14, 2024
385bf10
wip
stephmilovic May 14, 2024
4830879
zomg it streamed
stephmilovic May 15, 2024
ada553e
Merge branch 'main' into simple_chat_model
stephmilovic May 16, 2024
13cbfe8
this is awesome
stephmilovic May 16, 2024
b7c6af7
rm silly
stephmilovic May 16, 2024
af61cac
moar
stephmilovic May 16, 2024
cb83d04
merge in main
stephmilovic May 16, 2024
e0556f4
support non-streaming for ChatOpenAI
stephmilovic May 16, 2024
a3c5394
wip openai
stephmilovic May 17, 2024
109dfa0
openai really works
stephmilovic May 17, 2024
df3732e
fix executor tests
stephmilovic May 17, 2024
b123495
more tests
stephmilovic May 17, 2024
93fedb7
more
stephmilovic May 17, 2024
b53c2c5
more tests
stephmilovic May 20, 2024
14779d2
cleanup
stephmilovic May 20, 2024
082c5ba
Merge branch 'main' into simple_chat_model
stephmilovic May 20, 2024
4cdc699
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine May 20, 2024
88d759e
test fix
stephmilovic May 20, 2024
6d6a3c9
i18n fix
stephmilovic May 20, 2024
43cef41
Merge branch 'simple_chat_model' of github.com:stephmilovic/kibana in…
stephmilovic May 20, 2024
265afe2
rm disable
stephmilovic May 20, 2024
85f7d2d
server dir
stephmilovic May 21, 2024
8d7d540
move langchain code to langchain package
stephmilovic May 21, 2024
4025acd
fix types
stephmilovic May 21, 2024
47ff787
fix merge
stephmilovic May 21, 2024
5b0b77b
fix type
stephmilovic May 21, 2024
c463169
fix import
stephmilovic May 21, 2024
3a8c017
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine May 21, 2024
68b0b7b
[CI] Auto-commit changed files from 'node scripts/generate codeowners'
kibanamachine May 21, 2024
fd4e3c3
fix lint
stephmilovic May 21, 2024
6f11ca6
Merge branch 'simple_chat_model' of github.com:stephmilovic/kibana in…
stephmilovic May 21, 2024
726dcbd
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine May 21, 2024
afb7e49
more import fixing
stephmilovic May 21, 2024
b81bdf0
Merge branch 'simple_chat_model' of github.com:stephmilovic/kibana in…
stephmilovic May 21, 2024
2f66531
add readme comment, fix imports better
stephmilovic May 21, 2024
021de2b
fix!
stephmilovic May 21, 2024
f2d398d
Merge branch 'main' into simple_chat_model
stephmilovic May 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,7 @@ module.exports = {
'x-pack/plugins/elastic_assistant/**/*.{ts,tsx}',
'x-pack/packages/kbn-elastic-assistant/**/*.{ts,tsx}',
'x-pack/packages/kbn-elastic-assistant-common/**/*.{ts,tsx}',
'x-pack/packages/kbn-langchain/**/*.{ts,tsx}',
'x-pack/packages/security-solution/**/*.{ts,tsx}',
'x-pack/plugins/security_solution/**/*.{ts,tsx}',
'x-pack/plugins/security_solution_ess/**/*.{ts,tsx}',
Expand All @@ -1071,6 +1072,7 @@ module.exports = {
'x-pack/plugins/elastic_assistant/**/*.{test,mock,test_helper}.{ts,tsx}',
'x-pack/packages/kbn-elastic-assistant/**/*.{test,mock,test_helper}.{ts,tsx}',
'x-pack/packages/kbn-elastic-assistant-common/**/*.{test,mock,test_helper}.{ts,tsx}',
'x-pack/packages/kbn-langchain/**/*.{test,mock,test_helper}.{ts,tsx}',
'x-pack/packages/security-solution/**/*.{test,mock,test_helper}.{ts,tsx}',
'x-pack/plugins/security_solution/**/*.{test,mock,test_helper}.{ts,tsx}',
'x-pack/plugins/security_solution_ess/**/*.{test,mock,test_helper}.{ts,tsx}',
Expand All @@ -1090,6 +1092,7 @@ module.exports = {
'x-pack/plugins/elastic_assistant/**/*.{ts,tsx}',
'x-pack/packages/kbn-elastic-assistant/**/*.{ts,tsx}',
'x-pack/packages/kbn-elastic-assistant-common/**/*.{ts,tsx}',
'x-pack/packages/kbn-langchain/**/*.{ts,tsx}',
'x-pack/packages/security-solution/**/*.{ts,tsx}',
'x-pack/plugins/security_solution/**/*.{ts,tsx}',
'x-pack/plugins/security_solution_ess/**/*.{ts,tsx}',
Expand Down Expand Up @@ -1128,6 +1131,7 @@ module.exports = {
'x-pack/plugins/elastic_assistant/**/*.{js,mjs,ts,tsx}',
'x-pack/packages/kbn-elastic-assistant/**/*.{js,mjs,ts,tsx}',
'x-pack/packages/kbn-elastic-assistant-common/**/*.{js,mjs,ts,tsx}',
'x-pack/packages/kbn-langchain/**/*.{js,mjs,ts,tsx}',
'x-pack/packages/security-solution/**/*.{js,mjs,ts,tsx}',
'x-pack/plugins/security_solution/**/*.{js,mjs,ts,tsx}',
'x-pack/plugins/security_solution_ess/**/*.{js,mjs,ts,tsx}',
Expand Down
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,7 @@ src/plugins/kibana_react @elastic/appex-sharedux
src/plugins/kibana_usage_collection @elastic/kibana-core
src/plugins/kibana_utils @elastic/appex-sharedux
x-pack/plugins/kubernetes_security @elastic/kibana-cloud-security-posture
x-pack/packages/kbn-langchain @elastic/security-generative-ai
packages/kbn-language-documentation-popover @elastic/kibana-esql
x-pack/examples/lens_config_builder_example @elastic/kibana-visualizations
packages/kbn-lens-embeddable-utils @elastic/obs-ux-infra_services-team @elastic/kibana-visualizations
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@
"@kbn/kibana-usage-collection-plugin": "link:src/plugins/kibana_usage_collection",
"@kbn/kibana-utils-plugin": "link:src/plugins/kibana_utils",
"@kbn/kubernetes-security-plugin": "link:x-pack/plugins/kubernetes_security",
"@kbn/langchain": "link:x-pack/packages/kbn-langchain",
"@kbn/language-documentation-popover": "link:packages/kbn-language-documentation-popover",
"@kbn/lens-config-builder-example-plugin": "link:x-pack/examples/lens_config_builder_example",
"@kbn/lens-embeddable-utils": "link:packages/kbn-lens-embeddable-utils",
Expand Down
2 changes: 2 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,8 @@
"@kbn/kibana-utils-plugin/*": ["src/plugins/kibana_utils/*"],
"@kbn/kubernetes-security-plugin": ["x-pack/plugins/kubernetes_security"],
"@kbn/kubernetes-security-plugin/*": ["x-pack/plugins/kubernetes_security/*"],
"@kbn/langchain": ["x-pack/packages/kbn-langchain"],
"@kbn/langchain/*": ["x-pack/packages/kbn-langchain/*"],
"@kbn/language-documentation-popover": ["packages/kbn-language-documentation-popover"],
"@kbn/language-documentation-popover/*": ["packages/kbn-language-documentation-popover/*"],
"@kbn/lens-config-builder-example-plugin": ["x-pack/examples/lens_config_builder_example"],
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,30 @@
* 2.0.
*/

import { Logger } from '@kbn/core/server';
import { Logger } from '@kbn/logging';
import { EventStreamCodec } from '@smithy/eventstream-codec';
import { fromUtf8, toUtf8 } from '@smithy/util-utf8';

/**
* Parses a Bedrock buffer from an array of chunks.
*
* @param {Uint8Array[]} chunks - Array of Uint8Array chunks to be parsed.
* @returns {string} - Parsed string from the Bedrock buffer.
*/
export const parseBedrockBuffer = (chunks: Uint8Array[], logger: Logger): string => {
// Initialize an empty Uint8Array to store the concatenated buffer.
let bedrockBuffer: Uint8Array = new Uint8Array(0);

// Map through each chunk to process the Bedrock buffer.
return chunks
.map((chunk) => {
const processedChunk = handleBedrockChunk({ chunk, bedrockBuffer, logger });
bedrockBuffer = processedChunk.bedrockBuffer;
return processedChunk.decodedChunk;
})
.join('');
};

/**
* Handle a chunk of data from the bedrock API.
* @param chunk - The chunk of data to process.
Expand Down Expand Up @@ -55,7 +75,9 @@ export const handleBedrockChunk = ({
Buffer.from(JSON.parse(new TextDecoder().decode(event.body)).bytes, 'base64').toString()
);
const decodedContent = prepareBedrockOutput(body, logger);
if (chunkHandler) chunkHandler(decodedContent);
if (chunkHandler) {
chunkHandler(decodedContent);
}
return decodedContent;
})
.join('');
Expand Down
3 changes: 1 addition & 2 deletions x-pack/packages/kbn-elastic-assistant-common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,5 @@ export {
} from './impl/data_anonymization/helpers';

export { transformRawData } from './impl/data_anonymization/transform_raw_data';
export { handleBedrockChunk } from './impl/utils/bedrock';

export { parseBedrockBuffer, handleBedrockChunk } from './impl/utils/bedrock';
export * from './constants';
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"@kbn/zod-helpers",
"@kbn/securitysolution-io-ts-utils",
"@kbn/core",
"@kbn/actions-plugin",
"@kbn/logging-mocks",
"@kbn/logging",
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const mockHttp = {
fetch: jest.fn(),
} as unknown as HttpSetup;

const apiConfig: Record<'openai' | 'bedrock', ApiConfig> = {
const apiConfig: Record<'openai' | 'bedrock' | 'gemini', ApiConfig> = {
openai: {
connectorId: 'foo',
actionTypeId: '.gen-ai',
Expand All @@ -35,6 +35,10 @@ const apiConfig: Record<'openai' | 'bedrock', ApiConfig> = {
connectorId: 'foo',
actionTypeId: '.bedrock',
},
gemini: {
connectorId: 'foo',
actionTypeId: '.gemini',
},
};

const fetchConnectorArgs: FetchConnectorExecuteAction = {
Expand Down Expand Up @@ -94,7 +98,7 @@ describe('API tests', () => {
);
});

it('calls the non-stream API when assistantStreamingEnabled is true and actionTypeId is bedrock and isEnabledKnowledgeBase is true', async () => {
it('calls the stream API when assistantStreamingEnabled is true and actionTypeId is bedrock and isEnabledKnowledgeBase is true', async () => {
const testProps: FetchConnectorExecuteAction = {
...fetchConnectorArgs,
apiConfig: apiConfig.bedrock,
Expand All @@ -105,13 +109,13 @@ describe('API tests', () => {
expect(mockHttp.fetch).toHaveBeenCalledWith(
'/internal/elastic_assistant/actions/connector/foo/_execute',
{
...staticDefaults,
body: '{"message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".bedrock","replacements":{},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":false}',
...streamingDefaults,
body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".bedrock","replacements":{},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":false}',
}
);
});

it('calls the non-stream API when assistantStreamingEnabled is true and actionTypeId is bedrock and isEnabledKnowledgeBase is false and isEnabledRAGAlerts is true', async () => {
it('calls the stream API when assistantStreamingEnabled is true and actionTypeId is bedrock and isEnabledKnowledgeBase is false and isEnabledRAGAlerts is true', async () => {
const testProps: FetchConnectorExecuteAction = {
...fetchConnectorArgs,
apiConfig: apiConfig.bedrock,
Expand All @@ -121,11 +125,47 @@ describe('API tests', () => {

await fetchConnectorExecuteAction(testProps);

expect(mockHttp.fetch).toHaveBeenCalledWith(
'/internal/elastic_assistant/actions/connector/foo/_execute',
{
...streamingDefaults,
body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".bedrock","replacements":{},"isEnabledKnowledgeBase":false,"isEnabledRAGAlerts":true}',
}
);
});

it('calls the non-stream API when assistantStreamingEnabled is true and actionTypeId is gemini and isEnabledKnowledgeBase is true', async () => {
const testProps: FetchConnectorExecuteAction = {
...fetchConnectorArgs,
apiConfig: apiConfig.gemini,
};

await fetchConnectorExecuteAction(testProps);

expect(mockHttp.fetch).toHaveBeenCalledWith(
'/internal/elastic_assistant/actions/connector/foo/_execute',
{
...staticDefaults,
body: '{"message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".gemini","replacements":{},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":false}',
}
);
});

it('calls the non-stream API when assistantStreamingEnabled is true and actionTypeId is gemini and isEnabledKnowledgeBase is false and isEnabledRAGAlerts is true', async () => {
const testProps: FetchConnectorExecuteAction = {
...fetchConnectorArgs,
apiConfig: apiConfig.gemini,
isEnabledKnowledgeBase: false,
isEnabledRAGAlerts: true,
};

await fetchConnectorExecuteAction(testProps);

expect(mockHttp.fetch).toHaveBeenCalledWith(
'/internal/elastic_assistant/actions/connector/foo/_execute',
{
...staticDefaults,
body: '{"message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".bedrock","replacements":{},"isEnabledKnowledgeBase":false,"isEnabledRAGAlerts":true}',
body: '{"message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".gemini","replacements":{},"isEnabledKnowledgeBase":false,"isEnabledRAGAlerts":true}',
}
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,14 @@ export const fetchConnectorExecuteAction = async ({
size,
traceOptions,
}: FetchConnectorExecuteAction): Promise<FetchConnectorExecuteResponse> => {
// TODO add streaming support for gemini with langchain on
const isStream =
assistantStreamingEnabled &&
(apiConfig.actionTypeId === '.gen-ai' ||
// TODO add streaming support for bedrock with langchain on
apiConfig.actionTypeId === '.bedrock' ||
// TODO add streaming support for gemini with langchain on
// tracked here: https://github.com/elastic/security-team/issues/7363
(apiConfig.actionTypeId === '.bedrock' && !isEnabledRAGAlerts && !isEnabledKnowledgeBase));
(apiConfig.actionTypeId === '.gemini' && !isEnabledRAGAlerts && !isEnabledKnowledgeBase));

const optionalRequestParams = getOptionalRequestParams({
isEnabledRAGAlerts,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@ export const YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT = i18n.translate(
}
);

export const USE_THE_FOLLOWING_CONTEXT_TO_ANSWER = i18n.translate(
'xpack.elasticAssistant.assistant.content.prompts.system.useTheFollowingContextToAnswer',
{
defaultMessage: 'Use the following context to answer questions:',
}
);

export const IF_YOU_DONT_KNOW_THE_ANSWER = i18n.translate(
'xpack.elasticAssistant.assistant.content.prompts.system.ifYouDontKnowTheAnswer',
{
Expand All @@ -37,8 +30,7 @@ export const SUPERHERO_PERSONALITY = i18n.translate(
}
);

export const DEFAULT_SYSTEM_PROMPT_NON_I18N = `${YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT} ${IF_YOU_DONT_KNOW_THE_ANSWER}
${USE_THE_FOLLOWING_CONTEXT_TO_ANSWER}`;
export const DEFAULT_SYSTEM_PROMPT_NON_I18N = `${YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT} ${IF_YOU_DONT_KNOW_THE_ANSWER}`;

export const DEFAULT_SYSTEM_PROMPT_NAME = i18n.translate(
'xpack.elasticAssistant.assistant.content.prompts.system.defaultSystemPromptName',
Expand All @@ -48,8 +40,7 @@ export const DEFAULT_SYSTEM_PROMPT_NAME = i18n.translate(
);

export const SUPERHERO_SYSTEM_PROMPT_NON_I18N = `${YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT} ${IF_YOU_DONT_KNOW_THE_ANSWER}
${SUPERHERO_PERSONALITY}
${USE_THE_FOLLOWING_CONTEXT_TO_ANSWER}`;
${SUPERHERO_PERSONALITY}`;

export const SUPERHERO_SYSTEM_PROMPT_NAME = i18n.translate(
'xpack.elasticAssistant.assistant.content.prompts.system.superheroSystemPromptName',
Expand Down
5 changes: 5 additions & 0 deletions x-pack/packages/kbn-langchain/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# @kbn/langchain

Contains LangChain language models to be used with Kibana connectors

The package does not expose `index.ts` at its root, instead there's a `server` directory you should deep-import from.
22 changes: 22 additions & 0 deletions x-pack/packages/kbn-langchain/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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 = {
coverageDirectory: '<rootDir>/target/kibana-coverage/jest/x-pack/packages/kbn_langchain',
coverageReporters: ['text', 'html'],
collectCoverageFrom: [
'<rootDir>/x-pack/packages/kbn-langchain/server/**/*.{ts}',
'!<rootDir>/x-pack/packages/kbn-langchain/server/{__test__,__snapshots__,__examples__,*mock*,tests,test_helpers,integration_tests,types}/**/*',
'!<rootDir>/x-pack/packages/kbn-langchain/server/*mock*.{ts}',
'!<rootDir>/x-pack/packages/kbn-langchain/server/*.test.{ts}',
'!<rootDir>/x-pack/packages/kbn-langchain/server/*.d.ts',
'!<rootDir>/x-pack/packages/kbn-langchain/server/*.config.ts',
],
preset: '@kbn/test',
rootDir: '../../..',
roots: ['<rootDir>/x-pack/packages/kbn-langchain'],
};
5 changes: 5 additions & 0 deletions x-pack/packages/kbn-langchain/kibana.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "shared-server",
"id": "@kbn/langchain",
"owner": "@elastic/security-generative-ai"
}
7 changes: 7 additions & 0 deletions x-pack/packages/kbn-langchain/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "@kbn/langchain",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0",
"sideEffects": false
}
20 changes: 20 additions & 0 deletions x-pack/packages/kbn-langchain/server/index.ts
Original file line number Diff line number Diff line change
@@ -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 { ActionsClientChatOpenAI } from './language_models/chat_openai';
import { ActionsClientLlm } from './language_models/llm';
import { ActionsClientSimpleChatModel } from './language_models/simple_chat_model';
import { parseBedrockStream } from './utils/bedrock';
import { getDefaultArguments } from './language_models/constants';

export {
parseBedrockStream,
getDefaultArguments,
ActionsClientChatOpenAI,
ActionsClientLlm,
ActionsClientSimpleChatModel,
};