diff --git a/ee/app/assets/javascripts/ai/components/ai_genie_chat.vue b/ee/app/assets/javascripts/ai/components/ai_genie_chat.vue
index b28e3b9e7bc93f4aa01e591236af8390ae7c54d1..24ae0e0bcaf68f98e6308ba41003d7bc1452933e 100644
--- a/ee/app/assets/javascripts/ai/components/ai_genie_chat.vue
+++ b/ee/app/assets/javascripts/ai/components/ai_genie_chat.vue
@@ -12,11 +12,12 @@ import {
   GlFormText,
 } from '@gitlab/ui';
 import { throttle } from 'lodash';
-import { renderMarkdown } from '~/notes/utils';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
 import SafeHtml from '~/vue_shared/directives/safe_html';
-import { i18n, GENIE_CHAT_MODEL_ROLES } from '../constants';
+import { i18n, GENIE_CHAT_RESET_MESSAGE } from '../constants';
 import AiGenieLoader from './ai_genie_loader.vue';
 import AiPredefinedPrompts from './ai_predefined_prompts.vue';
+import AiGenieChatConversation from './ai_genie_chat_conversation.vue';
 
 export default {
   name: 'AiGenieChat',
@@ -32,10 +33,12 @@ export default {
     GlFormText,
     AiGenieLoader,
     AiPredefinedPrompts,
+    AiGenieChatConversation,
   },
   directives: {
     SafeHtml,
   },
+  mixins: [glFeatureFlagMixin()],
   props: {
     messages: {
       type: Array,
@@ -82,27 +85,46 @@ export default {
     hasMessages() {
       return this.messages.length > 0;
     },
+    conversations() {
+      if (!this.hasMessages) {
+        return [];
+      }
+
+      let conversationIndex = 0;
+      const conversations = [[]];
+
+      this.messages.forEach((message) => {
+        if (message.content === GENIE_CHAT_RESET_MESSAGE) {
+          conversationIndex += 1;
+          conversations[conversationIndex] = [];
+        } else {
+          conversations[conversationIndex].push(message);
+        }
+      });
+
+      return conversations;
+    },
+    resetDisabled() {
+      if (this.isLoading || !this.hasMessages) {
+        return true;
+      }
+
+      const lastMessage = this.messages[this.messages.length - 1];
+      return lastMessage.content === GENIE_CHAT_RESET_MESSAGE;
+    },
   },
   watch: {
-    async isLoading() {
+    isLoading() {
       this.isHidden = false;
-      await this.$nextTick();
-      if (this.$refs.lastMessage?.length) {
-        this.$refs.lastMessage
-          .at(0)
-          .scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' });
-      }
+      this.scrollToBottom();
     },
-    messages() {
+    async messages() {
+      await this.$nextTick();
       this.prompt = '';
     },
   },
-  async mounted() {
-    await this.$nextTick();
-
-    if (this.$refs.drawer) {
-      this.$refs.drawer.scrollTop = this.$refs.drawer.scrollHeight;
-    }
+  mounted() {
+    this.scrollToBottom();
   },
   methods: {
     hideChat() {
@@ -111,6 +133,9 @@ export default {
     },
     sendChatPrompt() {
       if (this.prompt) {
+        if (this.prompt === GENIE_CHAT_RESET_MESSAGE && this.resetDisabled) {
+          return;
+        }
         this.$emit('send-chat-prompt', this.prompt);
       }
     },
@@ -118,27 +143,18 @@ export default {
       this.prompt = prompt;
       this.sendChatPrompt();
     },
-    getPromptLocation(index) {
-      return index ? 'after_content' : 'before_content';
-    },
-    isLastMessage(index) {
-      return index === this.messages.length - 1;
-    },
-    isAssistantMessage(message) {
-      return message.role.toLowerCase() === GENIE_CHAT_MODEL_ROLES.assistant;
-    },
-    isUserMessage(message) {
-      return message.role.toLowerCase() === GENIE_CHAT_MODEL_ROLES.user;
-    },
-    getMessageContent(message) {
-      return renderMarkdown(message.content || message.errors[0]);
-    },
     handleScrolling: throttle(function handleScrollingDebounce() {
       const { scrollTop, offsetHeight, scrollHeight } = this.$refs.drawer;
 
       this.scrolledToBottom = scrollTop + offsetHeight >= scrollHeight;
     }),
-    renderMarkdown,
+    async scrollToBottom() {
+      await this.$nextTick();
+
+      if (this.$refs.drawer) {
+        this.$refs.drawer.scrollTop = this.$refs.drawer.scrollHeight;
+      }
+    },
   },
   i18n,
 };
@@ -207,32 +223,20 @@ export default {
             },
           ]"
         >
-          <template v-if="hasMessages || isLoading">
-            <div
-              v-for="(message, index) in messages"
-              :key="`${message.role}-${index}`"
-              :ref="isLastMessage(index) ? 'lastMessage' : undefined"
-              class="gl-py-3 gl-px-4 gl-mb-4 gl-rounded-lg gl-line-height-20 ai-genie-chat-message"
-              :class="{
-                'gl-ml-auto gl-bg-blue-100 gl-text-blue-900 gl-rounded-bottom-right-none': isUserMessage(
-                  message,
-                ),
-                'gl-rounded-bottom-left-none gl-text-gray-900 gl-bg-gray-50': isAssistantMessage(
-                  message,
-                ),
-                'gl-mb-0!': isLastMessage(index) && !isLoading,
-              }"
-            >
-              <div v-safe-html="getMessageContent(message)"></div>
-              <slot
-                v-if="isAssistantMessage(message)"
-                name="feedback"
-                :prompt-location="getPromptLocation(index)"
-                :message="message"
-              ></slot>
-            </div>
-          </template>
-          <template v-else>
+          <ai-genie-chat-conversation
+            v-for="(conversation, index) in conversations"
+            :key="`conversation-${index}`"
+            :messages="conversation"
+            :is-loading="isLoading"
+            :show-delimiter="index > 0"
+            class="gl-display-flex gl-flex-direction-column gl-justify-content-end"
+          >
+            <template #feedback="{ message, promptLocation }">
+              <slot name="feedback" :prompt-location="promptLocation" :message="message"></slot>
+            </template>
+          </ai-genie-chat-conversation>
+
+          <template v-if="!hasMessages && !isLoading">
             <div key="empty-state" class="gl-display-flex gl-flex-grow-1">
               <gl-empty-state
                 :svg-path="emptySvgPath"
@@ -270,7 +274,7 @@ export default {
       class="gl-drawer-footer gl-drawer-footer-sticky gl-p-5 gl-border-t gl-bg-white"
       :class="{ 'gl-drawer-body-scrim-on-footer': !scrolledToBottom }"
     >
-      <gl-form @submit.stop.prevent="sendChatPrompt">
+      <gl-form data-testid="chat-prompt-form" @submit.stop.prevent="sendChatPrompt">
         <gl-form-input-group>
           <div
             class="ai-genie-chat-input gl-flex-grow-1 gl-vertical-align-top gl-max-w-full gl-min-h-8 gl-inset-border-1-gray-400 gl-rounded-base"
diff --git a/ee/app/assets/javascripts/ai/components/ai_genie_chat_conversation.vue b/ee/app/assets/javascripts/ai/components/ai_genie_chat_conversation.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e18d59c20f63c6bb37ed9f9ccb53694bff352e24
--- /dev/null
+++ b/ee/app/assets/javascripts/ai/components/ai_genie_chat_conversation.vue
@@ -0,0 +1,84 @@
+<script>
+import { renderMarkdown } from '~/notes/utils';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import { GENIE_CHAT_MODEL_ROLES, i18n } from '../constants';
+
+export default {
+  name: 'AiGenieChatConversation',
+  directives: {
+    SafeHtml,
+  },
+  props: {
+    messages: {
+      type: Array,
+      required: false,
+      default: () => [],
+    },
+    isLoading: {
+      type: Boolean,
+      required: false,
+      default: false,
+    },
+    showDelimiter: {
+      type: Boolean,
+      required: false,
+      default: true,
+    },
+  },
+  methods: {
+    isLastMessage(index) {
+      return index === this.messages.length - 1;
+    },
+    isAssistantMessage(message) {
+      return message.role.toLowerCase() === GENIE_CHAT_MODEL_ROLES.assistant;
+    },
+    isUserMessage(message) {
+      return message.role.toLowerCase() === GENIE_CHAT_MODEL_ROLES.user;
+    },
+    getMessageContent(message) {
+      return renderMarkdown(message.content || message.errors[0]);
+    },
+    getPromptLocation(index) {
+      return index ? 'after_content' : 'before_content';
+    },
+    renderMarkdown,
+  },
+  i18n,
+};
+</script>
+<template>
+  <div class="gl-my-5">
+    <template v-if="showDelimiter">
+      <div
+        class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-gap-4 gl-mb-5 gl-mt-n5"
+        data-testid="conversation-delimiter"
+      >
+        <hr class="gl-my-5 gl-flex-grow-1" />
+        <span>{{ $options.i18n.GENIE_CHAT_NEW_CHAT }}</span>
+        <hr class="gl-my-5 gl-flex-grow-1" />
+      </div>
+    </template>
+
+    <div
+      v-for="(message, index) in messages"
+      :key="`${message.role}-${index}`"
+      :ref="isLastMessage(index) ? 'lastMessage' : undefined"
+      class="gl-py-3 gl-px-4 gl-mb-4 gl-rounded-lg gl-line-height-20 ai-genie-chat-message"
+      :class="{
+        'gl-ml-auto gl-bg-blue-100 gl-text-blue-900 gl-rounded-bottom-right-none': isUserMessage(
+          message,
+        ),
+        'gl-rounded-bottom-left-none gl-text-gray-900 gl-bg-gray-50': isAssistantMessage(message),
+        'gl-mb-0!': isLastMessage(index) && !isLoading,
+      }"
+    >
+      <div v-safe-html="getMessageContent(message)"></div>
+      <slot
+        v-if="isAssistantMessage(message)"
+        name="feedback"
+        :prompt-location="getPromptLocation(index)"
+        :message="message"
+      ></slot>
+    </div>
+  </div>
+</template>
diff --git a/ee/app/assets/javascripts/ai/constants.js b/ee/app/assets/javascripts/ai/constants.js
index 43a5cdc290d672fac97bd64c53884b273f919895..dc1171d2070f7ab1fd9840604b36d8c23acb31b3 100644
--- a/ee/app/assets/javascripts/ai/constants.js
+++ b/ee/app/assets/javascripts/ai/constants.js
@@ -28,6 +28,7 @@ export const i18n = {
   GENIE_CHAT_LEGAL_DISCLAIMER: s__(
     "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data.",
   ),
+  GENIE_CHAT_NEW_CHAT: s__('AI|New chat'),
 };
 export const TOO_LONG_ERROR_TYPE = 'too-long';
 export const AI_GENIE_DEBOUNCE = 300;
@@ -56,3 +57,4 @@ export const FEEDBACK_OPTIONS = [
 ];
 
 export const EXPLAIN_CODE_TRACKING_EVENT_NAME = 'explain_code_blob_viewer';
+export const GENIE_CHAT_RESET_MESSAGE = '/reset';
diff --git a/ee/app/assets/javascripts/ai/tanuki_bot/components/app.vue b/ee/app/assets/javascripts/ai/tanuki_bot/components/app.vue
index 3cfc7809038e2a12a403e99c8be8dc6210c63e16..b0ab01efb730eb040ff7340c42f8079fd7e71bdf 100644
--- a/ee/app/assets/javascripts/ai/tanuki_bot/components/app.vue
+++ b/ee/app/assets/javascripts/ai/tanuki_bot/components/app.vue
@@ -94,6 +94,7 @@ export default {
       'sendUserMessage',
       'receiveTanukiBotMessage',
       'tanukiBotMessageError',
+      'receiveMutationResponse',
       'setMessages',
     ]),
     sendMessage(question) {
@@ -107,6 +108,9 @@ export default {
             resourceId: this.resourceId || this.userId,
           },
         })
+        .then(({ data }) => {
+          this.receiveMutationResponse({ data, message: question });
+        })
         .catch(() => {
           this.tanukiBotMessageError();
         });
diff --git a/ee/app/assets/javascripts/ai/tanuki_bot/store/actions.js b/ee/app/assets/javascripts/ai/tanuki_bot/store/actions.js
index 533b4d6655ffcce5094c6015da07c662c7676ce6..d8d9a70447edc1b67b5e50f446945be64a63038d 100644
--- a/ee/app/assets/javascripts/ai/tanuki_bot/store/actions.js
+++ b/ee/app/assets/javascripts/ai/tanuki_bot/store/actions.js
@@ -1,4 +1,5 @@
 import { MESSAGE_TYPES } from '../constants';
+import { GENIE_CHAT_RESET_MESSAGE } from '../../constants';
 import * as types from './mutation_types';
 
 export const sendUserMessage = ({ commit }, msg) => {
@@ -6,6 +7,17 @@ export const sendUserMessage = ({ commit }, msg) => {
   commit(types.ADD_USER_MESSAGE, msg);
 };
 
+export const receiveMutationResponse = ({ commit }, { data, message }) => {
+  const hasErrors = data?.aiAction?.errors?.length > 0;
+
+  if (hasErrors) {
+    commit(types.SET_LOADING, false);
+    commit(types.ADD_ERROR_MESSAGE);
+  } else if (message === GENIE_CHAT_RESET_MESSAGE) {
+    commit(types.SET_LOADING, false);
+  }
+};
+
 export const receiveTanukiBotMessage = ({ commit, dispatch }, data) => {
   const response = data.aiCompletionResponse?.responseBody;
   const errors = data.aiCompletionResponse?.errors;
diff --git a/ee/lib/ee/gitlab/gon_helper.rb b/ee/lib/ee/gitlab/gon_helper.rb
index 8c731787555d05625fe1d27c65c350f69a97fef5..5eddf52d3efc607d843f589ae0b0260073b3d018 100644
--- a/ee/lib/ee/gitlab/gon_helper.rb
+++ b/ee/lib/ee/gitlab/gon_helper.rb
@@ -29,6 +29,8 @@ def add_gon_variables
           gon.registration_validation_form_url = ::Gitlab::Routing.url_helpers
                                                                   .subscription_portal_registration_validation_form_url
         end
+
+        push_frontend_feature_flag(:ai_chat_history_context, current_user)
       end
 
       # Exposes if a licensed feature is available.
diff --git a/ee/spec/frontend/ai/components/ai_genie_chat_conversation_spec.js b/ee/spec/frontend/ai/components/ai_genie_chat_conversation_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..4f349ef24f6d77a155a00b5f2503db302045ffb5
--- /dev/null
+++ b/ee/spec/frontend/ai/components/ai_genie_chat_conversation_spec.js
@@ -0,0 +1,112 @@
+import AiGenieChatConversation from 'ee/ai/components/ai_genie_chat_conversation.vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { GENIE_CHAT_MODEL_ROLES } from 'ee/ai/constants';
+
+describe('AiGenieChat', () => {
+  let wrapper;
+
+  const promptStr = 'foo';
+  const messages = [
+    {
+      role: GENIE_CHAT_MODEL_ROLES.user,
+      content: promptStr,
+    },
+  ];
+
+  const findChatMessages = () => wrapper.findAll('.ai-genie-chat-message');
+  const findDelimiter = () => wrapper.findByTestId('conversation-delimiter');
+  const createComponent = ({ propsData = {}, data = {}, scopedSlots = {}, slots = {} } = {}) => {
+    wrapper = shallowMountExtended(AiGenieChatConversation, {
+      propsData,
+      data() {
+        return {
+          ...data,
+        };
+      },
+      scopedSlots,
+      slots,
+    });
+  };
+
+  describe('rendering', () => {
+    it('renders messages when messages are passed', () => {
+      createComponent({ propsData: { messages } });
+      expect(findChatMessages().at(0).text()).toBe(messages[0].content);
+    });
+
+    it('renders delimiter when showDelimiter = true', () => {
+      createComponent({ propsData: { messages, showDelimiter: true } });
+      expect(findDelimiter().exists()).toBe(true);
+    });
+
+    it('does not render delimiter when showDelimiter = false', () => {
+      createComponent({ propsData: { messages, showDelimiter: false } });
+      expect(findDelimiter().exists()).toBe(false);
+    });
+
+    it('converts content of the message from Markdown into HTML', () => {
+      createComponent({
+        propsData: {
+          messages: [
+            {
+              role: GENIE_CHAT_MODEL_ROLES.user,
+              content: '**foo**',
+            },
+          ],
+        },
+      });
+      expect(findChatMessages().at(0).element.innerHTML).toContain('<strong>foo</strong>');
+    });
+  });
+
+  describe('slots', () => {
+    const slotContent = 'As Gregor Samsa awoke one morning from uneasy dreams';
+
+    describe('the feedback slot', () => {
+      const slotElement = `<template>${slotContent}</template>`;
+
+      it.each(['assistant', 'ASSISTANT'])(
+        'renders the content passed to the "feedback" slot when role is %s',
+        (role) => {
+          createComponent({
+            propsData: {
+              messages: [
+                {
+                  role: GENIE_CHAT_MODEL_ROLES.user,
+                  content: 'User foo',
+                },
+                {
+                  role,
+                  content: 'Assistent bar',
+                },
+              ],
+            },
+            scopedSlots: { feedback: slotElement },
+          });
+          expect(findChatMessages().at(0).text()).not.toContain(slotContent);
+          expect(findChatMessages().at(1).text()).toContain(slotContent);
+        },
+      );
+
+      it('sends correct `message` in the `slotProps` for the components users to consume', () => {
+        createComponent({
+          propsData: {
+            messages: [
+              {
+                role: GENIE_CHAT_MODEL_ROLES.assistant,
+                content: slotContent,
+              },
+            ],
+          },
+          scopedSlots: {
+            feedback: `<template #feedback="slotProps">
+              Hello {{ slotProps.message.content }}
+              </template>
+            `,
+          },
+        });
+        expect(wrapper.text()).toContain(`Hello ${slotContent}`);
+      });
+    });
+  });
+});
diff --git a/ee/spec/frontend/ai/components/ai_genie_chat_spec.js b/ee/spec/frontend/ai/components/ai_genie_chat_spec.js
index 740aa2eac3aa5280f702eb587ab1cb610bccc0bd..6c99213c87e012c6a27eef551f31898d2ca54fd9 100644
--- a/ee/spec/frontend/ai/components/ai_genie_chat_spec.js
+++ b/ee/spec/frontend/ai/components/ai_genie_chat_spec.js
@@ -1,15 +1,23 @@
-import { GlEmptyState, GlButton, GlBadge } from '@gitlab/ui';
+import { GlEmptyState, GlBadge } from '@gitlab/ui';
 import { nextTick } from 'vue';
 import AiGenieLoader from 'ee/ai/components/ai_genie_loader.vue';
 import AiGenieChat from 'ee/ai/components/ai_genie_chat.vue';
+import AiGenieChatConversation from 'ee/ai/components/ai_genie_chat_conversation.vue';
 import AiPredefinedPrompts from 'ee/ai/components/ai_predefined_prompts.vue';
 import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { i18n, GENIE_CHAT_MODEL_ROLES } from 'ee/ai/constants';
+import waitForPromises from 'helpers/wait_for_promises';
+import { i18n, GENIE_CHAT_MODEL_ROLES, GENIE_CHAT_RESET_MESSAGE } from 'ee/ai/constants';
 
 describe('AiGenieChat', () => {
   let wrapper;
 
-  const createComponent = ({ propsData = {}, data = {}, scopedSlots = {}, slots = {} } = {}) => {
+  const createComponent = ({
+    propsData = {},
+    data = {},
+    scopedSlots = {},
+    slots = {},
+    glFeatures = { aiChatHistoryContext: true },
+  } = {}) => {
     wrapper = shallowMountExtended(AiGenieChat, {
       propsData,
       data() {
@@ -22,15 +30,19 @@ describe('AiGenieChat', () => {
       stubs: {
         AiGenieLoader,
       },
+      provide: {
+        glFeatures,
+      },
     });
   };
 
   const findChatComponent = () => wrapper.findByTestId('chat-component');
-  const findCloseButton = () => wrapper.findComponent(GlButton);
+  const findCloseButton = () => wrapper.findByTestId('chat-close-button');
+  const findChatConversations = () => wrapper.findAllComponents(AiGenieChatConversation);
   const findCustomLoader = () => wrapper.findComponent(AiGenieLoader);
-  const findChatMessages = () => wrapper.findAll('.ai-genie-chat-message');
   const findError = () => wrapper.findByTestId('chat-error');
   const findFooter = () => wrapper.findByTestId('chat-footer');
+  const findPromptForm = () => wrapper.findByTestId('chat-prompt-form');
   const findGeneratedByAI = () => wrapper.findByText(i18n.GENIE_CHAT_LEGAL_GENERATED_BY_AI);
   const findBadge = () => wrapper.findComponent(GlBadge);
   const findEmptyState = () => wrapper.findComponent(GlEmptyState);
@@ -78,55 +90,56 @@ describe('AiGenieChat', () => {
       });
     });
 
-    describe('slots', () => {
-      const slotContent = 'As Gregor Samsa awoke one morning from uneasy dreams';
+    describe('conversations', () => {
+      it('renders one conversation when no reset message is present', () => {
+        const newMessages = [
+          {
+            role: GENIE_CHAT_MODEL_ROLES.user,
+            content: 'How are you?',
+          },
+          {
+            role: GENIE_CHAT_MODEL_ROLES.assistant,
+            content: 'Great!',
+          },
+        ];
+        createComponent({ propsData: { messages: newMessages } });
+
+        expect(findChatConversations().length).toEqual(1);
+        expect(findChatConversations().at(0).props('showDelimiter')).toEqual(false);
+      });
+
+      it('renders one conversation when no message is present', () => {
+        const newMessages = [];
+        createComponent({ propsData: { messages: newMessages } });
+
+        expect(findChatConversations().length).toEqual(0);
+      });
 
-      describe('the feedback slot', () => {
-        const slotElement = `<template>${slotContent}</template>`;
-
-        it.each(['assistant', 'ASSISTANT'])(
-          'renders the content passed to the "feedback" slot when role is %s',
-          (role) => {
-            createComponent({
-              propsData: {
-                messages: [
-                  {
-                    role: GENIE_CHAT_MODEL_ROLES.user,
-                    content: 'User foo',
-                  },
-                  {
-                    role,
-                    content: 'Assistent bar',
-                  },
-                ],
-              },
-              scopedSlots: { feedback: slotElement },
-            });
-            expect(findChatMessages().at(0).text()).not.toContain(slotContent);
-            expect(findChatMessages().at(1).text()).toContain(slotContent);
+      it('splits it up into multiple conversations when reset message is present', () => {
+        const newMessages = [
+          {
+            role: GENIE_CHAT_MODEL_ROLES.user,
+            content: 'Message 1',
           },
-        );
+          {
+            role: GENIE_CHAT_MODEL_ROLES.assistant,
+            content: 'Great!',
+          },
+          {
+            role: GENIE_CHAT_MODEL_ROLES.user,
+            content: GENIE_CHAT_RESET_MESSAGE,
+          },
+        ];
+        createComponent({ propsData: { messages: newMessages } });
 
-        it('sends correct `message` in the `slotProps` for the components users to consume', () => {
-          createComponent({
-            propsData: {
-              messages: [
-                {
-                  role: GENIE_CHAT_MODEL_ROLES.assistant,
-                  content: slotContent,
-                },
-              ],
-            },
-            scopedSlots: {
-              feedback: `<template #feedback="slotProps">
-              Hello {{ slotProps.message.content }}
-              </template>
-            `,
-            },
-          });
-          expect(wrapper.text()).toContain(`Hello ${slotContent}`);
-        });
+        expect(findChatConversations().length).toEqual(2);
+        expect(findChatConversations().at(0).props('showDelimiter')).toEqual(false);
+        expect(findChatConversations().at(1).props('showDelimiter')).toEqual(true);
       });
+    });
+
+    describe('slots', () => {
+      const slotContent = 'As Gregor Samsa awoke one morning from uneasy dreams';
 
       it.each`
         desc                 | slot           | content        | isChatAvailable | shouldRenderSlotContent
@@ -159,6 +172,89 @@ describe('AiGenieChat', () => {
     });
   });
 
+  describe('chat', () => {
+    it('does not render prompt input by default', () => {
+      createComponent({ propsData: { messages } });
+      expect(findChatInput().exists()).toBe(false);
+    });
+
+    it('renders prompt input if `isChatAvailable` prop is `true`', () => {
+      createComponent({ propsData: { messages, isChatAvailable: true } });
+      expect(findChatInput().exists()).toBe(true);
+    });
+
+    it('renders the legal disclaimer if `isChatAvailable` prop is `true', () => {
+      createComponent({ propsData: { messages, isChatAvailable: true } });
+      expect(findLegalDisclaimer().exists()).toBe(true);
+    });
+
+    describe('reset', () => {
+      const clickSubmit = () =>
+        findPromptForm().vm.$emit('submit', {
+          preventDefault: jest.fn(),
+          stopPropagation: jest.fn(),
+        });
+
+      it('emits the event with the reset prompt', () => {
+        createComponent({
+          propsData: { messages, isChatAvailable: true },
+          data: { prompt: GENIE_CHAT_RESET_MESSAGE },
+        });
+        clickSubmit();
+
+        expect(wrapper.emitted('send-chat-prompt')).toEqual([[GENIE_CHAT_RESET_MESSAGE]]);
+        expect(findChatConversations().length).toEqual(1);
+      });
+
+      it('reset does nothing when chat is loading', () => {
+        createComponent({
+          propsData: { messages, isChatAvailable: true, isLoading: true },
+          data: { prompt: GENIE_CHAT_RESET_MESSAGE },
+        });
+        clickSubmit();
+
+        expect(wrapper.emitted('send-chat-prompt')).toBeUndefined();
+        expect(findChatConversations().length).toEqual(1);
+      });
+
+      it('reset does nothing when there are no messages', () => {
+        createComponent({
+          propsData: { messages: [], isChatAvailable: true },
+          data: { prompt: GENIE_CHAT_RESET_MESSAGE },
+        });
+        clickSubmit();
+
+        expect(wrapper.emitted('send-chat-prompt')).toBeUndefined();
+        expect(findChatConversations().length).toEqual(0);
+      });
+
+      it('reset does nothing when last message was a reset message', () => {
+        const existingMessages = [
+          ...messages,
+          {
+            role: GENIE_CHAT_MODEL_ROLES.user,
+            content: GENIE_CHAT_RESET_MESSAGE,
+          },
+        ];
+        createComponent({
+          propsData: {
+            isLoading: false,
+            messages: existingMessages,
+            isChatAvailable: true,
+          },
+          data: { prompt: GENIE_CHAT_RESET_MESSAGE },
+        });
+        clickSubmit();
+
+        expect(wrapper.emitted('send-chat-prompt')).toBeUndefined();
+
+        expect(findChatConversations().length).toEqual(2);
+        expect(findChatConversations().at(0).props('messages')).toEqual(messages);
+        expect(findChatConversations().at(1).props('messages')).toEqual([]);
+      });
+    });
+  });
+
   describe('interaction', () => {
     it('is hidden after the header button is clicked', async () => {
       findCloseButton().vm.$emit('click');
@@ -179,6 +275,20 @@ describe('AiGenieChat', () => {
       expect(findChatComponent().exists()).toBe(true);
     });
 
+    it('resets the prompt when new messages are added', async () => {
+      const prompt = 'foo';
+      createComponent({ propsData: { isChatAvailable: true }, data: { prompt } });
+      expect(findChatInput().props('value')).toBe(prompt);
+      // setProps is justified here because we are testing the component's
+      // reactive behavior which consistutes an exception
+      // See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
+      wrapper.setProps({
+        messages,
+      });
+      await waitForPromises();
+      expect(findChatInput().props('value')).toBe('');
+    });
+
     it('renders custom loader when isLoading', () => {
       createComponent({ propsData: { isLoading: true } });
       expect(findCustomLoader().exists()).toBe(true);
@@ -190,25 +300,6 @@ describe('AiGenieChat', () => {
       expect(findError().text()).toBe(errorMessage);
     });
 
-    it('renders messages when messages are passed', () => {
-      createComponent({ propsData: { messages } });
-      expect(findChatMessages().at(0).text()).toBe(promptStr);
-    });
-
-    it('converts content of the message from Markdown into HTML', () => {
-      createComponent({
-        propsData: {
-          messages: [
-            {
-              role: GENIE_CHAT_MODEL_ROLES.user,
-              content: '**foo**',
-            },
-          ],
-        },
-      });
-      expect(findChatMessages().at(0).element.innerHTML).toContain('<strong>foo</strong>');
-    });
-
     it('hides the chat on button click and emits an event', () => {
       createComponent({ propsData: { messages } });
       expect(wrapper.vm.$data.isHidden).toBe(false);
@@ -222,23 +313,6 @@ describe('AiGenieChat', () => {
       expect(findEmptyState().exists()).toBe(false);
     });
 
-    describe('chat', () => {
-      it('does not render prompt input by default', () => {
-        createComponent({ propsData: { messages } });
-        expect(findChatInput().exists()).toBe(false);
-      });
-
-      it('renders prompt input if `isChatAvailable` prop is `true`', () => {
-        createComponent({ propsData: { messages, isChatAvailable: true } });
-        expect(findChatInput().exists()).toBe(true);
-      });
-
-      it('renders the legal disclaimer if `isChatAvailable` prop is `true', () => {
-        createComponent({ propsData: { messages, isChatAvailable: true } });
-        expect(findLegalDisclaimer().exists()).toBe(true);
-      });
-    });
-
     describe('scrolling', () => {
       let element;
 
diff --git a/ee/spec/frontend/ai/components/ai_genie_spec.js b/ee/spec/frontend/ai/components/ai_genie_spec.js
index 6ebf9b6a3049f9e7eef95232df8a0cb0aa345d4c..eecedf7d9a7c456a798ff75fd804dc35c9f1a775 100644
--- a/ee/spec/frontend/ai/components/ai_genie_spec.js
+++ b/ee/spec/frontend/ai/components/ai_genie_spec.js
@@ -5,6 +5,7 @@ import waitForPromises from 'helpers/wait_for_promises';
 import createMockApollo from 'helpers/mock_apollo_helper';
 import AiGenie from 'ee/ai/components/ai_genie.vue';
 import AiGenieChat from 'ee/ai/components/ai_genie_chat.vue';
+import AiGenieChatConversation from 'ee/ai/components/ai_genie_chat_conversation.vue';
 import CodeBlockHighlighted from '~/vue_shared/components/code_block_highlighted.vue';
 import UserFeedback from 'ee/ai/components/user_feedback.vue';
 import { generateExplainCodePrompt, generateChatPrompt } from 'ee/ai/utils';
@@ -15,6 +16,7 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
 import explainCodeMutation from 'ee/ai/graphql/explain_code.mutation.graphql';
 import aiResponseSubscription from 'ee/graphql_shared/subscriptions/ai_completion_response.subscription.graphql';
 import LineHighlighter from '~/blob/line_highlighter';
+import { MOCK_USER_MESSAGE, MOCK_TANUKI_MESSAGE } from '../tanuki_bot/mock_data';
 
 const aiResponseFormatted = 'Formatted AI response';
 
@@ -76,7 +78,7 @@ describe('AiGenie', () => {
       },
       stubs: {
         AiGenieChat,
-        UserFeedback,
+        AiGenieChatConversation,
       },
       apolloProvider,
     });
@@ -84,8 +86,9 @@ describe('AiGenie', () => {
   const findButton = () => wrapper.findComponent(GlButton);
   const findGenieChat = () => wrapper.findComponent(AiGenieChat);
   const findCodeBlock = () => wrapper.findComponent(CodeBlockHighlighted);
-  const findUserFeedback = () => wrapper.findComponent(UserFeedback);
   const findLegalWarning = () => wrapper.findByTestId('chat-legal-warning-gitlab-usage');
+  const findAllUserFeedback = () => wrapper.findAllComponents(UserFeedback);
+
   const getRangeAtMock = (top = () => 0) => {
     return jest.fn((rangePosition) => {
       return {
@@ -377,20 +380,21 @@ describe('AiGenie', () => {
     });
   });
 
-  describe('UserFeedback', () => {
-    beforeEach(() => {
-      createComponent();
-    });
-    it('is rendered', async () => {
-      await simulateSelectText();
-      await requestExplanation();
-      expect(findUserFeedback().exists()).toBe(true);
+  it('renders the User Feedback component for every assistent mesage', () => {
+    createComponent({
+      data: {
+        // the first 2 messages will be ignored in the component
+        // as those normally represent the `system` and the first `user` prompts
+        // we don't care about those here, hence sending `undefined`
+        messages: [undefined, undefined, MOCK_USER_MESSAGE, MOCK_TANUKI_MESSAGE],
+      },
     });
-    it('receives expected props', async () => {
-      await simulateSelectText();
-      await requestExplanation();
-      expect(findUserFeedback().props('eventName')).toBe(EXPLAIN_CODE_TRACKING_EVENT_NAME);
-      expect(findUserFeedback().props('promptLocation')).toBe('before_content');
+
+    expect(findAllUserFeedback().length).toBe(1);
+
+    findAllUserFeedback().wrappers.forEach((component) => {
+      expect(component.props('eventName')).toBe(EXPLAIN_CODE_TRACKING_EVENT_NAME);
+      expect(component.props('promptLocation')).toBe('after_content');
     });
   });
 
diff --git a/ee/spec/frontend/ai/tanuki_bot/components/app_spec.js b/ee/spec/frontend/ai/tanuki_bot/components/app_spec.js
index 5896762fd0a64cfc51f66912ec80a87a685c1188..77346a4c55812f826709d5eb7967aaaf7e0f5063 100644
--- a/ee/spec/frontend/ai/tanuki_bot/components/app_spec.js
+++ b/ee/spec/frontend/ai/tanuki_bot/components/app_spec.js
@@ -4,6 +4,7 @@ import Vuex from 'vuex';
 import VueApollo from 'vue-apollo';
 import TanukiBotChatApp from 'ee/ai/tanuki_bot/components/app.vue';
 import AiGenieChat from 'ee/ai/components/ai_genie_chat.vue';
+import AiGenieChatConversation from 'ee/ai/components/ai_genie_chat_conversation.vue';
 import UserFeedback from 'ee/ai/components/user_feedback.vue';
 import { i18n } from 'ee/ai/constants';
 import { TANUKI_BOT_TRACKING_EVENT_NAME } from 'ee/ai/tanuki_bot/constants';
@@ -68,6 +69,7 @@ describe('GitLab Chat', () => {
       stubs: {
         AiGenieChat,
         GlSprintf,
+        AiGenieChatConversation,
       },
       provide: {
         glFeatures,
@@ -79,6 +81,7 @@ describe('GitLab Chat', () => {
   const findWarning = () => wrapper.findByTestId('chat-legal-warning');
   const findGenieChat = () => wrapper.findComponent(AiGenieChat);
   const findGeneratedByAI = () => wrapper.findByText(i18n.GENIE_CHAT_LEGAL_GENERATED_BY_AI);
+  const findAllUserFeedback = () => wrapper.findAllComponents(UserFeedback);
 
   describe('rendering', () => {
     beforeEach(() => {
@@ -160,15 +163,16 @@ describe('GitLab Chat', () => {
     });
 
     it('renders the User Feedback component for every assistent mesage', () => {
-      const getPromptLocationSpy = jest.spyOn(AiGenieChat.methods, 'getPromptLocation');
-      getPromptLocationSpy.mockReturnValue('foo');
       createComponent({
         messages: [MOCK_USER_MESSAGE, MOCK_TANUKI_MESSAGE, MOCK_USER_MESSAGE, MOCK_TANUKI_MESSAGE],
       });
-      const userFeedbackComponents = wrapper.findAllComponents(UserFeedback);
-      expect(userFeedbackComponents.length).toBe(2);
-      expect(userFeedbackComponents.at(0).props('eventName')).toBe(TANUKI_BOT_TRACKING_EVENT_NAME);
-      expect(userFeedbackComponents.at(0).props('promptLocation')).toBe('foo');
+
+      expect(findAllUserFeedback().length).toBe(2);
+
+      findAllUserFeedback().wrappers.forEach((component) => {
+        expect(component.props('eventName')).toBe(TANUKI_BOT_TRACKING_EVENT_NAME);
+        expect(component.props('promptLocation')).toBe('after_content');
+      });
     });
 
     describe('when input is submitted', () => {
diff --git a/ee/spec/frontend/ai/tanuki_bot/store/actions_spec.js b/ee/spec/frontend/ai/tanuki_bot/store/actions_spec.js
index c25f6ab2c6dfff9a75e9fb314660591643c8f0df..3b2ae4663740fa3c3bfa660801a06717e9fb2cda 100644
--- a/ee/spec/frontend/ai/tanuki_bot/store/actions_spec.js
+++ b/ee/spec/frontend/ai/tanuki_bot/store/actions_spec.js
@@ -2,6 +2,7 @@ import * as actions from 'ee/ai/tanuki_bot/store/actions';
 import * as types from 'ee/ai/tanuki_bot/store/mutation_types';
 import createState from 'ee/ai/tanuki_bot/store/state';
 import testAction from 'helpers/vuex_action_helper';
+import { GENIE_CHAT_RESET_MESSAGE } from 'ee/ai/constants';
 import {
   MOCK_USER_MESSAGE,
   MOCK_TANUKI_MESSAGE,
@@ -73,6 +74,32 @@ describe('TanukiBot Store Actions', () => {
     });
   });
 
+  describe('receiveMutationResponse', () => {
+    it('on success it should dispatch the correct mutations', () => {
+      return testAction({
+        action: actions.receiveMutationResponse,
+        payload: { data: { aiAction: { errors: [] } }, message: GENIE_CHAT_RESET_MESSAGE },
+        state,
+        expectedMutations: [{ type: types.SET_LOADING, payload: false }],
+      });
+    });
+
+    it('on error it should dispatch the correct mutations', () => {
+      return testAction({
+        action: actions.receiveMutationResponse,
+        payload: {
+          data: { aiAction: { errors: ['some error'] } },
+          message: GENIE_CHAT_RESET_MESSAGE,
+        },
+        state,
+        expectedMutations: [
+          { type: types.SET_LOADING, payload: false },
+          { type: types.ADD_ERROR_MESSAGE },
+        ],
+      });
+    });
+  });
+
   describe('tanukiBotMessageError', () => {
     it(`should dispatch the correct mutations`, () => {
       return testAction({
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 23f5ea037b4a1759b69bb5d032999d208b92f1c0..953f7ab913b8f28378d41054822ac1d4d18ac083 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -1962,6 +1962,9 @@ msgstr ""
 msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
 msgstr ""
 
+msgid "AI|New chat"
+msgstr ""
+
 msgid "AI|Populate issue description"
 msgstr ""