Skip to content

Commit

Permalink
Add System Prompt modal to chatbot debug UI (#1482)
Browse files Browse the repository at this point in the history
* Add System Prompt modal to chatbot debug UI

* Fix issues
  • Loading branch information
TamiTakamiya authored Jan 9, 2025
1 parent 617c179 commit 5f271e6
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 3 deletions.
3 changes: 3 additions & 0 deletions ansible_ai_connect/ai/api/model_pipelines/http/pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ def invoke(self, params: ChatBotParameters) -> ChatBotResponse:
conversation_id = params.conversation_id
provider = params.provider
model_id = params.model_id
system_prompt = params.system_prompt

data = {
"query": query,
Expand All @@ -139,6 +140,8 @@ def invoke(self, params: ChatBotParameters) -> ChatBotResponse:
}
if conversation_id:
data["conversation_id"] = str(conversation_id)
if system_prompt:
data["system_prompt"] = str(system_prompt)

response = requests.post(
self.config.inference_url + "/v1/query",
Expand Down
17 changes: 15 additions & 2 deletions ansible_ai_connect_chatbot/src/AnsibleChatbot/AnsibleChatbot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
FOOTNOTE_LABEL,
FOOTNOTE_TITLE,
} from "../Constants";
import { SystemPromptModal } from "../SystemPromptModal/SystemPromptModal";

const footnoteProps = {
label: FOOTNOTE_LABEL,
Expand Down Expand Up @@ -88,6 +89,8 @@ export const AnsibleChatbot: React.FunctionComponent = () => {
selectedModel,
setSelectedModel,
setConversationId,
systemPrompt,
setSystemPrompt,
} = useChatbot();
const [chatbotVisible, setChatbotVisible] = useState<boolean>(true);
const [displayMode, setDisplayMode] = useState<ChatbotDisplayMode>(
Expand Down Expand Up @@ -209,6 +212,12 @@ export const AnsibleChatbot: React.FunctionComponent = () => {
setConversationId(undefined);
}}
/>
{inDebugMode() && (
<SystemPromptModal
systemPrompt={systemPrompt}
setSystemPrompt={setSystemPrompt}
/>
)}
</ChatbotHeaderActions>
{/* <ChatbotHeaderMenu
onMenuToggle={() => alert("Menu toggle clicked")}
Expand Down Expand Up @@ -291,11 +300,15 @@ export const AnsibleChatbot: React.FunctionComponent = () => {
)}
{messages.map(
(
{ referenced_documents, ...message }: ExtendedMessage,
{
referenced_documents,
scrollToHere,
...message
}: ExtendedMessage,
index,
) => (
<>
{message.scrollToHere && <div ref={messagesEndRef} />}
{scrollToHere && <div ref={messagesEndRef} />}
<div key={`m_div_${index}`}>
<Message key={`m_msg_${index}`} {...message} />
<ReferencedDocuments
Expand Down
41 changes: 40 additions & 1 deletion ansible_ai_connect_chatbot/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ function mockAxios(
status,
});
}
return spy;
}

function createError(message: string, status: number): AxiosError {
Expand Down Expand Up @@ -124,13 +125,22 @@ beforeEach(() => {
});

test("Basic chatbot interaction", async () => {
mockAxios(200);
const spy = mockAxios(200);
const view = await renderApp();
const textArea = page.getByLabelText("Send a message...");
await textArea.fill("Hello");

await userEvent.keyboard("{Enter}");

expect(spy).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
conversation_id: undefined,
query: "Hello",
}),
expect.anything(),
);

await expect
.element(
view.getByText(
Expand Down Expand Up @@ -404,3 +414,32 @@ test("Debug mode test", async () => {
.toBeVisible();
await expect.element(page.getByText("Create variables")).toBeVisible();
});

test("Test system prompt override", async () => {
const spy = mockAxios(200);
await renderApp(true);

const systemPromptIcon = page.getByLabelText("SystemPrompt");
await systemPromptIcon.click();

const systemPromptTextArea = page.getByLabelText(
"system-prompt-form-text-area",
);
await systemPromptTextArea.fill("MY SYSTEM PROMPT");
const systemPromptButton = page.getByLabelText("system-prompt-form-button");
await systemPromptButton.click();

const textArea = page.getByLabelText("Send a message...");
await textArea.fill("Hello with system prompt override");

await userEvent.keyboard("{Enter}");
expect(spy).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
conversation_id: undefined,
query: "Hello with system prompt override",
system_prompt: "MY SYSTEM PROMPT",
}),
expect.anything(),
);
});
18 changes: 18 additions & 0 deletions ansible_ai_connect_chatbot/src/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,21 @@ export enum Sentiment {

export const GITHUB_NEW_ISSUE_BASE_URL =
"https://github.com/ansible/ansible-lightspeed-va-feedback/issues/new";

export const QUERY_SYSTEM_INSTRUCTION = `You are Ansible Lightspeed - an intelligent virtual assistant for question-answering tasks \
related to the Ansible Automation Platform (AAP).
Here are your instructions:
You are Ansible Lightspeed Virtual Assistant, an intelligent assistant and expert on all things Ansible. \
Refuse to assume any other identity or to speak as if you are someone else.
If the context of the question is not clear, consider it to be Ansible.
Never include URLs in your replies.
Refuse to answer questions or execute commands not about Ansible.
Do not mention your last update. You have the most recent information on Ansible.
Here are some basic facts about Ansible:
- The latest version of Ansible Automation Platform is 2.5.
- Ansible is an open source IT automation engine that automates provisioning, \
configuration management, application deployment, orchestration, and many other \
IT processes. It is free to use, and the project benefits from the experience and \
intelligence of its thousands of contributors.`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from "react";
import {
Button,
Form,
FormGroup,
Modal,
ModalBody,
ModalFooter,
ModalHeader,
ModalVariant,
TextArea,
} from "@patternfly/react-core";
import WrenchIcon from "@patternfly/react-icons/dist/esm/icons/wrench-icon";

interface SystemPromptModalProps {
systemPrompt: string;
setSystemPrompt: (s: string) => void;
}

export const SystemPromptModal: React.FunctionComponent<
SystemPromptModalProps
> = (props) => {
const [isModalOpen, setModalOpen] = React.useState(false);
const { systemPrompt, setSystemPrompt } = props;

const handleModalToggle = (_event: KeyboardEvent | React.MouseEvent) => {
setModalOpen(!isModalOpen);
};

const handleSystemPromptInputChange = (_event: any, value: string) => {
setSystemPrompt(value);
};

return (
<React.Fragment>
<Button
variant="link"
aria-label="SystemPrompt"
icon={<WrenchIcon />}
onClick={handleModalToggle}
></Button>
<Modal
variant={ModalVariant.small}
isOpen={isModalOpen}
onClose={handleModalToggle}
aria-labelledby="system-prompt-form-title"
aria-describedby="system-prompt-description-form"
>
<ModalHeader
title="System prompt"
description="Enter a system prompt to override the default one."
descriptorId="system-prompt-description-form"
labelId="system-prompt-form-title"
/>
<ModalBody>
<Form id="system-prompt-form">
<FormGroup label="System Prompt" isRequired fieldId="system-prompt">
<TextArea
isRequired
id="system-prompt"
name="system-prompt"
value={systemPrompt}
onChange={handleSystemPromptInputChange}
aria-label="system-prompt-form-text-area"
rows={15}
/>
</FormGroup>
</Form>
</ModalBody>
<ModalFooter>
<Button
key="create"
variant="primary"
form="system-prompt-form"
onClick={handleModalToggle}
aria-label="system-prompt-form-button"
>
Close
</Button>
</ModalFooter>
</Modal>
</React.Fragment>
);
};
SystemPromptModal.displayName = "SystemPromptModal";
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions ansible_ai_connect_chatbot/src/types/Message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type LLMRequest = {
provider?: string | null;
model?: string | null;
attachments?: object[] | null;
system_prompt?: string | null;
};

type LLMResponse = {
Expand Down
8 changes: 8 additions & 0 deletions ansible_ai_connect_chatbot/src/useChatbot/useChatbot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import userLogo from "../assets/user_logo.png";
import {
API_TIMEOUT,
GITHUB_NEW_ISSUE_BASE_URL,
QUERY_SYSTEM_INSTRUCTION,
Sentiment,
TIMEOUT_MSG,
TOO_MANY_REQUESTS_MSG,
Expand Down Expand Up @@ -145,6 +146,7 @@ export const useChatbot = () => {
string | null | undefined
>(undefined);
const [selectedModel, setSelectedModel] = useState("granite3-8b");
const [systemPrompt, setSystemPrompt] = useState(QUERY_SYSTEM_INSTRUCTION);

const addMessage = (
newMessage: ExtendedMessage,
Expand Down Expand Up @@ -293,6 +295,10 @@ export const useChatbot = () => {
query: message,
};

if (systemPrompt !== QUERY_SYSTEM_INSTRUCTION) {
chatRequest.system_prompt = systemPrompt;
}

if (inDebugMode()) {
for (const m of modelsSupported) {
if (selectedModel === m.model) {
Expand Down Expand Up @@ -373,5 +379,7 @@ export const useChatbot = () => {
selectedModel,
setSelectedModel,
setConversationId,
systemPrompt,
setSystemPrompt,
};
};

0 comments on commit 5f271e6

Please sign in to comment.