@gitlab/duo-ui 15.0.4 → 15.0.6
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 +16 -0
- package/dist/components/agentic_chat/agentic_duo_chat.js +20 -6
- package/dist/components/agentic_chat/web_agentic_duo_chat.js +12 -1
- package/dist/components/chat/components/duo_chat_conversation/duo_chat_conversation.js +5 -2
- package/dist/components/chat/components/duo_chat_message/duo_chat_message.js +19 -6
- package/dist/components/chat/components/duo_chat_message_tool_approval/message_tool_approval.js +23 -28
- package/dist/components/chat/duo_chat.js +5 -2
- package/dist/components/chat/web_duo_chat.js +5 -2
- package/package.json +1 -1
- package/src/components/agentic_chat/agentic_duo_chat.vue +22 -10
- package/src/components/agentic_chat/web_agentic_duo_chat.vue +12 -0
- package/src/components/chat/components/duo_chat_conversation/duo_chat_conversation.vue +4 -1
- package/src/components/chat/components/duo_chat_message/duo_chat_message.vue +15 -6
- package/src/components/chat/components/duo_chat_message_tool_approval/message_tool_approval.vue +22 -27
- package/src/components/chat/duo_chat.vue +4 -1
- package/src/components/chat/web_duo_chat.vue +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## [15.0.6](https://gitlab.com/gitlab-org/duo-ui/compare/v15.0.5...v15.0.6) (2025-12-08)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* trustedUrls propagation to renderMarkdown ([7e296d1](https://gitlab.com/gitlab-org/duo-ui/commit/7e296d15d82d9edc5f3216c1f557861d6ba37272))
|
|
7
|
+
* trustedUrls validation and comments ([66b1307](https://gitlab.com/gitlab-org/duo-ui/commit/66b1307938f07d50792fcf3d95337512846855fc))
|
|
8
|
+
|
|
9
|
+
## [15.0.5](https://gitlab.com/gitlab-org/duo-ui/compare/v15.0.4...v15.0.5) (2025-12-07)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* Do not allow to cancel chat while tool is being processed ([41ba989](https://gitlab.com/gitlab-org/duo-ui/commit/41ba9896584762a5d0064d64a6284dd563494b46))
|
|
15
|
+
* Tool approval buttons enabled too fast ([8977579](https://gitlab.com/gitlab-org/duo-ui/commit/897757973ad54ac69a6bfb225df4c88bcda6426b))
|
|
16
|
+
|
|
1
17
|
## [15.0.4](https://gitlab.com/gitlab-org/duo-ui/compare/v15.0.3...v15.0.4) (2025-12-03)
|
|
2
18
|
|
|
3
19
|
|
|
@@ -284,6 +284,17 @@ var script = {
|
|
|
284
284
|
type: String,
|
|
285
285
|
required: false,
|
|
286
286
|
default: () => ''
|
|
287
|
+
},
|
|
288
|
+
/**
|
|
289
|
+
* Array of trusted hostnames (e.g., ['gitlab.com', 'example.com'])
|
|
290
|
+
* that are allowed to render as clickable links in markdown content.
|
|
291
|
+
* Links to other domains will not be clickable.
|
|
292
|
+
*/
|
|
293
|
+
trustedUrls: {
|
|
294
|
+
type: Array,
|
|
295
|
+
required: false,
|
|
296
|
+
default: () => [],
|
|
297
|
+
validator: urls => urls.every(url => typeof url === 'string')
|
|
287
298
|
}
|
|
288
299
|
},
|
|
289
300
|
data() {
|
|
@@ -305,11 +316,7 @@ var script = {
|
|
|
305
316
|
computed: {
|
|
306
317
|
canSubmit() {
|
|
307
318
|
const shouldAllowSubmit = !this.isLoading && !this.isStreaming && !this.isToolApprovalProcessing && !this.isAwaitingToolApproval;
|
|
308
|
-
|
|
309
|
-
// Fallback logic: If we're not loading, not streaming, and not awaiting approval,
|
|
310
|
-
// but isToolApprovalProcessing is stuck at true, we should still enable submit
|
|
311
|
-
const isStuckInProcessing = !this.isLoading && !this.isStreaming && !this.isAwaitingToolApproval && this.isToolApprovalProcessing;
|
|
312
|
-
return shouldAllowSubmit || isStuckInProcessing;
|
|
319
|
+
return shouldAllowSubmit;
|
|
313
320
|
},
|
|
314
321
|
shouldShowThreadList() {
|
|
315
322
|
return this.isMultithreaded && this.currentView === VIEW_TYPES.LIST;
|
|
@@ -398,6 +405,13 @@ var script = {
|
|
|
398
405
|
return Boolean(
|
|
399
406
|
// It is possible to get tool null, so we assert it is truthy to make sure there is a payload
|
|
400
407
|
lastMessage && lastMessage.message_type === 'request' && lastMessage.tool_info);
|
|
408
|
+
},
|
|
409
|
+
canCancelInternal() {
|
|
410
|
+
// Don't allow cancel while there are pending tool approvals
|
|
411
|
+
if (this.isAwaitingToolApproval) {
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
return this.canCancel;
|
|
401
415
|
}
|
|
402
416
|
},
|
|
403
417
|
watch: {
|
|
@@ -707,7 +721,7 @@ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=
|
|
|
707
721
|
},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-flex gl-max-h-full gl-flex-col",class:{
|
|
708
722
|
'resizable-content': _vm.shouldRenderResizable,
|
|
709
723
|
'duo-chat-drawer': !_vm.shouldRenderResizable,
|
|
710
|
-
},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,"error":_vm.error,"is-multithreaded":_vm.isMultithreaded,"current-view":_vm.currentView,"should-render-resizable":_vm.shouldRenderResizable,"badge-type":_vm.isMultithreaded ? null : _vm.badgeType,"session-id":_vm.sessionId,"agents":_vm.agents},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-flex gl-flex-1 gl-flex-grow gl-flex-col gl-overflow-y-auto gl-overscroll-contain gl-bg-inherit",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-mt-auto gl-px-4 gl-pb-4 gl-pt-6",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,"show-delimiter":index > 0,"with-feedback":_vm.withFeedback,"is-tool-approval-processing":_vm.isToolApprovalProcessing,"working-directory":_vm.workingDirectory},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,"approve-tool":_vm.onApproveToolCall,"deny-tool":_vm.onDenyToolCall,"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-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-relative gl-z-2 gl-shrink-0",attrs:{"data-testid":"chat-footer"}},[(_vm.$scopedSlots['footer-panel'])?_c('div',{staticClass:"gl-relative gl-max-w-full",attrs:{"data-testid":"footer-panel-wrapper"}},[_vm._t("footer-panel")],2):_vm._e(),_vm._v(" "),(_vm.$scopedSlots['footer-actions'])?_c('div',{staticClass:"gl-my-4 gl-flex gl-items-center gl-justify-between gl-gap-x-4 gl-px-4",attrs:{"data-testid":"footer-actions-wrapper"}},[_vm._t("footer-actions")],2):_vm._e(),_vm._v(" "),_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.canSubmit)?_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","disabled":_vm.isPromptEmpty || !_vm.hasValidPrompt,"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,"disabled":!_vm.
|
|
724
|
+
},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,"error":_vm.error,"is-multithreaded":_vm.isMultithreaded,"current-view":_vm.currentView,"should-render-resizable":_vm.shouldRenderResizable,"badge-type":_vm.isMultithreaded ? null : _vm.badgeType,"session-id":_vm.sessionId,"agents":_vm.agents},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-flex gl-flex-1 gl-flex-grow gl-flex-col gl-overflow-y-auto gl-overscroll-contain gl-bg-inherit",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-mt-auto gl-px-4 gl-pb-4 gl-pt-6",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,"show-delimiter":index > 0,"with-feedback":_vm.withFeedback,"is-tool-approval-processing":_vm.isToolApprovalProcessing,"working-directory":_vm.workingDirectory,"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,"approve-tool":_vm.onApproveToolCall,"deny-tool":_vm.onDenyToolCall,"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-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-relative gl-z-2 gl-shrink-0",attrs:{"data-testid":"chat-footer"}},[(_vm.$scopedSlots['footer-panel'])?_c('div',{staticClass:"gl-relative gl-max-w-full",attrs:{"data-testid":"footer-panel-wrapper"}},[_vm._t("footer-panel")],2):_vm._e(),_vm._v(" "),(_vm.$scopedSlots['footer-actions'])?_c('div',{staticClass:"gl-my-4 gl-flex gl-items-center gl-justify-between gl-gap-x-4 gl-px-4",attrs:{"data-testid":"footer-actions-wrapper"}},[_vm._t("footer-actions")],2):_vm._e(),_vm._v(" "),_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.canSubmit)?_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","disabled":_vm.isPromptEmpty || !_vm.hasValidPrompt,"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,"disabled":!_vm.canCancelInternal},on:{"click":_vm.cancelPrompt}})]},proxy:true}],null,false,3149367298)},[_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",attrs:{"disabled":!_vm.canSubmit,"data-testid":"chat-prompt-input","placeholder":_vm.inputPlaceholder,"character-count-limit":_vm.maxPromptLength,"textarea-classes":[
|
|
711
725
|
'gl-absolute',
|
|
712
726
|
'!gl-h-full',
|
|
713
727
|
'gl-rounded-br-none',
|
|
@@ -317,6 +317,17 @@ var script = {
|
|
|
317
317
|
type: Boolean,
|
|
318
318
|
required: false,
|
|
319
319
|
default: true
|
|
320
|
+
},
|
|
321
|
+
/**
|
|
322
|
+
* Array of trusted hostnames (e.g., ['gitlab.com', 'example.com'])
|
|
323
|
+
* that are allowed to render as clickable links in markdown content.
|
|
324
|
+
* Links to other domains will not be clickable.
|
|
325
|
+
*/
|
|
326
|
+
trustedUrls: {
|
|
327
|
+
type: Array,
|
|
328
|
+
required: false,
|
|
329
|
+
default: () => [],
|
|
330
|
+
validator: urls => urls.every(url => typeof url === 'string')
|
|
320
331
|
}
|
|
321
332
|
},
|
|
322
333
|
data() {
|
|
@@ -748,7 +759,7 @@ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=
|
|
|
748
759
|
'duo-chat-history gl-px-4',
|
|
749
760
|
_vm.$scopedSlots['custom-empty-state']
|
|
750
761
|
? 'gl-flex gl-flex-1 gl-items-center gl-justify-center'
|
|
751
|
-
: 'gl-mt-auto gl-pb-4 gl-pt-6' ],attrs:{"mode":"out-in","tag":"section","name":"message","data-testid":"chat-messages"}},[_vm._l((_vm.conversations),function(conversation,index){return _c('duo-chat-conversation',{key:("conversation-" + index),attrs:{"enable-code-insertion":_vm.enableCodeInsertion,"messages":conversation,"show-delimiter":index > 0,"with-feedback":_vm.withFeedback,"is-tool-approval-processing":_vm.isToolApprovalProcessing,"working-directory":_vm.workingDirectory},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,"approve-tool":_vm.onApproveToolCall,"deny-tool":_vm.onDenyToolCall,"open-file-path":_vm.onOpenFilePath}})}),_vm._v(" "),(!_vm.hasMessages && !_vm.isLoading)?[_vm._t("custom-empty-state",function(){return [_c('div',{key:"empty-state-message",staticClass:"duo-chat-message gl-rounded-bl-none gl-leading-20 gl-text-default gl-break-anywhere",attrs:{"data-testid":"gl-duo-chat-empty-state"}},[_c('div',{staticClass:"gl-mb-[3.75rem] gl-flex gl-flex-col gl-items-center gl-justify-center gl-gap-3 gl-text-center"},[_c('h1',{staticClass:"gl-my-0 gl-text-[3.5rem]",attrs:{"data-testid":"gl-duo-chat-empty-state-emoji"}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_EMPTY_STATE_EMOJI)+"\n ")]),_vm._v(" "),(_vm.agentName)?_c('h2',{staticClass:"gl-heading-2 gl-my-0",attrs:{"data-testid":"gl-duo-chat-empty-state-greeting"}},[_vm._v("\n "+_vm._s(_vm.emptyStateGreeting)+"\n ")]):_vm._e(),_vm._v(" "),_c('h2',{staticClass:"gl-my-0 gl-text-size-h2",attrs:{"data-testid":"gl-duo-chat-empty-state-title"}},[_vm._v("\n "+_vm._s(_vm.emptyStateMainText)+"\n ")]),_vm._v(" "),_c('p',{staticClass:"gl-text-base gl-text-subtle",attrs:{"data-testid":"gl-duo-chat-empty-state-subtitle"}},[_vm._v("\n "+_vm._s(_vm.emptyStateSubText)+"\n ")])]),_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.shouldShowThreadList)?_c('footer',{staticClass:"duo-chat-drawer-footer gl-relative gl-z-2 gl-shrink-0",attrs:{"data-testid":"chat-footer"}},[_c('p',{staticClass:"gl-mb-3 gl-text-sm gl-text-subtle",class:{ 'gl-invisible': !_vm.hasAssistantMessages },attrs:{"data-testid":"chat-disclaimer"}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_DISCLAIMER)+"\n ")]),_vm._v(" "),_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('div',{staticClass:"duo-chat-input gl-relative gl-min-h-8 gl-max-w-full gl-grow gl-flex-col gl-rounded-bl-[12px] gl-rounded-br-[18px] gl-rounded-tl-[12px] gl-rounded-tr-[12px] gl-align-top forced-colors:gl-border"},[(_vm.$scopedSlots['agentic-model'] || _vm.$scopedSlots['agentic-switch'])?_c('div',{staticClass:"gl-flex gl-items-center gl-justify-between gl-gap-5 gl-border-0 gl-border-b-1 gl-border-solid gl-border-strong gl-px-4 gl-py-4 forced-colors:gl-border-none"},[_c('div',{staticClass:"duo-model-switcher gl-min-w-0 gl-max-w-full"},[_vm._t("agentic-model")],2),_vm._v(" "),_c('div',{staticClass:"duo-agent-mode-switcher gl-min-w-0 gl-max-w-full gl-shrink-0"},[_vm._t("agentic-switch")],2)]):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-h-[80px] gl-grow",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",attrs:{"disabled":!_vm.canSubmit || !_vm.isChatAvailable || !_vm.chatState.isEnabled,"data-testid":"chat-prompt-input","placeholder":_vm.inputPlaceholder,"character-count-limit":_vm.maxPromptLength,"textarea-classes":[
|
|
762
|
+
: 'gl-mt-auto gl-pb-4 gl-pt-6' ],attrs:{"mode":"out-in","tag":"section","name":"message","data-testid":"chat-messages"}},[_vm._l((_vm.conversations),function(conversation,index){return _c('duo-chat-conversation',{key:("conversation-" + index),attrs:{"enable-code-insertion":_vm.enableCodeInsertion,"messages":conversation,"show-delimiter":index > 0,"with-feedback":_vm.withFeedback,"is-tool-approval-processing":_vm.isToolApprovalProcessing,"working-directory":_vm.workingDirectory,"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,"approve-tool":_vm.onApproveToolCall,"deny-tool":_vm.onDenyToolCall,"open-file-path":_vm.onOpenFilePath}})}),_vm._v(" "),(!_vm.hasMessages && !_vm.isLoading)?[_vm._t("custom-empty-state",function(){return [_c('div',{key:"empty-state-message",staticClass:"duo-chat-message gl-rounded-bl-none gl-leading-20 gl-text-default gl-break-anywhere",attrs:{"data-testid":"gl-duo-chat-empty-state"}},[_c('div',{staticClass:"gl-mb-[3.75rem] gl-flex gl-flex-col gl-items-center gl-justify-center gl-gap-3 gl-text-center"},[_c('h1',{staticClass:"gl-my-0 gl-text-[3.5rem]",attrs:{"data-testid":"gl-duo-chat-empty-state-emoji"}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_EMPTY_STATE_EMOJI)+"\n ")]),_vm._v(" "),(_vm.agentName)?_c('h2',{staticClass:"gl-heading-2 gl-my-0",attrs:{"data-testid":"gl-duo-chat-empty-state-greeting"}},[_vm._v("\n "+_vm._s(_vm.emptyStateGreeting)+"\n ")]):_vm._e(),_vm._v(" "),_c('h2',{staticClass:"gl-my-0 gl-text-size-h2",attrs:{"data-testid":"gl-duo-chat-empty-state-title"}},[_vm._v("\n "+_vm._s(_vm.emptyStateMainText)+"\n ")]),_vm._v(" "),_c('p',{staticClass:"gl-text-base gl-text-subtle",attrs:{"data-testid":"gl-duo-chat-empty-state-subtitle"}},[_vm._v("\n "+_vm._s(_vm.emptyStateSubText)+"\n ")])]),_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.shouldShowThreadList)?_c('footer',{staticClass:"duo-chat-drawer-footer gl-relative gl-z-2 gl-shrink-0",attrs:{"data-testid":"chat-footer"}},[_c('p',{staticClass:"gl-mb-3 gl-text-sm gl-text-subtle",class:{ 'gl-invisible': !_vm.hasAssistantMessages },attrs:{"data-testid":"chat-disclaimer"}},[_vm._v("\n "+_vm._s(_vm.$options.i18n.CHAT_DISCLAIMER)+"\n ")]),_vm._v(" "),_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('div',{staticClass:"duo-chat-input gl-relative gl-min-h-8 gl-max-w-full gl-grow gl-flex-col gl-rounded-bl-[12px] gl-rounded-br-[18px] gl-rounded-tl-[12px] gl-rounded-tr-[12px] gl-align-top forced-colors:gl-border"},[(_vm.$scopedSlots['agentic-model'] || _vm.$scopedSlots['agentic-switch'])?_c('div',{staticClass:"gl-flex gl-items-center gl-justify-between gl-gap-5 gl-border-0 gl-border-b-1 gl-border-solid gl-border-strong gl-px-4 gl-py-4 forced-colors:gl-border-none"},[_c('div',{staticClass:"duo-model-switcher gl-min-w-0 gl-max-w-full"},[_vm._t("agentic-model")],2),_vm._v(" "),_c('div',{staticClass:"duo-agent-mode-switcher gl-min-w-0 gl-max-w-full gl-shrink-0"},[_vm._t("agentic-switch")],2)]):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-h-[80px] gl-grow",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",attrs:{"disabled":!_vm.canSubmit || !_vm.isChatAvailable || !_vm.chatState.isEnabled,"data-testid":"chat-prompt-input","placeholder":_vm.inputPlaceholder,"character-count-limit":_vm.maxPromptLength,"textarea-classes":[
|
|
752
763
|
'!gl-h-full',
|
|
753
764
|
'!gl-bg-transparent',
|
|
754
765
|
'!gl-py-4',
|
|
@@ -47,12 +47,15 @@ var script = {
|
|
|
47
47
|
default: true
|
|
48
48
|
},
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
50
|
+
* Array of trusted hostnames (e.g., ['gitlab.com', 'example.com'])
|
|
51
|
+
* that are allowed to render as clickable links in markdown content.
|
|
52
|
+
* Links to other domains will not be clickable.
|
|
51
53
|
*/
|
|
52
54
|
trustedUrls: {
|
|
53
55
|
type: Array,
|
|
54
56
|
required: false,
|
|
55
|
-
default: () => []
|
|
57
|
+
default: () => [],
|
|
58
|
+
validator: urls => urls.every(url => typeof url === 'string')
|
|
56
59
|
},
|
|
57
60
|
/**
|
|
58
61
|
* Whether the chat should show the feedback link on the assistant messages.
|
|
@@ -67,12 +67,15 @@ var script = {
|
|
|
67
67
|
required: true
|
|
68
68
|
},
|
|
69
69
|
/**
|
|
70
|
-
*
|
|
70
|
+
* Array of trusted hostnames (e.g., ['gitlab.com', 'example.com'])
|
|
71
|
+
* that are allowed to render as clickable links in markdown content.
|
|
72
|
+
* Links to other domains will not be clickable.
|
|
71
73
|
*/
|
|
72
74
|
trustedUrls: {
|
|
73
75
|
type: Array,
|
|
74
76
|
required: false,
|
|
75
|
-
default: () => []
|
|
77
|
+
default: () => [],
|
|
78
|
+
validator: urls => urls.every(url => typeof url === 'string')
|
|
76
79
|
},
|
|
77
80
|
/**
|
|
78
81
|
* Whether the chat should show the feedback link on the assistant messages.
|
|
@@ -136,17 +139,27 @@ var script = {
|
|
|
136
139
|
if (this.message.contentHtml) {
|
|
137
140
|
return this.message.contentHtml;
|
|
138
141
|
}
|
|
139
|
-
return this.renderMarkdown(this.message.content,
|
|
142
|
+
return this.renderMarkdown(this.message.content, {
|
|
143
|
+
trustedUrls: this.trustedUrls
|
|
144
|
+
});
|
|
140
145
|
},
|
|
141
146
|
messageContent() {
|
|
142
147
|
if (this.isAssistantMessage && this.isChunk) {
|
|
143
|
-
return this.renderMarkdown(concatUntilEmpty(this.messageChunks),
|
|
148
|
+
return this.renderMarkdown(concatUntilEmpty(this.messageChunks), {
|
|
149
|
+
trustedUrls: this.trustedUrls
|
|
150
|
+
});
|
|
144
151
|
}
|
|
145
|
-
return this.renderMarkdown(this.defaultContent,
|
|
152
|
+
return this.renderMarkdown(this.defaultContent, {
|
|
153
|
+
trustedUrls: this.trustedUrls
|
|
154
|
+
}) || this.renderMarkdown(concatUntilEmpty(this.message.chunks), {
|
|
155
|
+
trustedUrls: this.trustedUrls
|
|
156
|
+
});
|
|
146
157
|
},
|
|
147
158
|
renderedError() {
|
|
148
159
|
var _this$message$errors;
|
|
149
|
-
return this.renderMarkdown(((_this$message$errors = this.message.errors) === null || _this$message$errors === void 0 ? void 0 : _this$message$errors.join('; ')) || '',
|
|
160
|
+
return this.renderMarkdown(((_this$message$errors = this.message.errors) === null || _this$message$errors === void 0 ? void 0 : _this$message$errors.join('; ')) || '', {
|
|
161
|
+
trustedUrls: this.trustedUrls
|
|
162
|
+
});
|
|
150
163
|
},
|
|
151
164
|
error() {
|
|
152
165
|
var _this$message, _this$message$errors2;
|
package/dist/components/chat/components/duo_chat_message_tool_approval/message_tool_approval.js
CHANGED
|
@@ -165,13 +165,14 @@ var script = {
|
|
|
165
165
|
return this.approvalStatus === TOOL_STATUS.Approved;
|
|
166
166
|
},
|
|
167
167
|
isApproving() {
|
|
168
|
-
return this.
|
|
168
|
+
return this.localProcessingState === PROCESSING_STATE.APPROVING || this.isProcessing;
|
|
169
169
|
},
|
|
170
170
|
isDenying() {
|
|
171
|
-
return this.
|
|
171
|
+
return this.localProcessingState === PROCESSING_STATE.DENYING;
|
|
172
172
|
},
|
|
173
173
|
buttonsDisabled() {
|
|
174
|
-
|
|
174
|
+
// Disable if we've taken action locally OR if parent says we're processing
|
|
175
|
+
return this.localProcessingState !== PROCESSING_STATE.NONE || this.isProcessing;
|
|
175
176
|
},
|
|
176
177
|
approveButtonText() {
|
|
177
178
|
return this.isApproving ? this.$options.i18n.APPROVING_TEXT : this.$options.i18n.APPROVE_TEXT;
|
|
@@ -197,51 +198,45 @@ var script = {
|
|
|
197
198
|
}
|
|
198
199
|
},
|
|
199
200
|
watch: {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
this.resetProcessingState();
|
|
201
|
+
approvalStatus(newVal) {
|
|
202
|
+
if (newVal === TOOL_STATUS.Approved) {
|
|
203
|
+
this.collapsed = true;
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
},
|
|
207
207
|
methods: {
|
|
208
|
-
|
|
209
|
-
if (this.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const approvalPayload = {
|
|
213
|
-
type: this.primaryApprovalOption.type || acceptedApproveToolPayloads.APPROVE_TOOL_ONCE
|
|
214
|
-
};
|
|
215
|
-
this.$emit('approve-tool', approvalPayload);
|
|
216
|
-
},
|
|
217
|
-
handlePrimaryApprove() {
|
|
218
|
-
if (this.isProcessing) return;
|
|
208
|
+
approveWithType(approvalType) {
|
|
209
|
+
if (this.localProcessingState !== PROCESSING_STATE.NONE) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
219
212
|
this.localProcessingState = PROCESSING_STATE.APPROVING;
|
|
220
213
|
this.$emit('approve-tool', {
|
|
221
|
-
type:
|
|
214
|
+
type: approvalType
|
|
222
215
|
});
|
|
223
216
|
},
|
|
217
|
+
handleApprove() {
|
|
218
|
+
const approvalType = this.primaryApprovalOption.type || acceptedApproveToolPayloads.APPROVE_TOOL_ONCE;
|
|
219
|
+
this.approveWithType(approvalType);
|
|
220
|
+
},
|
|
221
|
+
handlePrimaryApprove() {
|
|
222
|
+
this.approveWithType(this.primaryApprovalOption.type);
|
|
223
|
+
},
|
|
224
224
|
handleDropdownSelection(option) {
|
|
225
|
-
|
|
226
|
-
this.localProcessingState = PROCESSING_STATE.APPROVING;
|
|
227
|
-
this.$emit('approve-tool', {
|
|
228
|
-
type: option.type
|
|
229
|
-
});
|
|
225
|
+
this.approveWithType(option.type);
|
|
230
226
|
},
|
|
231
227
|
handleDeny() {
|
|
232
|
-
if (this.isProcessing) return;
|
|
233
228
|
this.showDenialReason = true;
|
|
234
229
|
},
|
|
235
230
|
cancelDenial() {
|
|
236
231
|
this.showDenialReason = false;
|
|
237
232
|
this.denialReason = '';
|
|
238
|
-
this.localProcessingState = PROCESSING_STATE.NONE;
|
|
239
233
|
},
|
|
240
234
|
submitDenial() {
|
|
241
|
-
if (this.
|
|
235
|
+
if (this.localProcessingState !== PROCESSING_STATE.NONE) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
242
238
|
this.localProcessingState = PROCESSING_STATE.DENYING;
|
|
243
239
|
this.$emit('deny-tool', this.denialReason || null);
|
|
244
|
-
// Don't reset state here - wait for isProcessing to change
|
|
245
240
|
},
|
|
246
241
|
resetProcessingState() {
|
|
247
242
|
this.localProcessingState = PROCESSING_STATE.NONE;
|
|
@@ -242,12 +242,15 @@ var script = {
|
|
|
242
242
|
default: false
|
|
243
243
|
},
|
|
244
244
|
/**
|
|
245
|
-
*
|
|
245
|
+
* Array of trusted hostnames (e.g., ['gitlab.com', 'example.com'])
|
|
246
|
+
* that are allowed to render as clickable links in markdown content.
|
|
247
|
+
* Links to other domains will not be clickable.
|
|
246
248
|
*/
|
|
247
249
|
trustedUrls: {
|
|
248
250
|
type: Array,
|
|
249
251
|
required: false,
|
|
250
|
-
default: () => []
|
|
252
|
+
default: () => [],
|
|
253
|
+
validator: urls => urls.every(url => typeof url === 'string')
|
|
251
254
|
},
|
|
252
255
|
/*
|
|
253
256
|
* The preferred locale for the chat interface.
|
|
@@ -219,12 +219,15 @@ var script = {
|
|
|
219
219
|
default: false
|
|
220
220
|
},
|
|
221
221
|
/**
|
|
222
|
-
*
|
|
222
|
+
* Array of trusted hostnames (e.g., ['gitlab.com', 'example.com'])
|
|
223
|
+
* that are allowed to render as clickable links in markdown content.
|
|
224
|
+
* Links to other domains will not be clickable.
|
|
223
225
|
*/
|
|
224
226
|
trustedUrls: {
|
|
225
227
|
type: Array,
|
|
226
228
|
required: false,
|
|
227
|
-
default: () => []
|
|
229
|
+
default: () => [],
|
|
230
|
+
validator: urls => urls.every(url => typeof url === 'string')
|
|
228
231
|
},
|
|
229
232
|
/*
|
|
230
233
|
* The preferred locale for the chat interface.
|
package/package.json
CHANGED
|
@@ -345,6 +345,17 @@ export default {
|
|
|
345
345
|
required: false,
|
|
346
346
|
default: () => '',
|
|
347
347
|
},
|
|
348
|
+
/**
|
|
349
|
+
* Array of trusted hostnames (e.g., ['gitlab.com', 'example.com'])
|
|
350
|
+
* that are allowed to render as clickable links in markdown content.
|
|
351
|
+
* Links to other domains will not be clickable.
|
|
352
|
+
*/
|
|
353
|
+
trustedUrls: {
|
|
354
|
+
type: Array,
|
|
355
|
+
required: false,
|
|
356
|
+
default: () => [],
|
|
357
|
+
validator: (urls) => urls.every((url) => typeof url === 'string'),
|
|
358
|
+
},
|
|
348
359
|
},
|
|
349
360
|
data() {
|
|
350
361
|
return {
|
|
@@ -370,15 +381,7 @@ export default {
|
|
|
370
381
|
!this.isToolApprovalProcessing &&
|
|
371
382
|
!this.isAwaitingToolApproval;
|
|
372
383
|
|
|
373
|
-
|
|
374
|
-
// but isToolApprovalProcessing is stuck at true, we should still enable submit
|
|
375
|
-
const isStuckInProcessing =
|
|
376
|
-
!this.isLoading &&
|
|
377
|
-
!this.isStreaming &&
|
|
378
|
-
!this.isAwaitingToolApproval &&
|
|
379
|
-
this.isToolApprovalProcessing;
|
|
380
|
-
|
|
381
|
-
return shouldAllowSubmit || isStuckInProcessing;
|
|
384
|
+
return shouldAllowSubmit;
|
|
382
385
|
},
|
|
383
386
|
shouldShowThreadList() {
|
|
384
387
|
return this.isMultithreaded && this.currentView === VIEW_TYPES.LIST;
|
|
@@ -484,6 +487,14 @@ export default {
|
|
|
484
487
|
lastMessage && lastMessage.message_type === 'request' && lastMessage.tool_info
|
|
485
488
|
);
|
|
486
489
|
},
|
|
490
|
+
canCancelInternal() {
|
|
491
|
+
// Don't allow cancel while there are pending tool approvals
|
|
492
|
+
if (this.isAwaitingToolApproval) {
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return this.canCancel;
|
|
497
|
+
},
|
|
487
498
|
},
|
|
488
499
|
watch: {
|
|
489
500
|
multiThreadedView(newView) {
|
|
@@ -871,6 +882,7 @@ export default {
|
|
|
871
882
|
:with-feedback="withFeedback"
|
|
872
883
|
:is-tool-approval-processing="isToolApprovalProcessing"
|
|
873
884
|
:working-directory="workingDirectory"
|
|
885
|
+
:trusted-urls="trustedUrls"
|
|
874
886
|
@track-feedback="onTrackFeedback"
|
|
875
887
|
@insert-code-snippet="onInsertCodeSnippet"
|
|
876
888
|
@copy-code-snippet="onCopyCodeSnippet"
|
|
@@ -1029,7 +1041,7 @@ export default {
|
|
|
1029
1041
|
class="!gl-absolute gl-bottom-2 gl-right-2 !gl-rounded-full"
|
|
1030
1042
|
data-testid="chat-prompt-cancel-button"
|
|
1031
1043
|
:aria-label="$options.i18n.CHAT_CANCEL_LABEL"
|
|
1032
|
-
:disabled="!
|
|
1044
|
+
:disabled="!canCancelInternal"
|
|
1033
1045
|
@click="cancelPrompt"
|
|
1034
1046
|
/>
|
|
1035
1047
|
</template>
|
|
@@ -381,6 +381,17 @@ export default {
|
|
|
381
381
|
required: false,
|
|
382
382
|
default: true,
|
|
383
383
|
},
|
|
384
|
+
/**
|
|
385
|
+
* Array of trusted hostnames (e.g., ['gitlab.com', 'example.com'])
|
|
386
|
+
* that are allowed to render as clickable links in markdown content.
|
|
387
|
+
* Links to other domains will not be clickable.
|
|
388
|
+
*/
|
|
389
|
+
trustedUrls: {
|
|
390
|
+
type: Array,
|
|
391
|
+
required: false,
|
|
392
|
+
default: () => [],
|
|
393
|
+
validator: (urls) => urls.every((url) => typeof url === 'string'),
|
|
394
|
+
},
|
|
384
395
|
},
|
|
385
396
|
data() {
|
|
386
397
|
return {
|
|
@@ -894,6 +905,7 @@ export default {
|
|
|
894
905
|
:with-feedback="withFeedback"
|
|
895
906
|
:is-tool-approval-processing="isToolApprovalProcessing"
|
|
896
907
|
:working-directory="workingDirectory"
|
|
908
|
+
:trusted-urls="trustedUrls"
|
|
897
909
|
@track-feedback="onTrackFeedback"
|
|
898
910
|
@insert-code-snippet="onInsertCodeSnippet"
|
|
899
911
|
@copy-code-snippet="onCopyCodeSnippet"
|
|
@@ -49,12 +49,15 @@ export default {
|
|
|
49
49
|
default: true,
|
|
50
50
|
},
|
|
51
51
|
/**
|
|
52
|
-
*
|
|
52
|
+
* Array of trusted hostnames (e.g., ['gitlab.com', 'example.com'])
|
|
53
|
+
* that are allowed to render as clickable links in markdown content.
|
|
54
|
+
* Links to other domains will not be clickable.
|
|
53
55
|
*/
|
|
54
56
|
trustedUrls: {
|
|
55
57
|
type: Array,
|
|
56
58
|
required: false,
|
|
57
59
|
default: () => [],
|
|
60
|
+
validator: (urls) => urls.every((url) => typeof url === 'string'),
|
|
58
61
|
},
|
|
59
62
|
/**
|
|
60
63
|
* Whether the chat should show the feedback link on the assistant messages.
|
|
@@ -82,12 +82,15 @@ export default {
|
|
|
82
82
|
required: true,
|
|
83
83
|
},
|
|
84
84
|
/**
|
|
85
|
-
*
|
|
85
|
+
* Array of trusted hostnames (e.g., ['gitlab.com', 'example.com'])
|
|
86
|
+
* that are allowed to render as clickable links in markdown content.
|
|
87
|
+
* Links to other domains will not be clickable.
|
|
86
88
|
*/
|
|
87
89
|
trustedUrls: {
|
|
88
90
|
type: Array,
|
|
89
91
|
required: false,
|
|
90
92
|
default: () => [],
|
|
93
|
+
validator: (urls) => urls.every((url) => typeof url === 'string'),
|
|
91
94
|
},
|
|
92
95
|
/**
|
|
93
96
|
* Whether the chat should show the feedback link on the assistant messages.
|
|
@@ -149,20 +152,26 @@ export default {
|
|
|
149
152
|
return this.message.contentHtml;
|
|
150
153
|
}
|
|
151
154
|
|
|
152
|
-
return this.renderMarkdown(this.message.content, this.trustedUrls);
|
|
155
|
+
return this.renderMarkdown(this.message.content, { trustedUrls: this.trustedUrls });
|
|
153
156
|
},
|
|
154
157
|
messageContent() {
|
|
155
158
|
if (this.isAssistantMessage && this.isChunk) {
|
|
156
|
-
return this.renderMarkdown(concatUntilEmpty(this.messageChunks),
|
|
159
|
+
return this.renderMarkdown(concatUntilEmpty(this.messageChunks), {
|
|
160
|
+
trustedUrls: this.trustedUrls,
|
|
161
|
+
});
|
|
157
162
|
}
|
|
158
163
|
|
|
159
164
|
return (
|
|
160
|
-
this.renderMarkdown(this.defaultContent, this.trustedUrls) ||
|
|
161
|
-
this.renderMarkdown(concatUntilEmpty(this.message.chunks),
|
|
165
|
+
this.renderMarkdown(this.defaultContent, { trustedUrls: this.trustedUrls }) ||
|
|
166
|
+
this.renderMarkdown(concatUntilEmpty(this.message.chunks), {
|
|
167
|
+
trustedUrls: this.trustedUrls,
|
|
168
|
+
})
|
|
162
169
|
);
|
|
163
170
|
},
|
|
164
171
|
renderedError() {
|
|
165
|
-
return this.renderMarkdown(this.message.errors?.join('; ') || '',
|
|
172
|
+
return this.renderMarkdown(this.message.errors?.join('; ') || '', {
|
|
173
|
+
trustedUrls: this.trustedUrls,
|
|
174
|
+
});
|
|
166
175
|
},
|
|
167
176
|
error() {
|
|
168
177
|
return Boolean(this.message?.errors?.length) && this.message.errors.join('; ');
|
package/src/components/chat/components/duo_chat_message_tool_approval/message_tool_approval.vue
CHANGED
|
@@ -189,13 +189,14 @@ export default {
|
|
|
189
189
|
return this.approvalStatus === TOOL_STATUS.Approved;
|
|
190
190
|
},
|
|
191
191
|
isApproving() {
|
|
192
|
-
return this.
|
|
192
|
+
return this.localProcessingState === PROCESSING_STATE.APPROVING || this.isProcessing;
|
|
193
193
|
},
|
|
194
194
|
isDenying() {
|
|
195
|
-
return this.
|
|
195
|
+
return this.localProcessingState === PROCESSING_STATE.DENYING;
|
|
196
196
|
},
|
|
197
197
|
buttonsDisabled() {
|
|
198
|
-
|
|
198
|
+
// Disable if we've taken action locally OR if parent says we're processing
|
|
199
|
+
return this.localProcessingState !== PROCESSING_STATE.NONE || this.isProcessing;
|
|
199
200
|
},
|
|
200
201
|
approveButtonText() {
|
|
201
202
|
return this.isApproving ? this.$options.i18n.APPROVING_TEXT : this.$options.i18n.APPROVE_TEXT;
|
|
@@ -221,52 +222,46 @@ export default {
|
|
|
221
222
|
},
|
|
222
223
|
},
|
|
223
224
|
watch: {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
this.resetProcessingState();
|
|
225
|
+
approvalStatus(newVal) {
|
|
226
|
+
if (newVal === TOOL_STATUS.Approved) {
|
|
227
|
+
this.collapsed = true;
|
|
228
228
|
}
|
|
229
229
|
},
|
|
230
230
|
},
|
|
231
231
|
methods: {
|
|
232
|
-
|
|
233
|
-
if (this.
|
|
232
|
+
approveWithType(approvalType) {
|
|
233
|
+
if (this.localProcessingState !== PROCESSING_STATE.NONE) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
234
236
|
|
|
235
237
|
this.localProcessingState = PROCESSING_STATE.APPROVING;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
238
|
+
this.$emit('approve-tool', { type: approvalType });
|
|
239
|
+
},
|
|
240
|
+
handleApprove() {
|
|
241
|
+
const approvalType =
|
|
242
|
+
this.primaryApprovalOption.type || acceptedApproveToolPayloads.APPROVE_TOOL_ONCE;
|
|
243
|
+
this.approveWithType(approvalType);
|
|
241
244
|
},
|
|
242
245
|
handlePrimaryApprove() {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
this.localProcessingState = PROCESSING_STATE.APPROVING;
|
|
246
|
-
this.$emit('approve-tool', { type: this.primaryApprovalOption.type });
|
|
246
|
+
this.approveWithType(this.primaryApprovalOption.type);
|
|
247
247
|
},
|
|
248
248
|
handleDropdownSelection(option) {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
this.localProcessingState = PROCESSING_STATE.APPROVING;
|
|
252
|
-
this.$emit('approve-tool', { type: option.type });
|
|
249
|
+
this.approveWithType(option.type);
|
|
253
250
|
},
|
|
254
251
|
handleDeny() {
|
|
255
|
-
if (this.isProcessing) return;
|
|
256
|
-
|
|
257
252
|
this.showDenialReason = true;
|
|
258
253
|
},
|
|
259
254
|
cancelDenial() {
|
|
260
255
|
this.showDenialReason = false;
|
|
261
256
|
this.denialReason = '';
|
|
262
|
-
this.localProcessingState = PROCESSING_STATE.NONE;
|
|
263
257
|
},
|
|
264
258
|
submitDenial() {
|
|
265
|
-
if (this.
|
|
259
|
+
if (this.localProcessingState !== PROCESSING_STATE.NONE) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
266
262
|
|
|
267
263
|
this.localProcessingState = PROCESSING_STATE.DENYING;
|
|
268
264
|
this.$emit('deny-tool', this.denialReason || null);
|
|
269
|
-
// Don't reset state here - wait for isProcessing to change
|
|
270
265
|
},
|
|
271
266
|
resetProcessingState() {
|
|
272
267
|
this.localProcessingState = PROCESSING_STATE.NONE;
|
|
@@ -297,12 +297,15 @@ export default {
|
|
|
297
297
|
default: false,
|
|
298
298
|
},
|
|
299
299
|
/**
|
|
300
|
-
*
|
|
300
|
+
* Array of trusted hostnames (e.g., ['gitlab.com', 'example.com'])
|
|
301
|
+
* that are allowed to render as clickable links in markdown content.
|
|
302
|
+
* Links to other domains will not be clickable.
|
|
301
303
|
*/
|
|
302
304
|
trustedUrls: {
|
|
303
305
|
type: Array,
|
|
304
306
|
required: false,
|
|
305
307
|
default: () => [],
|
|
308
|
+
validator: (urls) => urls.every((url) => typeof url === 'string'),
|
|
306
309
|
},
|
|
307
310
|
/*
|
|
308
311
|
* The preferred locale for the chat interface.
|
|
@@ -279,12 +279,15 @@ export default {
|
|
|
279
279
|
default: false,
|
|
280
280
|
},
|
|
281
281
|
/**
|
|
282
|
-
*
|
|
282
|
+
* Array of trusted hostnames (e.g., ['gitlab.com', 'example.com'])
|
|
283
|
+
* that are allowed to render as clickable links in markdown content.
|
|
284
|
+
* Links to other domains will not be clickable.
|
|
283
285
|
*/
|
|
284
286
|
trustedUrls: {
|
|
285
287
|
type: Array,
|
|
286
288
|
required: false,
|
|
287
289
|
default: () => [],
|
|
290
|
+
validator: (urls) => urls.every((url) => typeof url === 'string'),
|
|
288
291
|
},
|
|
289
292
|
/*
|
|
290
293
|
* The preferred locale for the chat interface.
|