@gitlab/duo-ui 8.16.0 → 8.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/components/agentic_chat/agentic_duo_chat.js +1 -1
- package/dist/components/chat/components/duo_chat_header/duo_chat_header.js +2 -1
- package/dist/components/chat/duo_chat.js +4 -1
- package/dist/components/chat/markdown_renderer.js +18 -2
- package/dist/components/chat/mock_data.js +34 -2
- package/package.json +2 -2
- package/src/components/agentic_chat/agentic_duo_chat.vue +1 -1
- package/src/components/chat/components/duo_chat_header/duo_chat_header.vue +14 -1
- package/src/components/chat/duo_chat.vue +4 -0
- package/src/components/chat/markdown_renderer.js +21 -13
- package/src/components/chat/mock_data.js +34 -3
- package/translations.js +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## [8.16.2](https://gitlab.com/gitlab-org/duo-ui/compare/v8.16.1...v8.16.2) (2025-05-28)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* correct config option for DOMPurify ([5085b3c](https://gitlab.com/gitlab-org/duo-ui/commit/5085b3cc3e6c9e690aef7d2d35644076a9b7ea50))
|
|
7
|
+
* fixed nested code blocks ([1a1953a](https://gitlab.com/gitlab-org/duo-ui/commit/1a1953aab48ecaf72160be24f29f0be48ff79a7f))
|
|
8
|
+
|
|
9
|
+
## [8.16.1](https://gitlab.com/gitlab-org/duo-ui/compare/v8.16.0...v8.16.1) (2025-05-21)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* **chat:** Update Agentic Chat disclaimer ([8277327](https://gitlab.com/gitlab-org/duo-ui/commit/827732738f2dc7bf1f7e67a9ddb48593e291706f))
|
|
15
|
+
|
|
1
16
|
# [8.16.0](https://gitlab.com/gitlab-org/duo-ui/compare/v8.15.0...v8.16.0) (2025-05-14)
|
|
2
17
|
|
|
3
18
|
|
|
@@ -14,7 +14,7 @@ import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
|
|
|
14
14
|
const i18n = {
|
|
15
15
|
CHAT_DEFAULT_TITLE: translate('AgenticDuoChat.chatDefaultTitle', 'GitLab Duo Chat'),
|
|
16
16
|
CHAT_HISTORY_TITLE: translate('AgenticDuoChat.chatHistoryTitle', 'Chat history'),
|
|
17
|
-
CHAT_DISCLAMER: translate('AgenticDuoChat.chatDisclamer', 'Responses
|
|
17
|
+
CHAT_DISCLAMER: translate('AgenticDuoChat.chatDisclamer', 'Chat can autonomously change code. Responses and changes can be inaccurate. Review carefully.'),
|
|
18
18
|
CHAT_EMPTY_STATE_TITLE: translate('AgenticDuoChat.chatEmptyStateTitle', '👋 I am GitLab Duo Chat, your personal AI-powered assistant. How can I help you today?'),
|
|
19
19
|
CHAT_PROMPT_PLACEHOLDER_DEFAULT: translate('AgenticDuoChat.chatPromptPlaceholderDefault', 'GitLab Duo Chat'),
|
|
20
20
|
CHAT_PROMPT_PLACEHOLDER_WITH_COMMANDS: translate('AgenticDuoChat.chatPromptPlaceholderWithCommands', 'Type /help to learn more'),
|
|
@@ -9,6 +9,7 @@ const i18n = {
|
|
|
9
9
|
CHAT_NEW_LABEL: translate('DuoChat.chatNewLabel', 'New Chat'),
|
|
10
10
|
CHAT_NEW_TOOLTIP: translate('DuoChat.chatNewToolTip', 'New Chat'),
|
|
11
11
|
CHAT_HISTORY_TOOLTIP: translate('DuoChat.chatHistoryToolTip', 'Chat History'),
|
|
12
|
+
CHAT_BACK_TO_CHAT_TOOLTIP: translate('DuoChat.chatBackToChatToolTip', 'Back to Chat'),
|
|
12
13
|
CHAT_TITLE: translate('DuoChat.chatTitle', 'GitLab Duo Chat')
|
|
13
14
|
};
|
|
14
15
|
var script = {
|
|
@@ -75,7 +76,7 @@ var script = {
|
|
|
75
76
|
const __vue_script__ = script;
|
|
76
77
|
|
|
77
78
|
/* template */
|
|
78
|
-
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('header',{staticClass:"gl-border-b gl-bg-default gl-p-0 gl-shrink-0",attrs:{"data-testid":"chat-header"}},[_c('div',{staticClass:"drawer-title gl-flex gl-items-center gl-justify-start gl-p-5"},[(_vm.isMultithreaded && _vm.currentView === _vm.VIEW_TYPES.CHAT)?_c('gl-button',{directives:[{name:"gl-tooltip",rawName:"v-gl-tooltip"}],staticClass:"gl-mr-3",attrs:{"title":_vm.$options.i18n.CHAT_HISTORY_TOOLTIP,"data-testid":"
|
|
79
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('header',{staticClass:"gl-border-b gl-bg-default gl-p-0 gl-shrink-0",attrs:{"data-testid":"chat-header"}},[_c('div',{staticClass:"drawer-title gl-flex gl-items-center gl-justify-start gl-p-5"},[(_vm.isMultithreaded && _vm.activeThreadId && _vm.currentView === _vm.VIEW_TYPES.LIST)?_c('gl-button',{directives:[{name:"gl-tooltip",rawName:"v-gl-tooltip"}],staticClass:"gl-mr-3",attrs:{"title":_vm.$options.i18n.CHAT_BACK_TO_CHAT_TOOLTIP,"data-testid":"go-back-to-chat-button","category":"primary","size":"medium","icon":"go-back","aria-label":_vm.$options.i18n.CHAT_BACK_TO_CHAT_TOOLTIP},on:{"click":function($event){return _vm.$emit('go-back-to-chat')}}}):_vm._e(),_vm._v(" "),(_vm.isMultithreaded && _vm.currentView === _vm.VIEW_TYPES.CHAT)?_c('gl-button',{directives:[{name:"gl-tooltip",rawName:"v-gl-tooltip"}],staticClass:"gl-mr-3",attrs:{"title":_vm.$options.i18n.CHAT_HISTORY_TOOLTIP,"data-testid":"go-back-to-list-button","category":"primary","size":"medium","icon":"history","aria-label":_vm.$options.i18n.CHAT_BACK_LABEL},on:{"click":function($event){return _vm.$emit('go-back')}}}):_vm._e(),_vm._v(" "),(_vm.isMultithreaded && (_vm.activeThreadId || _vm.currentView === _vm.VIEW_TYPES.LIST))?_c('gl-button',{directives:[{name:"gl-tooltip",rawName:"v-gl-tooltip"}],staticClass:"gl-mr-3",attrs:{"title":_vm.$options.i18n.CHAT_NEW_TOOLTIP,"data-testid":"chat-new-button","category":"primary","size":"medium","icon":"duo-chat-new","aria-label":_vm.$options.i18n.CHAT_NEW_LABEL},on:{"click":function($event){return _vm.$emit('new-chat')}}}):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-flex-1 gl-overflow-hidden"},[_c('div',{staticClass:"gl-flex gl-items-center"},[_c('h3',{staticClass:"gl-my-0 gl-text-size-h2"},[_vm._v(_vm._s(_vm.title))]),_vm._v(" "),(_vm.badgeType)?_c('gl-experiment-badge',{attrs:{"type":_vm.badgeType,"container-id":"chat-component"}}):_vm._e()],1),_vm._v(" "),(_vm.subtitle)?_c('h4',{staticClass:"gl-text-base gl-whitespace-nowrap gl-overflow-hidden gl-text-ellipsis gl-font-normal text-muted gl-mb-0",attrs:{"data-testid":"chat-subtitle"}},[_vm._v("\n "+_vm._s(_vm.subtitle)+"\n ")]):_vm._e()]),_vm._v(" "),_c('gl-button',{staticClass:"gl-ml-auto",attrs:{"category":"tertiary","variant":"default","icon":"close","size":"small","data-testid":"chat-close-button","aria-label":_vm.$options.i18n.CHAT_CLOSE_LABEL},on:{"click":function($event){return _vm.$emit('close')}}})],1),_vm._v(" "),_vm._t("subheader"),_vm._v(" "),(_vm.error)?_c('gl-alert',{key:"error",staticClass:"!gl-pl-9",attrs:{"dismissible":false,"variant":"danger","role":"alert","data-testid":"chat-error"}},[_c('span',{directives:[{name:"safe-html",rawName:"v-safe-html",value:(_vm.error),expression:"error"}]})]):_vm._e()],2)};
|
|
79
80
|
var __vue_staticRenderFns__ = [];
|
|
80
81
|
|
|
81
82
|
/* style */
|
|
@@ -392,6 +392,9 @@ var script = {
|
|
|
392
392
|
onGoBack() {
|
|
393
393
|
this.$emit('back-to-list');
|
|
394
394
|
},
|
|
395
|
+
onGoBackToChat() {
|
|
396
|
+
this.$emit('back-to-chat');
|
|
397
|
+
},
|
|
395
398
|
onNewChat() {
|
|
396
399
|
this.$emit('new-chat');
|
|
397
400
|
this.$nextTick(() => {
|
|
@@ -627,7 +630,7 @@ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=
|
|
|
627
630
|
},attrs:{"width":_vm.shouldRenderResizable ? _vm.dimensions.width : null,"height":_vm.shouldRenderResizable ? _vm.dimensions.height : null,"max-width":_vm.shouldRenderResizable ? _vm.dimensions.maxWidth : null,"max-height":_vm.shouldRenderResizable ? _vm.dimensions.maxHeight : null,"min-width":_vm.shouldRenderResizable ? _vm.dimensions.minWidth : null,"left":_vm.shouldRenderResizable ? _vm.dimensions.left : null,"top":_vm.shouldRenderResizable ? _vm.dimensions.top : null,"fit-parent":true,"min-height":_vm.shouldRenderResizable ? _vm.dimensions.minHeight : null,"active":_vm.shouldRenderResizable ? ['l', 't', 'lt'] : null},on:{"resize:end":_vm.updateSize}},[(!_vm.isHidden)?_c('aside',{staticClass:"markdown-code-block duo-chat gl-bottom-0 gl-max-h-full gl-flex gl-flex-col",class:{
|
|
628
631
|
'resizable-content': _vm.shouldRenderResizable,
|
|
629
632
|
'duo-chat-drawer': !_vm.shouldRenderResizable,
|
|
630
|
-
},attrs:{"id":"chat-component","role":"complementary","data-testid":"chat-component"}},[(_vm.showHeader)?_c('duo-chat-header',{ref:"header",attrs:{"active-thread-id":_vm.activeThreadId,"title":_vm.isMultithreaded && _vm.currentView === 'list' ? _vm.$options.i18n.CHAT_HISTORY_TITLE : _vm.title,"subtitle":_vm.activeThreadTitleForView,"is-multithreaded":_vm.isMultithreaded,"current-view":_vm.currentView,"should-render-resizable":_vm.shouldRenderResizable,"badge-type":_vm.isMultithreaded ? null : _vm.badgeType},on:{"go-back":_vm.onGoBack,"new-chat":_vm.onNewChat,"close":_vm.hideChat},scopedSlots:_vm._u([{key:"subheader",fn:function(){return [_vm._t("subheader")]},proxy:true}],null,true)}):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-overflow-y-auto gl-flex gl-flex-col gl-flex-1 gl-flex-grow gl-bg-inherit gl-overscroll-contain",attrs:{"data-testid":"chat-history"},on:{"scroll":_vm.handleScrollingThrottled}},[(_vm.shouldShowThreadList)?_c('duo-chat-threads',{attrs:{"threads":_vm.threadList,"preferred-locale":_vm.preferredLocale},on:{"new-chat":_vm.onNewChat,"select-thread":_vm.onSelectThread,"delete-thread":_vm.onDeleteThread,"close":_vm.hideChat}}):_c('transition-group',{staticClass:"duo-chat-history gl-p-5 gl-mt-auto",attrs:{"mode":"out-in","tag":"section","name":"message"}},[_vm._l((_vm.conversations),function(conversation,index){return _c('duo-chat-conversation',{key:("conversation-" + index),attrs:{"enable-code-insertion":_vm.enableCodeInsertion,"messages":conversation,"canceled-request-ids":_vm.canceledRequestIds,"show-delimiter":index > 0,"trusted-urls":_vm.trustedUrls},on:{"track-feedback":_vm.onTrackFeedback,"insert-code-snippet":_vm.onInsertCodeSnippet,"copy-code-snippet":_vm.onCopyCodeSnippet,"copy-message":_vm.onCopyMessage,"get-context-item-content":_vm.onGetContextItemContent,"open-file-path":_vm.onOpenFilePath}})}),_vm._v(" "),(!_vm.hasMessages && !_vm.isLoading)?[_c('div',{key:"empty-state-message",staticClass:"duo-chat-message gl-rounded-bl-none gl-border-1 gl-border-solid gl-border-gray-50 gl-bg-gray-10 gl-p-4 gl-leading-20 gl-text-gray-900 gl-break-anywhere",attrs:{"data-testid":"gl-duo-chat-empty-state"}},[(_vm.emptyStateTitle)?_c('p',{staticClass:"gl-m-0",attrs:{"data-testid":"gl-duo-chat-empty-state-title"}},[_vm._v("\n "+_vm._s(_vm.emptyStateTitle)+"\n ")]):_vm._e(),_vm._v(" "),_c('duo-chat-predefined-prompts',{key:"predefined-prompts",attrs:{"prompts":_vm.predefinedPrompts},on:{"click":_vm.sendPredefinedPrompt}})],1)]:_vm._e(),_vm._v(" "),(_vm.isLoading)?_c('duo-chat-loader',{key:"loader",attrs:{"tool-name":_vm.toolName}}):_vm._e(),_vm._v(" "),_c('div',{key:"anchor",ref:"anchor",staticClass:"scroll-anchor"})],2)],1),_vm._v(" "),(_vm.isChatAvailable && !_vm.shouldShowThreadList)?_c('footer',{staticClass:"duo-chat-drawer-footer gl-border-0 gl-bg-default gl-pb-3 gl-shrink-0 gl-relative gl-z-2",class:{ 'duo-chat-drawer-body-scrim-on-footer': !_vm.scrolledToBottom },attrs:{"data-testid":"chat-footer"}},[_c('gl-form',{attrs:{"data-testid":"chat-prompt-form"},on:{"submit":function($event){$event.stopPropagation();$event.preventDefault();return _vm.sendChatPrompt.apply(null, arguments)}}},[_c('div',{staticClass:"gl-relative gl-max-w-full"},[_vm._t("context-items-menu",null,{"isOpen":_vm.contextItemsMenuIsOpen,"onClose":_vm.closeContextItemsMenuOpen,"setRef":_vm.setContextItemsMenuRef,"focusPrompt":_vm.focusChatInput})],2),_vm._v(" "),_c('gl-form-input-group',{scopedSlots:_vm._u([{key:"append",fn:function(){return [(_vm.displaySubmitButton)?_c('gl-button',{staticClass:"!gl-absolute gl-bottom-2 gl-right-2 !gl-rounded-full",attrs:{"icon":"paper-airplane","category":"primary","variant":"confirm","type":"submit","data-testid":"chat-prompt-submit-button","aria-label":_vm.$options.i18n.CHAT_SUBMIT_LABEL}}):_c('gl-button',{staticClass:"!gl-absolute gl-bottom-2 gl-right-2 !gl-rounded-full",attrs:{"icon":"stop","category":"primary","variant":"default","data-testid":"chat-prompt-cancel-button","aria-label":_vm.$options.i18n.CHAT_CANCEL_LABEL},on:{"click":_vm.cancelPrompt}})]},proxy:true}],null,false,608602988)},[_c('div',{staticClass:"duo-chat-input gl-min-h-8 gl-max-w-full gl-grow gl-align-top",attrs:{"data-value":_vm.prompt}},[(_vm.shouldShowSlashCommands)?_c('gl-card',{ref:"commands",staticClass:"slash-commands !gl-absolute gl-w-full -gl-translate-y-full gl-list-none gl-pl-0 gl-shadow-md",attrs:{"body-class":"!gl-p-2"}},_vm._l((_vm.filteredSlashCommands),function(command,index){return _c('gl-dropdown-item',{key:command.name,class:{ 'active-command': index === _vm.activeCommandIndex },on:{"click":function($event){return _vm.selectSlashCommand(index)}},nativeOn:{"mouseenter":function($event){_vm.activeCommandIndex = index;}}},[_c('span',{staticClass:"gl-flex gl-justify-between"},[_c('span',{staticClass:"gl-block"},[_vm._v(_vm._s(command.name))]),_vm._v(" "),_c('small',{staticClass:"gl-pl-3 gl-text-right gl-italic gl-text-subtle"},[_vm._v(_vm._s(command.description))])])])}),1):_vm._e(),_vm._v(" "),_c('gl-form-textarea',{ref:"prompt",staticClass:"gl-absolute !gl-h-full gl-rounded-br-none gl-rounded-tr-none !gl-bg-transparent !gl-py-4 !gl-shadow-none",class:{ 'gl-truncate': !_vm.prompt },attrs:{"data-testid":"chat-prompt-input","placeholder":_vm.inputPlaceholder,"autofocus":""},on:{"compositionend":_vm.compositionEnd},nativeOn:{"keydown":function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"enter",13,$event.key,"Enter")){ return null; }if($event.ctrlKey||$event.shiftKey||$event.altKey||$event.metaKey){ return null; }$event.preventDefault();},"keyup":function($event){return _vm.onInputKeyup.apply(null, arguments)}},model:{value:(_vm.prompt),callback:function ($$v) {_vm.prompt=$$v;},expression:"prompt"}})],1)])],1),_vm._v(" "),_c('p',{staticClass:"gl-mb-0 gl-mt-3 gl-px-4 gl-text-sm gl-text-secondary"},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_DISCLAMER)+"\n ")])],1):_vm._e()],1):_vm._e()])};
|
|
633
|
+
},attrs:{"id":"chat-component","role":"complementary","data-testid":"chat-component"}},[(_vm.showHeader)?_c('duo-chat-header',{ref:"header",attrs:{"active-thread-id":_vm.activeThreadId,"title":_vm.isMultithreaded && _vm.currentView === 'list' ? _vm.$options.i18n.CHAT_HISTORY_TITLE : _vm.title,"subtitle":_vm.activeThreadTitleForView,"is-multithreaded":_vm.isMultithreaded,"current-view":_vm.currentView,"should-render-resizable":_vm.shouldRenderResizable,"badge-type":_vm.isMultithreaded ? null : _vm.badgeType},on:{"go-back":_vm.onGoBack,"go-back-to-chat":_vm.onGoBackToChat,"new-chat":_vm.onNewChat,"close":_vm.hideChat},scopedSlots:_vm._u([{key:"subheader",fn:function(){return [_vm._t("subheader")]},proxy:true}],null,true)}):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-overflow-y-auto gl-flex gl-flex-col gl-flex-1 gl-flex-grow gl-bg-inherit gl-overscroll-contain",attrs:{"data-testid":"chat-history"},on:{"scroll":_vm.handleScrollingThrottled}},[(_vm.shouldShowThreadList)?_c('duo-chat-threads',{attrs:{"threads":_vm.threadList,"preferred-locale":_vm.preferredLocale},on:{"new-chat":_vm.onNewChat,"select-thread":_vm.onSelectThread,"delete-thread":_vm.onDeleteThread,"close":_vm.hideChat}}):_c('transition-group',{staticClass:"duo-chat-history gl-p-5 gl-mt-auto",attrs:{"mode":"out-in","tag":"section","name":"message"}},[_vm._l((_vm.conversations),function(conversation,index){return _c('duo-chat-conversation',{key:("conversation-" + index),attrs:{"enable-code-insertion":_vm.enableCodeInsertion,"messages":conversation,"canceled-request-ids":_vm.canceledRequestIds,"show-delimiter":index > 0,"trusted-urls":_vm.trustedUrls},on:{"track-feedback":_vm.onTrackFeedback,"insert-code-snippet":_vm.onInsertCodeSnippet,"copy-code-snippet":_vm.onCopyCodeSnippet,"copy-message":_vm.onCopyMessage,"get-context-item-content":_vm.onGetContextItemContent,"open-file-path":_vm.onOpenFilePath}})}),_vm._v(" "),(!_vm.hasMessages && !_vm.isLoading)?[_c('div',{key:"empty-state-message",staticClass:"duo-chat-message gl-rounded-bl-none gl-border-1 gl-border-solid gl-border-gray-50 gl-bg-gray-10 gl-p-4 gl-leading-20 gl-text-gray-900 gl-break-anywhere",attrs:{"data-testid":"gl-duo-chat-empty-state"}},[(_vm.emptyStateTitle)?_c('p',{staticClass:"gl-m-0",attrs:{"data-testid":"gl-duo-chat-empty-state-title"}},[_vm._v("\n "+_vm._s(_vm.emptyStateTitle)+"\n ")]):_vm._e(),_vm._v(" "),_c('duo-chat-predefined-prompts',{key:"predefined-prompts",attrs:{"prompts":_vm.predefinedPrompts},on:{"click":_vm.sendPredefinedPrompt}})],1)]:_vm._e(),_vm._v(" "),(_vm.isLoading)?_c('duo-chat-loader',{key:"loader",attrs:{"tool-name":_vm.toolName}}):_vm._e(),_vm._v(" "),_c('div',{key:"anchor",ref:"anchor",staticClass:"scroll-anchor"})],2)],1),_vm._v(" "),(_vm.isChatAvailable && !_vm.shouldShowThreadList)?_c('footer',{staticClass:"duo-chat-drawer-footer gl-border-0 gl-bg-default gl-pb-3 gl-shrink-0 gl-relative gl-z-2",class:{ 'duo-chat-drawer-body-scrim-on-footer': !_vm.scrolledToBottom },attrs:{"data-testid":"chat-footer"}},[_c('gl-form',{attrs:{"data-testid":"chat-prompt-form"},on:{"submit":function($event){$event.stopPropagation();$event.preventDefault();return _vm.sendChatPrompt.apply(null, arguments)}}},[_c('div',{staticClass:"gl-relative gl-max-w-full"},[_vm._t("context-items-menu",null,{"isOpen":_vm.contextItemsMenuIsOpen,"onClose":_vm.closeContextItemsMenuOpen,"setRef":_vm.setContextItemsMenuRef,"focusPrompt":_vm.focusChatInput})],2),_vm._v(" "),_c('gl-form-input-group',{scopedSlots:_vm._u([{key:"append",fn:function(){return [(_vm.displaySubmitButton)?_c('gl-button',{staticClass:"!gl-absolute gl-bottom-2 gl-right-2 !gl-rounded-full",attrs:{"icon":"paper-airplane","category":"primary","variant":"confirm","type":"submit","data-testid":"chat-prompt-submit-button","aria-label":_vm.$options.i18n.CHAT_SUBMIT_LABEL}}):_c('gl-button',{staticClass:"!gl-absolute gl-bottom-2 gl-right-2 !gl-rounded-full",attrs:{"icon":"stop","category":"primary","variant":"default","data-testid":"chat-prompt-cancel-button","aria-label":_vm.$options.i18n.CHAT_CANCEL_LABEL},on:{"click":_vm.cancelPrompt}})]},proxy:true}],null,false,608602988)},[_c('div',{staticClass:"duo-chat-input gl-min-h-8 gl-max-w-full gl-grow gl-align-top",attrs:{"data-value":_vm.prompt}},[(_vm.shouldShowSlashCommands)?_c('gl-card',{ref:"commands",staticClass:"slash-commands !gl-absolute gl-w-full -gl-translate-y-full gl-list-none gl-pl-0 gl-shadow-md",attrs:{"body-class":"!gl-p-2"}},_vm._l((_vm.filteredSlashCommands),function(command,index){return _c('gl-dropdown-item',{key:command.name,class:{ 'active-command': index === _vm.activeCommandIndex },on:{"click":function($event){return _vm.selectSlashCommand(index)}},nativeOn:{"mouseenter":function($event){_vm.activeCommandIndex = index;}}},[_c('span',{staticClass:"gl-flex gl-justify-between"},[_c('span',{staticClass:"gl-block"},[_vm._v(_vm._s(command.name))]),_vm._v(" "),_c('small',{staticClass:"gl-pl-3 gl-text-right gl-italic gl-text-subtle"},[_vm._v(_vm._s(command.description))])])])}),1):_vm._e(),_vm._v(" "),_c('gl-form-textarea',{ref:"prompt",staticClass:"gl-absolute !gl-h-full gl-rounded-br-none gl-rounded-tr-none !gl-bg-transparent !gl-py-4 !gl-shadow-none",class:{ 'gl-truncate': !_vm.prompt },attrs:{"data-testid":"chat-prompt-input","placeholder":_vm.inputPlaceholder,"autofocus":""},on:{"compositionend":_vm.compositionEnd},nativeOn:{"keydown":function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"enter",13,$event.key,"Enter")){ return null; }if($event.ctrlKey||$event.shiftKey||$event.altKey||$event.metaKey){ return null; }$event.preventDefault();},"keyup":function($event){return _vm.onInputKeyup.apply(null, arguments)}},model:{value:(_vm.prompt),callback:function ($$v) {_vm.prompt=$$v;},expression:"prompt"}})],1)])],1),_vm._v(" "),_c('p',{staticClass:"gl-mb-0 gl-mt-3 gl-px-4 gl-text-sm gl-text-secondary"},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_DISCLAMER)+"\n ")])],1):_vm._e()],1):_vm._e()])};
|
|
631
634
|
var __vue_staticRenderFns__ = [];
|
|
632
635
|
|
|
633
636
|
/* style */
|
|
@@ -9,7 +9,7 @@ const duoMarked = new Marked([{
|
|
|
9
9
|
gfm: false
|
|
10
10
|
}, markedBidi()]);
|
|
11
11
|
const config = {
|
|
12
|
-
|
|
12
|
+
ADD_TAGS: ['insert-code-snippet', 'copy-code', 'gl-markdown', '#text', 'gl-compact-markdown'],
|
|
13
13
|
ADD_ATTR: ['data-canonical-lang', 'data-sourcepos', 'lang', 'data-src', 'img'],
|
|
14
14
|
FORBID_TAGS: ['script', 'style', 'iframe', 'form', 'button'],
|
|
15
15
|
FORBID_ATTR: ['onerror', 'onload', 'onclick']
|
|
@@ -96,6 +96,22 @@ const sanitizeLinksHook = function () {
|
|
|
96
96
|
node.removeAttribute('href');
|
|
97
97
|
};
|
|
98
98
|
};
|
|
99
|
+
function isHtml(markup) {
|
|
100
|
+
const src = markup.toString().trim();
|
|
101
|
+
if (src.length === 0 || !src.startsWith('<') || !src.includes('>')) {
|
|
102
|
+
return false; // fast-fail trivial cases
|
|
103
|
+
}
|
|
104
|
+
const doc = new DOMParser().parseFromString(src, 'text/html');
|
|
105
|
+
|
|
106
|
+
// DOMParser drops invalid tags but inserts a <parsererror> element on failure
|
|
107
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#error_handling
|
|
108
|
+
if (doc.querySelector('parsererror') !== null) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Do we have at least one real element node inside <body>?
|
|
113
|
+
return Array.from(doc.body.childNodes).some(n => n.nodeType === Node.ELEMENT_NODE);
|
|
114
|
+
}
|
|
99
115
|
function renderDuoChatMarkdownPreview(md) {
|
|
100
116
|
let {
|
|
101
117
|
trustedUrls = []
|
|
@@ -103,7 +119,7 @@ function renderDuoChatMarkdownPreview(md) {
|
|
|
103
119
|
if (!md) return '';
|
|
104
120
|
DOMPurify.addHook('beforeSanitizeElements', handleImageElements);
|
|
105
121
|
DOMPurify.addHook('afterSanitizeAttributes', sanitizeLinksHook(trustedUrls));
|
|
106
|
-
const parsedMarkdown = duoMarked.parse(md.toString());
|
|
122
|
+
const parsedMarkdown = isHtml(md) ? md : duoMarked.parse(md.toString());
|
|
107
123
|
const sanitized = DOMPurify.sanitize(parsedMarkdown, config);
|
|
108
124
|
DOMPurify.removeHook('beforeSanitizeElements');
|
|
109
125
|
DOMPurify.removeHook('afterSanitizeAttributes');
|
|
@@ -19,8 +19,40 @@ const MOCK_SOURCES = [{
|
|
|
19
19
|
}];
|
|
20
20
|
const MOCK_RESPONSE_MESSAGE = {
|
|
21
21
|
id: '123',
|
|
22
|
-
content: '
|
|
23
|
-
contentHtml:
|
|
22
|
+
content: 'I\'ll write a simple Python function with comments for you. Here\'s an example:\\\\n\\\\n```python\\\\ndef calculate_factorial(n):\\\\n \\\\\\"\\\\\\"\\\\\\"\\\\n Calculate the factorial of a non-negative integer.\\\\n \\\\n Args:\\\\n n (int): A non-negative integer\\\\n \\\\n Returns:\\\\n int: The factorial of n (n!)\\\\n \\\\n Examples:\\\\n >>> calculate_factorial(5)\\\\n 120\\\\n >>> calculate_factorial(0)\\\\n 1\\\\n \\\\\\"\\\\\\"\\\\\\"\\\\n # Handle base cases\\\\n if n == 0 or n == 1:\\\\n return 1\\\\n \\\\n # Use recursion to calculate factorial\\\\n return n * calculate_factorial(n - 1)\\\\n```\\\\n\\\\nThis function calculates the factorial of a number using recursion. It includes a docstring explaining what the function does, its parameters, return value, and usage examples, plus inline comments explaining the logic.',
|
|
23
|
+
contentHtml: `<p dir="auto">I'd be happy to write a simple Python function with comments for you. </p>
|
|
24
|
+
<p dir="auto">Here's a basic Python function that calculates the factorial of a number:</p>
|
|
25
|
+
<div class="gl-relative markdown-code-block js-markdown-code"><pre><code class="language-python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">factorial</span>(<span class="hljs-params">n</span>):
|
|
26
|
+
<span class="hljs-string">"""
|
|
27
|
+
Calculate the factorial of a non-negative integer.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
n (int): A non-negative integer
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
int: The factorial of n (n!)
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
>>> factorial(5)
|
|
37
|
+
120
|
|
38
|
+
>>> factorial(0)
|
|
39
|
+
1
|
|
40
|
+
"""</span>
|
|
41
|
+
<span class="hljs-comment"># Base case: factorial of 0 or 1 is 1</span>
|
|
42
|
+
<span class="hljs-keyword">if</span> n <= <span class="hljs-number">1</span>:
|
|
43
|
+
<span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
|
|
44
|
+
|
|
45
|
+
<span class="hljs-comment"># Recursive case: n! = n * (n-1)!</span>
|
|
46
|
+
<span class="hljs-keyword">return</span> n * factorial(n - <span class="hljs-number">1</span>)
|
|
47
|
+
</code></pre>
|
|
48
|
+
<copy-code></copy-code><insert-code-snippet></insert-code-snippet></div><p dir="auto">This function includes:</p>
|
|
49
|
+
<ul dir="auto">
|
|
50
|
+
<li>A docstring explaining what the function does</li>
|
|
51
|
+
<li>Parameter and return type documentation</li>
|
|
52
|
+
<li>Usage examples</li>
|
|
53
|
+
<li>Inline comments explaining the logic</li>
|
|
54
|
+
</ul>
|
|
55
|
+
<p dir="auto">Is there a specific type of function you'd like me to create instead?</p>`,
|
|
24
56
|
role: MESSAGE_MODEL_ROLES.assistant,
|
|
25
57
|
extras: {
|
|
26
58
|
sources: MOCK_SOURCES,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/duo-ui",
|
|
3
|
-
"version": "8.16.
|
|
3
|
+
"version": "8.16.2",
|
|
4
4
|
"description": "Duo UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"@gitlab/eslint-plugin": "20.7.1",
|
|
101
101
|
"@gitlab/fonts": "^1.3.0",
|
|
102
102
|
"@gitlab/stylelint-config": "6.2.2",
|
|
103
|
-
"@gitlab/svgs": "^3.
|
|
103
|
+
"@gitlab/svgs": "^3.134.0",
|
|
104
104
|
"@gitlab/ui": "latest",
|
|
105
105
|
"@jest/test-sequencer": "^29.7.0",
|
|
106
106
|
"@rollup/plugin-commonjs": "^11.1.0",
|
|
@@ -37,7 +37,7 @@ export const i18n = {
|
|
|
37
37
|
CHAT_HISTORY_TITLE: translate('AgenticDuoChat.chatHistoryTitle', 'Chat history'),
|
|
38
38
|
CHAT_DISCLAMER: translate(
|
|
39
39
|
'AgenticDuoChat.chatDisclamer',
|
|
40
|
-
'Responses
|
|
40
|
+
'Chat can autonomously change code. Responses and changes can be inaccurate. Review carefully.'
|
|
41
41
|
),
|
|
42
42
|
CHAT_EMPTY_STATE_TITLE: translate(
|
|
43
43
|
'AgenticDuoChat.chatEmptyStateTitle',
|
|
@@ -15,6 +15,7 @@ export const i18n = {
|
|
|
15
15
|
CHAT_NEW_LABEL: translate('DuoChat.chatNewLabel', 'New Chat'),
|
|
16
16
|
CHAT_NEW_TOOLTIP: translate('DuoChat.chatNewToolTip', 'New Chat'),
|
|
17
17
|
CHAT_HISTORY_TOOLTIP: translate('DuoChat.chatHistoryToolTip', 'Chat History'),
|
|
18
|
+
CHAT_BACK_TO_CHAT_TOOLTIP: translate('DuoChat.chatBackToChatToolTip', 'Back to Chat'),
|
|
18
19
|
CHAT_TITLE: translate('DuoChat.chatTitle', 'GitLab Duo Chat'),
|
|
19
20
|
};
|
|
20
21
|
|
|
@@ -83,11 +84,23 @@ export default {
|
|
|
83
84
|
<template>
|
|
84
85
|
<header data-testid="chat-header" class="gl-border-b gl-bg-default gl-p-0 gl-shrink-0">
|
|
85
86
|
<div class="drawer-title gl-flex gl-items-center gl-justify-start gl-p-5">
|
|
87
|
+
<gl-button
|
|
88
|
+
v-if="isMultithreaded && activeThreadId && currentView === VIEW_TYPES.LIST"
|
|
89
|
+
v-gl-tooltip
|
|
90
|
+
:title="$options.i18n.CHAT_BACK_TO_CHAT_TOOLTIP"
|
|
91
|
+
data-testid="go-back-to-chat-button"
|
|
92
|
+
category="primary"
|
|
93
|
+
size="medium"
|
|
94
|
+
icon="go-back"
|
|
95
|
+
class="gl-mr-3"
|
|
96
|
+
:aria-label="$options.i18n.CHAT_BACK_TO_CHAT_TOOLTIP"
|
|
97
|
+
@click="$emit('go-back-to-chat')"
|
|
98
|
+
/>
|
|
86
99
|
<gl-button
|
|
87
100
|
v-if="isMultithreaded && currentView === VIEW_TYPES.CHAT"
|
|
88
101
|
v-gl-tooltip
|
|
89
102
|
:title="$options.i18n.CHAT_HISTORY_TOOLTIP"
|
|
90
|
-
data-testid="
|
|
103
|
+
data-testid="go-back-to-list-button"
|
|
91
104
|
category="primary"
|
|
92
105
|
size="medium"
|
|
93
106
|
icon="history"
|
|
@@ -462,6 +462,9 @@ export default {
|
|
|
462
462
|
onGoBack() {
|
|
463
463
|
this.$emit('back-to-list');
|
|
464
464
|
},
|
|
465
|
+
onGoBackToChat() {
|
|
466
|
+
this.$emit('back-to-chat');
|
|
467
|
+
},
|
|
465
468
|
onNewChat() {
|
|
466
469
|
this.$emit('new-chat');
|
|
467
470
|
|
|
@@ -732,6 +735,7 @@ export default {
|
|
|
732
735
|
:should-render-resizable="shouldRenderResizable"
|
|
733
736
|
:badge-type="isMultithreaded ? null : badgeType"
|
|
734
737
|
@go-back="onGoBack"
|
|
738
|
+
@go-back-to-chat="onGoBackToChat"
|
|
735
739
|
@new-chat="onNewChat"
|
|
736
740
|
@close="hideChat"
|
|
737
741
|
>
|
|
@@ -13,18 +13,7 @@ const duoMarked = new Marked([
|
|
|
13
13
|
]);
|
|
14
14
|
|
|
15
15
|
const config = {
|
|
16
|
-
|
|
17
|
-
'p',
|
|
18
|
-
'#text',
|
|
19
|
-
'div',
|
|
20
|
-
'code',
|
|
21
|
-
'insert-code-snippet',
|
|
22
|
-
'gl-markdown',
|
|
23
|
-
'pre',
|
|
24
|
-
'span',
|
|
25
|
-
'gl-compact-markdown',
|
|
26
|
-
'copy-code',
|
|
27
|
-
],
|
|
16
|
+
ADD_TAGS: ['insert-code-snippet', 'copy-code', 'gl-markdown', '#text', 'gl-compact-markdown'],
|
|
28
17
|
ADD_ATTR: ['data-canonical-lang', 'data-sourcepos', 'lang', 'data-src', 'img'],
|
|
29
18
|
FORBID_TAGS: ['script', 'style', 'iframe', 'form', 'button'],
|
|
30
19
|
FORBID_ATTR: ['onerror', 'onload', 'onclick'],
|
|
@@ -116,13 +105,32 @@ const sanitizeLinksHook =
|
|
|
116
105
|
node.removeAttribute('href');
|
|
117
106
|
};
|
|
118
107
|
|
|
108
|
+
function isHtml(markup) {
|
|
109
|
+
const src = markup.toString().trim();
|
|
110
|
+
if (src.length === 0 || !src.startsWith('<') || !src.includes('>')) {
|
|
111
|
+
return false; // fast-fail trivial cases
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const doc = new DOMParser().parseFromString(src, 'text/html');
|
|
115
|
+
|
|
116
|
+
// DOMParser drops invalid tags but inserts a <parsererror> element on failure
|
|
117
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#error_handling
|
|
118
|
+
if (doc.querySelector('parsererror') !== null) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Do we have at least one real element node inside <body>?
|
|
123
|
+
return Array.from(doc.body.childNodes).some((n) => n.nodeType === Node.ELEMENT_NODE);
|
|
124
|
+
}
|
|
125
|
+
|
|
119
126
|
export function renderDuoChatMarkdownPreview(md, { trustedUrls = [] } = {}) {
|
|
120
127
|
if (!md) return '';
|
|
121
128
|
|
|
122
129
|
DOMPurify.addHook('beforeSanitizeElements', handleImageElements);
|
|
123
130
|
DOMPurify.addHook('afterSanitizeAttributes', sanitizeLinksHook(trustedUrls));
|
|
124
131
|
|
|
125
|
-
const parsedMarkdown = duoMarked.parse(md.toString());
|
|
132
|
+
const parsedMarkdown = isHtml(md) ? md : duoMarked.parse(md.toString());
|
|
133
|
+
|
|
126
134
|
const sanitized = DOMPurify.sanitize(parsedMarkdown, config);
|
|
127
135
|
|
|
128
136
|
DOMPurify.removeHook('beforeSanitizeElements');
|
|
@@ -31,9 +31,40 @@ const MOCK_SOURCES = [
|
|
|
31
31
|
export const MOCK_RESPONSE_MESSAGE = {
|
|
32
32
|
id: '123',
|
|
33
33
|
content:
|
|
34
|
-
'
|
|
35
|
-
contentHtml:
|
|
36
|
-
|
|
34
|
+
'I\'ll write a simple Python function with comments for you. Here\'s an example:\\\\n\\\\n```python\\\\ndef calculate_factorial(n):\\\\n \\\\\\"\\\\\\"\\\\\\"\\\\n Calculate the factorial of a non-negative integer.\\\\n \\\\n Args:\\\\n n (int): A non-negative integer\\\\n \\\\n Returns:\\\\n int: The factorial of n (n!)\\\\n \\\\n Examples:\\\\n >>> calculate_factorial(5)\\\\n 120\\\\n >>> calculate_factorial(0)\\\\n 1\\\\n \\\\\\"\\\\\\"\\\\\\"\\\\n # Handle base cases\\\\n if n == 0 or n == 1:\\\\n return 1\\\\n \\\\n # Use recursion to calculate factorial\\\\n return n * calculate_factorial(n - 1)\\\\n```\\\\n\\\\nThis function calculates the factorial of a number using recursion. It includes a docstring explaining what the function does, its parameters, return value, and usage examples, plus inline comments explaining the logic.',
|
|
35
|
+
contentHtml: `<p dir="auto">I'd be happy to write a simple Python function with comments for you. </p>
|
|
36
|
+
<p dir="auto">Here's a basic Python function that calculates the factorial of a number:</p>
|
|
37
|
+
<div class="gl-relative markdown-code-block js-markdown-code"><pre><code class="language-python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">factorial</span>(<span class="hljs-params">n</span>):
|
|
38
|
+
<span class="hljs-string">"""
|
|
39
|
+
Calculate the factorial of a non-negative integer.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
n (int): A non-negative integer
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
int: The factorial of n (n!)
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
>>> factorial(5)
|
|
49
|
+
120
|
|
50
|
+
>>> factorial(0)
|
|
51
|
+
1
|
|
52
|
+
"""</span>
|
|
53
|
+
<span class="hljs-comment"># Base case: factorial of 0 or 1 is 1</span>
|
|
54
|
+
<span class="hljs-keyword">if</span> n <= <span class="hljs-number">1</span>:
|
|
55
|
+
<span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
|
|
56
|
+
|
|
57
|
+
<span class="hljs-comment"># Recursive case: n! = n * (n-1)!</span>
|
|
58
|
+
<span class="hljs-keyword">return</span> n * factorial(n - <span class="hljs-number">1</span>)
|
|
59
|
+
</code></pre>
|
|
60
|
+
<copy-code></copy-code><insert-code-snippet></insert-code-snippet></div><p dir="auto">This function includes:</p>
|
|
61
|
+
<ul dir="auto">
|
|
62
|
+
<li>A docstring explaining what the function does</li>
|
|
63
|
+
<li>Parameter and return type documentation</li>
|
|
64
|
+
<li>Usage examples</li>
|
|
65
|
+
<li>Inline comments explaining the logic</li>
|
|
66
|
+
</ul>
|
|
67
|
+
<p dir="auto">Is there a specific type of function you'd like me to create instead?</p>`,
|
|
37
68
|
role: MESSAGE_MODEL_ROLES.assistant,
|
|
38
69
|
extras: {
|
|
39
70
|
sources: MOCK_SOURCES,
|
package/translations.js
CHANGED
|
@@ -7,7 +7,8 @@ export default {
|
|
|
7
7
|
'AgenticDuoChat.chatDefaultPredefinedPromptsCreateTemplate': 'How do I create a template?',
|
|
8
8
|
'AgenticDuoChat.chatDefaultPredefinedPromptsForkProject': 'How do I fork a project?',
|
|
9
9
|
'AgenticDuoChat.chatDefaultTitle': 'GitLab Duo Chat',
|
|
10
|
-
'AgenticDuoChat.chatDisclamer':
|
|
10
|
+
'AgenticDuoChat.chatDisclamer':
|
|
11
|
+
'Chat can autonomously change code. Responses and changes can be inaccurate. Review carefully.',
|
|
11
12
|
'AgenticDuoChat.chatEmptyStateTitle':
|
|
12
13
|
'👋 I am GitLab Duo Chat, your personal AI-powered assistant. How can I help you today?',
|
|
13
14
|
'AgenticDuoChat.chatHistoryTitle': 'Chat history',
|
|
@@ -15,6 +16,7 @@ export default {
|
|
|
15
16
|
'AgenticDuoChat.chatPromptPlaceholderWithCommands': 'Type /help to learn more',
|
|
16
17
|
'AgenticDuoChat.chatSubmitLabel': 'Send chat message.',
|
|
17
18
|
'DuoChat.chatBackLabel': 'Back to History',
|
|
19
|
+
'DuoChat.chatBackToChatToolTip': 'Back to Chat',
|
|
18
20
|
'DuoChat.chatCancelLabel': 'Cancel',
|
|
19
21
|
'DuoChat.chatDefaultPredefinedPromptsChangePassword': 'How do I change my password in GitLab?',
|
|
20
22
|
'DuoChat.chatDefaultPredefinedPromptsCloneRepository': 'How do I clone a repository?',
|