Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ export const ELASTIC_AI_ASSISTANT_ALERT_SUMMARY_URL_BULK_ACTION =
export const ELASTIC_AI_ASSISTANT_ALERT_SUMMARY_URL_FIND =
`${ELASTIC_AI_ASSISTANT_ALERT_SUMMARY_URL}/_find` as const;

// Security AI Prompts (prompt integration)
export const ELASTIC_AI_ASSISTANT_SECURITY_AI_PROMPTS_URL =
`${ELASTIC_AI_ASSISTANT_URL}/security_ai_prompts` as const;
export const ELASTIC_AI_ASSISTANT_SECURITY_AI_PROMPTS_URL_FIND =
`${ELASTIC_AI_ASSISTANT_SECURITY_AI_PROMPTS_URL}/_find` as const;

// Defend insights
export const DEFEND_INSIGHTS_TOOL_ID = 'defend-insights';
export const DEFEND_INSIGHTS = `${ELASTIC_AI_ASSISTANT_INTERNAL_URL}/defend_insights`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export const BulkActionBase = z.object({
});

/**
* User screen context.
* IDs for a specific prompt within a group of prompts.
*/
export type PromptIds = z.infer<typeof PromptIds>;
export const PromptIds = z.object({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ components:
- "5678"

PromptIds:
description: User screen context.
description: IDs for a specific prompt within a group of prompts.
type: object
required:
- promptId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,6 @@ export * from './anonymization_fields/find_anonymization_fields_route.gen';
export * from './prompts/bulk_crud_prompts_route.gen';
export * from './prompts/find_prompts_route.gen';

export * from './security_ai_prompts/find_prompts_route.gen';

export { PromptResponse, PromptTypeEnum } from './prompts/bulk_crud_prompts_route.gen';
Original file line number Diff line number Diff line change
@@ -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.
*/

/*
* NOTICE: Do not edit this file manually.
* This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
*
* info:
* title: Common Security AI Prompts Attributes
* version: not applicable
*/

import { z } from '@kbn/zod';

export type PromptItem = z.infer<typeof PromptItem>;
export const PromptItem = z.object({
promptId: z.string(),
prompt: z.string(),
});

/**
* Prompt array by prompt group id and prompt id.
*/
export type PromptItemArray = z.infer<typeof PromptItemArray>;
export const PromptItemArray = z.array(PromptItem);
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
openapi: 3.0.0
info:
title: Common Security AI Prompts Attributes
version: 'not applicable'
paths: {}
components:
x-codegen-enabled: true
schemas:
PromptItem:
type: object
properties:
promptId:
type: string
example: systemPrompt
prompt:
type: string
example: This is the prompt
required:
- promptId
- prompt

PromptItemArray:
type: array
description: Prompt array by prompt group id and prompt id.
items:
$ref: '#/components/schemas/PromptItem'
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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.
*/

/*
* NOTICE: Do not edit this file manually.
* This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
*
* info:
* title: Get Security AI Prompt endpoint
* version: 2023-10-31
*/

import { z } from '@kbn/zod';
import { ArrayFromString } from '@kbn/zod-helpers';

import { PromptItemArray } from './common_attributes.gen';

export type FindSecurityAIPromptsRequestQuery = z.infer<typeof FindSecurityAIPromptsRequestQuery>;
export const FindSecurityAIPromptsRequestQuery = z.object({
/**
* Connector id used for prompt lookup
*/
connector_id: z.string().optional(),
/**
* The unique identifier for the prompt group
*/
prompt_group_id: z.string(),
/**
* Comma-separated list of prompt IDs to retrieve
*/
prompt_ids: ArrayFromString(z.string()),
});
export type FindSecurityAIPromptsRequestQueryInput = z.input<
typeof FindSecurityAIPromptsRequestQuery
>;

export type FindSecurityAIPromptsResponse = z.infer<typeof FindSecurityAIPromptsResponse>;
export const FindSecurityAIPromptsResponse = z.object({
prompts: PromptItemArray,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
openapi: 3.0.0
info:
title: Get Security AI Prompt endpoint
version: '2023-10-31'
paths:
/api/security_ai_assistant/security_ai_prompts/_find:
get:
x-codegen-enabled: true
x-internal: true
x-labels: [ess, serverless]
operationId: FindSecurityAIPrompts
description: Gets Security AI prompts
summary: Gets Security AI prompts
tags:
- Security AI Prompts API
parameters:
- name: connector_id
in: query
description: Connector id used for prompt lookup
required: false
schema:
type: string
- name: prompt_group_id
in: query
description: The unique identifier for the prompt group
required: true
schema:
type: string
- name: prompt_ids
in: query
description: Comma-separated list of prompt IDs to retrieve
required: true
style: form
explode: true
schema:
type: array
items:
type: string
responses:
'200':
description: Indicates a successful call.
content:
application/json:
schema:
type: object
properties:
prompts:
$ref: './common_attributes.schema.yaml#/components/schemas/PromptItemArray'
required:
- prompts
'400':
description: Generic Error
content:
application/json:
schema:
type: object
properties:
status_code:
type: number
error:
type: string
message:
type: string
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* 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 { waitFor, renderHook } from '@testing-library/react';
import { useFindPrompts, UseFindPromptsParams } from './use_find_prompts';
import {
API_VERSIONS,
ELASTIC_AI_ASSISTANT_SECURITY_AI_PROMPTS_URL_FIND,
} from '@kbn/elastic-assistant-common';
import { TestProviders } from '../../../mock/test_providers/test_providers';
import { IToasts } from '@kbn/core-notifications-browser';

const mockHttpFetch = jest.fn();
const mockToasts = {
addSuccess: jest.fn(),
addError: jest.fn(),
} as unknown as IToasts;

describe('useFindPrompts', () => {
const params: UseFindPromptsParams = {
context: {
isAssistantEnabled: true,
httpFetch: mockHttpFetch,
toasts: mockToasts,
},
params: {
connector_id: 'connector-1',
prompt_ids: ['prompt-1'],
prompt_group_id: 'group-1',
},
signal: undefined,
};

beforeEach(() => {
jest.clearAllMocks();
});

it('returns initial and placeholder data when loading', async () => {
mockHttpFetch.mockResolvedValueOnce({ prompts: [{ id: 'prompt-1', name: 'Prompt 1' }] });
const { result } = renderHook(() => useFindPrompts(params), {
wrapper: TestProviders,
});
expect(result.current.data).toEqual({ prompts: [] });
await waitFor(() => result.current.isSuccess);

await waitFor(() =>
expect(result.current.data).toEqual({ prompts: [{ id: 'prompt-1', name: 'Prompt 1' }] })
);
});

it('disables the query if isAssistantEnabled is false', async () => {
const disabledParams = { ...params, context: { ...params.context, isAssistantEnabled: false } };
const { result } = renderHook(() => useFindPrompts(disabledParams), { wrapper: TestProviders });
expect(result.current.isLoading).toBe(false);
expect(result.current.data).toEqual({ prompts: [] });
expect(mockHttpFetch).not.toHaveBeenCalled();
});

it('calls httpFetch with correct arguments', async () => {
mockHttpFetch.mockResolvedValueOnce({ prompts: [{ id: 'prompt-1', name: 'Prompt 1' }] });
const { result } = renderHook(() => useFindPrompts(params), {
wrapper: TestProviders,
});
await waitFor(() => result.current.isSuccess);
expect(mockHttpFetch).toHaveBeenCalledWith(
ELASTIC_AI_ASSISTANT_SECURITY_AI_PROMPTS_URL_FIND,
expect.objectContaining({
method: 'GET',
version: API_VERSIONS.public.v1,
query: {
connector_id: 'connector-1',
prompt_ids: ['prompt-1'],
prompt_group_id: 'group-1',
},
})
);
});

it('shows a toast on error', async () => {
const error = { body: { message: 'Something went wrong' } };
mockHttpFetch.mockRejectedValueOnce(error);
const { result } = renderHook(() => useFindPrompts(params), {
wrapper: TestProviders,
});
await waitFor(() => result.current.isError);
expect(mockToasts.addError).toHaveBeenCalledWith(
expect.any(Error),
expect.objectContaining({
title: expect.any(String),
})
);
});
});
Loading