Skip to content

Commit

Permalink
Merge branch 'main' into feature-display-package-root-privileges
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored Nov 7, 2023
2 parents 92d66c1 + 0fce67d commit 30a575c
Show file tree
Hide file tree
Showing 101 changed files with 5,597 additions and 1,388 deletions.
2 changes: 1 addition & 1 deletion .buildkite/scripts/steps/artifacts/docker_context.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ KIBANA_DOCKER_CONTEXT="${KIBANA_DOCKER_CONTEXT:="default"}"

echo "--- Create contexts"
mkdir -p target
node scripts/build --skip-initialize --skip-generic-folders --skip-platform-folders --skip-archives --docker-context-use-local-artifact
node scripts/build --skip-initialize --skip-generic-folders --skip-platform-folders --skip-archives --skip-cdn-assets --docker-context-use-local-artifact

echo "--- Setup context"
DOCKER_BUILD_FOLDER=$(mktemp -d)
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-management/cards_navigation/src/consts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const appDefinitions: Record<AppId, AppDefinition> = {
[AppIds.SAVED_OBJECTS]: {
category: appCategories.CONTENT,
description: i18n.translate('management.landing.withCardNavigation.objectsDescription', {
defaultMessage: 'Manage your saved dashboards, maps, data views, and Canvas workpads.',
defaultMessage: 'Manage your saved dashboards, visualizations, maps, and data views.',
}),
icon: 'save',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,15 @@ export const IntegrationsPanel: React.FC<IntegrationsPanelProps> = ({
<EuiTitle size="s">
<h3>
{i18n.translate('searchApiPanels.welcomeBanner.ingestData.connectorsTitle', {
defaultMessage: 'Connector Client',
defaultMessage: 'Connector clients',
})}
</h3>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText size="s">
{i18n.translate('searchApiPanels.welcomeBanner.ingestData.connectorsDescription', {
defaultMessage:
'Specialized integrations for syncing data from third-party sources to Elasticsearch. Use Elastic Connectors to sync content from a range of databases and object stores.',
'Specialized integrations for syncing data from third-party sources to Elasticsearch. Use Elastic connectors to sync content from a range of databases and object stores.',
})}
</EuiText>
<EuiSpacer size="m" />
Expand All @@ -153,7 +153,7 @@ export const IntegrationsPanel: React.FC<IntegrationsPanelProps> = ({
label={i18n.translate(
'searchApiPanels.welcomeBanner.ingestData.connectorsPythonLink',
{
defaultMessage: 'connectors-python',
defaultMessage: 'elastic/connectors',
}
)}
assetBasePath={assetBasePath}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const TryInConsoleButton = ({
<EuiButtonEmpty href={consolePreviewLink} iconType="popout" target="_blank" size="s">
<FormattedMessage
id="searchApiPanels.welcomeBanner.tryInConsoleButton"
defaultMessage="Try in console"
defaultMessage="Try in Console"
/>
</EuiButtonEmpty>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ describe('API tests', () => {

const result = await fetchConnectorExecuteAction(testProps);

expect(result).toEqual({ response: API_ERROR, isError: true });
expect(result).toEqual({ response: API_ERROR, isStream: false, isError: true });
});

it('returns API_ERROR when there are no choices', async () => {
Expand All @@ -109,7 +109,7 @@ describe('API tests', () => {

const result = await fetchConnectorExecuteAction(testProps);

expect(result).toEqual({ response: API_ERROR, isError: true });
expect(result).toEqual({ response: API_ERROR, isStream: false, isError: true });
});

it('returns the value of the action_input property when assistantLangChain is true, and `content` has properly prefixed and suffixed JSON with the action_input property', async () => {
Expand All @@ -129,7 +129,11 @@ describe('API tests', () => {

const result = await fetchConnectorExecuteAction(testProps);

expect(result).toEqual({ response: 'value from action_input', isError: false });
expect(result).toEqual({
response: 'value from action_input',
isStream: false,
isError: false,
});
});

it('returns the original content when assistantLangChain is true, and `content` has properly formatted JSON WITHOUT the action_input property', async () => {
Expand All @@ -149,7 +153,7 @@ describe('API tests', () => {

const result = await fetchConnectorExecuteAction(testProps);

expect(result).toEqual({ response, isError: false });
expect(result).toEqual({ response, isStream: false, isError: false });
});

it('returns the original when assistantLangChain is true, and `content` is not JSON', async () => {
Expand All @@ -169,7 +173,7 @@ describe('API tests', () => {

const result = await fetchConnectorExecuteAction(testProps);

expect(result).toEqual({ response, isError: false });
expect(result).toEqual({ response, isStream: false, isError: false });
});
});

Expand Down
71 changes: 59 additions & 12 deletions x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/public/common';

import { HttpSetup, IHttpFetchError } from '@kbn/core-http-browser';

import type { Conversation, Message } from '../assistant_context/types';
import { API_ERROR } from './translations';
import { MODEL_GPT_3_5_TURBO } from '../connectorland/models/model_selector/model_selector';
Expand All @@ -24,8 +23,9 @@ export interface FetchConnectorExecuteAction {
}

export interface FetchConnectorExecuteResponse {
response: string;
response: string | ReadableStreamDefaultReader<Uint8Array>;
isError: boolean;
isStream: boolean;
}

export const fetchConnectorExecuteAction = async ({
Expand Down Expand Up @@ -54,26 +54,69 @@ export const fetchConnectorExecuteAction = async ({
messages: outboundMessages,
};

const requestBody = {
params: {
subActionParams: body,
subAction: 'invokeAI',
},
assistantLangChain,
};
// TODO: Remove in part 2 of streaming work for security solution
// tracked here: https://github.com/elastic/security-team/issues/7363
// My "Feature Flag", turn to false before merging
// In part 2 I will make enhancements to invokeAI to make it work with both openA, but to keep it to a Security Soltuion only review on this PR,
// I'm calling the stream action directly
const isStream = !assistantLangChain && false;
const requestBody = isStream
? {
params: {
subActionParams: body,
subAction: 'stream',
},
assistantLangChain,
}
: {
params: {
subActionParams: body,
subAction: 'invokeAI',
},
assistantLangChain,
};

try {
if (isStream) {
const response = await http.fetch(
`/internal/elastic_assistant/actions/connector/${apiConfig?.connectorId}/_execute`,
{
method: 'POST',
body: JSON.stringify(requestBody),
signal,
asResponse: isStream,
rawResponse: isStream,
}
);

const reader = response?.response?.body?.getReader();

if (!reader) {
return {
response: `${API_ERROR}\n\nCould not get reader from response`,
isError: true,
isStream: false,
};
}
return {
response: reader,
isStream: true,
isError: false,
};
}

// TODO: Remove in part 2 of streaming work for security solution
// tracked here: https://github.com/elastic/security-team/issues/7363
// This is a temporary code to support the non-streaming API
const response = await http.fetch<{
connector_id: string;
status: string;
data: string;
service_message?: string;
}>(`/internal/elastic_assistant/actions/connector/${apiConfig?.connectorId}/_execute`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody),
headers: { 'Content-Type': 'application/json' },
signal,
});

Expand All @@ -82,21 +125,25 @@ export const fetchConnectorExecuteAction = async ({
return {
response: `${API_ERROR}\n\n${response.service_message}`,
isError: true,
isStream: false,
};
}
return {
response: API_ERROR,
isError: true,
isStream: false,
};
}
return {
response: assistantLangChain ? getFormattedMessageContent(response.data) : response.data,
isError: false,
isStream: false,
};
} catch (error) {
return {
response: `${API_ERROR}\n\n${error?.body?.message ?? error?.message}`,
isError: true,
isStream: false,
};
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,28 @@ import React from 'react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { ChatSend, Props } from '.';
import { TestProviders } from '../../mock/test_providers/test_providers';
import { useChatSend } from './use_chat_send';
import { defaultSystemPrompt, mockSystemPrompt } from '../../mock/system_prompt';
import { emptyWelcomeConvo } from '../../mock/conversation';
import { HttpSetup } from '@kbn/core-http-browser';

jest.mock('./use_chat_send');

const testProps: Props = {
selectedPromptContexts: {},
allSystemPrompts: [defaultSystemPrompt, mockSystemPrompt],
currentConversation: emptyWelcomeConvo,
http: {
basePath: {
basePath: '/mfg',
serverBasePath: '/mfg',
},
anonymousPaths: {},
externalUrl: {},
} as unknown as HttpSetup,
editingSystemPromptId: defaultSystemPrompt.id,
setEditingSystemPromptId: () => {},
setPromptTextPreview: () => {},
setSelectedPromptContexts: () => {},
setUserPrompt: () => {},
isDisabled: false,
shouldRefocusPrompt: false,
userPrompt: '',
};
const handleButtonSendMessage = jest.fn();
const handleOnChatCleared = jest.fn();
const handlePromptChange = jest.fn();
const handleSendMessage = jest.fn();
const chatSend = {
const handleRegenerateResponse = jest.fn();
const testProps: Props = {
handleButtonSendMessage,
handleOnChatCleared,
handlePromptChange,
handleSendMessage,
handleRegenerateResponse,
isLoading: false,
isDisabled: false,
shouldRefocusPrompt: false,
userPrompt: '',
};

describe('ChatSend', () => {
beforeEach(() => {
jest.clearAllMocks();
(useChatSend as jest.Mock).mockReturnValue(chatSend);
});
it('the prompt updates when the text area changes', async () => {
const { getByTestId } = render(<ChatSend {...testProps} />, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { css } from '@emotion/react';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { useChatSend, UseChatSendProps } from './use_chat_send';
import { UseChatSend } from './use_chat_send';
import { ChatActions } from '../chat_actions';
import { PromptTextArea } from '../prompt_textarea';

export interface Props extends UseChatSendProps {
export interface Props extends UseChatSend {
isDisabled: boolean;
shouldRefocusPrompt: boolean;
userPrompt: string | null;
Expand All @@ -23,18 +23,15 @@ export interface Props extends UseChatSendProps {
* Allows the user to clear the chat and switch between different system prompts.
*/
export const ChatSend: React.FC<Props> = ({
handleButtonSendMessage,
handleOnChatCleared,
handlePromptChange,
handleSendMessage,
isDisabled,
userPrompt,
isLoading,
shouldRefocusPrompt,
...rest
userPrompt,
}) => {
const {
handleButtonSendMessage,
handleOnChatCleared,
handlePromptChange,
handleSendMessage,
isLoading,
} = useChatSend(rest);
// For auto-focusing prompt within timeline
const promptTextAreaRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const setSelectedPromptContexts = jest.fn();
const setUserPrompt = jest.fn();
const sendMessages = jest.fn();
const appendMessage = jest.fn();
const removeLastMessage = jest.fn();
const appendReplacements = jest.fn();
const clearConversation = jest.fn();

Expand Down Expand Up @@ -55,6 +56,7 @@ describe('use chat send', () => {
(useConversation as jest.Mock).mockReturnValue({
appendMessage,
appendReplacements,
removeLastMessage,
clearConversation,
});
});
Expand Down Expand Up @@ -106,4 +108,17 @@ describe('use chat send', () => {
expect(appendMessage.mock.calls[0][0].message.content).toEqual(`\n\n${promptText}`);
});
});
it('handleRegenerateResponse removes the last message of the conversation, resends the convo to GenAI, and appends the message received', async () => {
const { result } = renderHook(() =>
useChatSend({ ...testProps, currentConversation: welcomeConvo })
);

result.current.handleRegenerateResponse();
expect(removeLastMessage).toHaveBeenCalledWith('Welcome');

await waitFor(() => {
expect(sendMessages).toHaveBeenCalled();
expect(appendMessage.mock.calls[0][0].message.content).toEqual(robotMessage.response);
});
});
});
Loading

0 comments on commit 30a575c

Please sign in to comment.