@nuraly/lumenui 0.3.8 → 0.5.0
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/dist/nuralyui.bundle.js +633 -634
- package/dist/nuralyui.bundle.js.gz +0 -0
- package/dist/src/components/canvas/bundle.js +409 -410
- package/dist/src/components/canvas/bundle.js.gz +0 -0
- package/dist/src/components/chatbot/bundle.js +147 -148
- package/dist/src/components/chatbot/bundle.js.gz +0 -0
- package/dist/src/components/chatbot/chatbot.component.d.ts +14 -1
- package/dist/src/components/chatbot/chatbot.component.js +165 -8
- package/dist/src/components/chatbot/chatbot.style.js +6 -9
- package/dist/src/components/chatbot/chatbot.types.d.ts +94 -0
- package/dist/src/components/chatbot/plugins/artifact-plugin.d.ts +44 -0
- package/dist/src/components/chatbot/plugins/artifact-plugin.js +62 -0
- package/dist/src/components/chatbot/templates/artifact-panel.template.d.ts +2 -1
- package/dist/src/components/chatbot/templates/artifact-panel.template.js +4 -5
- package/dist/src/components/chatbot/templates/chatbot-main.template.d.ts +3 -1
- package/dist/src/components/chatbot/templates/chatbot-main.template.js +15 -10
- package/dist/src/components/chatbot/templates/file-upload-area.template.d.ts +5 -6
- package/dist/src/components/chatbot/templates/file-upload-area.template.js +4 -11
- package/dist/src/components/chatbot/templates/input-box.template.d.ts +2 -1
- package/dist/src/components/chatbot/templates/input-box.template.js +25 -26
- package/dist/src/components/chatbot/templates/message.template.d.ts +4 -4
- package/dist/src/components/chatbot/templates/message.template.js +11 -12
- package/dist/src/components/chatbot/templates/suggestion.template.d.ts +3 -9
- package/dist/src/components/chatbot/templates/suggestion.template.js +6 -13
- package/dist/src/components/chatbot/templates/thread-sidebar.template.d.ts +2 -1
- package/dist/src/components/chatbot/templates/thread-sidebar.template.js +11 -12
- package/dist/src/components/chatbot/templates/url-modal.template.d.ts +2 -3
- package/dist/src/components/chatbot/templates/url-modal.template.js +24 -28
- package/dist/src/components/icon/bundle.js +10 -10
- package/dist/src/components/icon/bundle.js.gz +0 -0
- package/dist/src/components/icon/icon-paths.js +1 -0
- package/dist/src/components/iconpicker/bundle.js +1 -1
- package/dist/src/components/iconpicker/bundle.js.gz +0 -0
- package/dist/src/components/panel/bundle.js +1 -1
- package/dist/src/components/panel/bundle.js.gz +0 -0
- package/dist/src/components/tabs/bundle.js +1 -1
- package/dist/src/components/tabs/bundle.js.gz +0 -0
- package/package.json +1 -1
- package/packages/common/dist/VERSIONS.md +1 -1
|
Binary file
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
import { LitElement, TemplateResult } from 'lit';
|
|
7
|
-
import { ChatbotMessage, ChatbotSuggestion, ChatbotSize, ChatbotVariant, ChatbotLoadingType, ChatbotThread, ChatbotModule, ChatbotFile, ChatbotAction, ChatbotArtifact } from './chatbot.types.js';
|
|
7
|
+
import { ChatbotMessage, ChatbotSuggestion, ChatbotSize, ChatbotVariant, ChatbotLoadingType, ChatbotThread, ChatbotModule, ChatbotFile, ChatbotAction, ChatbotArtifact, ChatbotI18nOverrides } from './chatbot.types.js';
|
|
8
8
|
import { ChatbotCoreController } from './core/chatbot-core.controller.js';
|
|
9
9
|
declare const NrChatbotElement_base: (new (...args: any[]) => import("@nuralyui/common/mixins").DependencyAware) & (new (...args: any[]) => import("@nuralyui/common/mixins").ThemeAware) & (new (...args: any[]) => import("@nuralyui/common/mixins").EventHandlerCapable) & (new (...args: any[]) => import("packages/common/src/shared/base-mixin.js").LightDomContent) & typeof LitElement;
|
|
10
10
|
/**
|
|
@@ -64,6 +64,11 @@ export declare class NrChatbotElement extends NrChatbotElement_base {
|
|
|
64
64
|
disabled: boolean;
|
|
65
65
|
/** Custom placeholder text */
|
|
66
66
|
placeholder: string;
|
|
67
|
+
/**
|
|
68
|
+
* Override any UI string. Falls back to the default
|
|
69
|
+
* (from `@lit/localize`) when a key or section is omitted.
|
|
70
|
+
*/
|
|
71
|
+
i18n?: ChatbotI18nOverrides;
|
|
67
72
|
/** Show send button */
|
|
68
73
|
showSendButton: boolean;
|
|
69
74
|
/** Auto-scroll to new messages */
|
|
@@ -127,6 +132,8 @@ export declare class NrChatbotElement extends NrChatbotElement_base {
|
|
|
127
132
|
private selectedUrlFileName;
|
|
128
133
|
private isFilePreviewModalOpen;
|
|
129
134
|
private previewFile;
|
|
135
|
+
private _isDragging;
|
|
136
|
+
private _dragDepth;
|
|
130
137
|
private controllerUnsubscribes;
|
|
131
138
|
private _audio;
|
|
132
139
|
private _audioMode;
|
|
@@ -159,6 +166,7 @@ export declare class NrChatbotElement extends NrChatbotElement_base {
|
|
|
159
166
|
private handleControllerMessageSent;
|
|
160
167
|
private handleControllerMessageReceived;
|
|
161
168
|
private handleControllerError;
|
|
169
|
+
private get resolvedI18n();
|
|
162
170
|
render(): TemplateResult<1>;
|
|
163
171
|
private renderModuleSelectedDisplay;
|
|
164
172
|
private toggleThreadSidebar;
|
|
@@ -195,6 +203,11 @@ export declare class NrChatbotElement extends NrChatbotElement_base {
|
|
|
195
203
|
private handleUrlConfirm;
|
|
196
204
|
private handleUrlAttachFile;
|
|
197
205
|
private handleFileRemove;
|
|
206
|
+
private dragHasFiles;
|
|
207
|
+
private handleDragEnter;
|
|
208
|
+
private handleDragOver;
|
|
209
|
+
private handleDragLeave;
|
|
210
|
+
private handleDrop;
|
|
198
211
|
private handleFilePreview;
|
|
199
212
|
private handleArtifactClick;
|
|
200
213
|
private handleArtifactPanelClose;
|
|
@@ -26,6 +26,79 @@ import { localized, msg } from '@lit/localize';
|
|
|
26
26
|
import styles from './chatbot.style.js';
|
|
27
27
|
import { NuralyUIBaseMixin } from '@nuralyui/common/mixins';
|
|
28
28
|
import { ChatbotSender, ChatbotSize, ChatbotVariant, ChatbotLoadingType, EMPTY_STRING } from './chatbot.types.js';
|
|
29
|
+
const DEFAULT_I18N = {
|
|
30
|
+
input: {
|
|
31
|
+
placeholder: msg('Type your message...'),
|
|
32
|
+
chatInputAriaLabel: msg('Chat input'),
|
|
33
|
+
attachButton: msg('Attach'),
|
|
34
|
+
attachFilesAriaLabel: msg('Attach files'),
|
|
35
|
+
removeFileLabel: msg('Remove file'),
|
|
36
|
+
uploadingLabel: msg('Uploading'),
|
|
37
|
+
uploadingProgress: msg('Uploading…'),
|
|
38
|
+
dropFilesHere: msg('Drop files here to upload'),
|
|
39
|
+
},
|
|
40
|
+
send: {
|
|
41
|
+
sendButton: msg('Send'),
|
|
42
|
+
stopButton: msg('Stop'),
|
|
43
|
+
sendMessageLabel: msg('Send message'),
|
|
44
|
+
stopQueryLabel: msg('Stop query'),
|
|
45
|
+
},
|
|
46
|
+
audio: {
|
|
47
|
+
recordSpeechLabel: msg('Record speech to text'),
|
|
48
|
+
sendVoiceMessageLabel: msg('Send voice message'),
|
|
49
|
+
cancelRecordingLabel: msg('Cancel recording'),
|
|
50
|
+
speechToTextLabel: msg('Speech to text'),
|
|
51
|
+
voiceMessageLabel: msg('Voice message'),
|
|
52
|
+
convertToTextLabel: msg('Convert to text'),
|
|
53
|
+
sendAsVoiceMessageLabel: msg('Send as voice message'),
|
|
54
|
+
},
|
|
55
|
+
modules: {
|
|
56
|
+
moduleSelectionLabel: msg('Select Modules'),
|
|
57
|
+
moduleSearchPlaceholder: msg('Search modules...'),
|
|
58
|
+
moduleSelectAriaLabel: msg('Select modules'),
|
|
59
|
+
modulesSelectedSuffix: msg('modules selected'),
|
|
60
|
+
},
|
|
61
|
+
threads: {
|
|
62
|
+
conversationsTitle: msg('Conversations'),
|
|
63
|
+
bookmarksLabel: msg('Bookmarks'),
|
|
64
|
+
allConversationsLabel: msg('All Conversations'),
|
|
65
|
+
noConversationsLabel: msg('No conversations yet'),
|
|
66
|
+
newChatTitle: msg('New Chat'),
|
|
67
|
+
newConversationLabel: msg('New conversation'),
|
|
68
|
+
removeBookmarkLabel: msg('Remove bookmark'),
|
|
69
|
+
bookmarkLabel: msg('Bookmark'),
|
|
70
|
+
renameLabel: msg('Rename'),
|
|
71
|
+
deleteLabel: msg('Delete'),
|
|
72
|
+
moreOptionsLabel: msg('More options'),
|
|
73
|
+
showThreadsLabel: msg('Show threads'),
|
|
74
|
+
hideThreadsLabel: msg('Hide threads'),
|
|
75
|
+
},
|
|
76
|
+
messages: {
|
|
77
|
+
attachedFilesLabel: msg('Attached files'),
|
|
78
|
+
copyMessageLabel: msg('Copy message'),
|
|
79
|
+
retryMessageLabel: msg('Retry message'),
|
|
80
|
+
retryButton: msg('Retry'),
|
|
81
|
+
startConversationLabel: msg('Start a conversation'),
|
|
82
|
+
suggestionPrefix: msg('Select suggestion: '),
|
|
83
|
+
},
|
|
84
|
+
urlModal: {
|
|
85
|
+
addUrlTitle: msg('Add URL'),
|
|
86
|
+
urlLabel: msg('URL'),
|
|
87
|
+
urlPlaceholder: msg('Enter URL...'),
|
|
88
|
+
loadFromUrlLabel: msg('Load file from URL'),
|
|
89
|
+
selectedFileLabel: msg('Selected file'),
|
|
90
|
+
loadingFromUrlLabel: msg('Loading file from URL...'),
|
|
91
|
+
cancelButton: msg('Cancel'),
|
|
92
|
+
addButton: msg('Add'),
|
|
93
|
+
},
|
|
94
|
+
artifactPanel: {
|
|
95
|
+
copyCodeLabel: msg('Copy code'),
|
|
96
|
+
closePanelLabel: msg('Close panel'),
|
|
97
|
+
},
|
|
98
|
+
loading: {
|
|
99
|
+
agentWorkingLabel: msg('Agent is working...'),
|
|
100
|
+
},
|
|
101
|
+
};
|
|
29
102
|
import { renderChatbotMain, renderFilePreviewModal } from './templates/index.js';
|
|
30
103
|
import { ChatbotAudioController } from './chatbot-audio.controller.js';
|
|
31
104
|
/**
|
|
@@ -132,6 +205,8 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
132
205
|
this.selectedUrlFileName = '';
|
|
133
206
|
this.isFilePreviewModalOpen = false;
|
|
134
207
|
this.previewFile = null;
|
|
208
|
+
this._isDragging = false;
|
|
209
|
+
this._dragDepth = 0;
|
|
135
210
|
// Keep track of controller event unsubscriptions
|
|
136
211
|
this.controllerUnsubscribes = [];
|
|
137
212
|
this._audio = new ChatbotAudioController(this);
|
|
@@ -417,8 +492,24 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
417
492
|
this.isBotTyping = false;
|
|
418
493
|
console.error('Controller error:', data.error);
|
|
419
494
|
}
|
|
495
|
+
get resolvedI18n() {
|
|
496
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
497
|
+
const o = this.i18n;
|
|
498
|
+
return {
|
|
499
|
+
input: Object.assign(Object.assign({}, DEFAULT_I18N.input), ((_a = o === null || o === void 0 ? void 0 : o.input) !== null && _a !== void 0 ? _a : {})),
|
|
500
|
+
send: Object.assign(Object.assign({}, DEFAULT_I18N.send), ((_b = o === null || o === void 0 ? void 0 : o.send) !== null && _b !== void 0 ? _b : {})),
|
|
501
|
+
audio: Object.assign(Object.assign({}, DEFAULT_I18N.audio), ((_c = o === null || o === void 0 ? void 0 : o.audio) !== null && _c !== void 0 ? _c : {})),
|
|
502
|
+
modules: Object.assign(Object.assign({}, DEFAULT_I18N.modules), ((_d = o === null || o === void 0 ? void 0 : o.modules) !== null && _d !== void 0 ? _d : {})),
|
|
503
|
+
threads: Object.assign(Object.assign({}, DEFAULT_I18N.threads), ((_e = o === null || o === void 0 ? void 0 : o.threads) !== null && _e !== void 0 ? _e : {})),
|
|
504
|
+
messages: Object.assign(Object.assign({}, DEFAULT_I18N.messages), ((_f = o === null || o === void 0 ? void 0 : o.messages) !== null && _f !== void 0 ? _f : {})),
|
|
505
|
+
urlModal: Object.assign(Object.assign({}, DEFAULT_I18N.urlModal), ((_g = o === null || o === void 0 ? void 0 : o.urlModal) !== null && _g !== void 0 ? _g : {})),
|
|
506
|
+
artifactPanel: Object.assign(Object.assign({}, DEFAULT_I18N.artifactPanel), ((_h = o === null || o === void 0 ? void 0 : o.artifactPanel) !== null && _h !== void 0 ? _h : {})),
|
|
507
|
+
loading: Object.assign(Object.assign({}, DEFAULT_I18N.loading), ((_j = o === null || o === void 0 ? void 0 : o.loading) !== null && _j !== void 0 ? _j : {})),
|
|
508
|
+
};
|
|
509
|
+
}
|
|
420
510
|
render() {
|
|
421
511
|
var _a;
|
|
512
|
+
const i18n = this.resolvedI18n;
|
|
422
513
|
const templateData = {
|
|
423
514
|
boxed: this.boxed,
|
|
424
515
|
showMessages: this.showMessages,
|
|
@@ -448,6 +539,7 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
448
539
|
showAudioButton: this.showAudioButton,
|
|
449
540
|
audioRecording: this._audio.state,
|
|
450
541
|
audioMode: this._audioMode,
|
|
542
|
+
i18n,
|
|
451
543
|
},
|
|
452
544
|
enableThreads: this.showThreads,
|
|
453
545
|
enableThreadCreation: this.enableThreadCreation,
|
|
@@ -455,21 +547,26 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
455
547
|
threadSidebar: this.showThreads ? {
|
|
456
548
|
threads: this.threads,
|
|
457
549
|
activeThreadId: this.activeThreadId,
|
|
458
|
-
editingThreadId: this._editingThreadId
|
|
550
|
+
editingThreadId: this._editingThreadId,
|
|
551
|
+
i18n,
|
|
459
552
|
} : undefined,
|
|
460
|
-
|
|
553
|
+
enableFileUpload: this.enableFileUpload,
|
|
554
|
+
isDragging: this._isDragging,
|
|
555
|
+
i18n,
|
|
461
556
|
enableArtifacts: this.enableArtifacts,
|
|
462
557
|
artifactPanel: this.enableArtifacts ? {
|
|
463
558
|
artifact: this.selectedArtifact,
|
|
464
559
|
isOpen: this.isArtifactPanelOpen,
|
|
465
|
-
renderContent: (_a = this.renderArtifactContent) !== null && _a !== void 0 ? _a : this.getPluginArtifactRenderer()
|
|
560
|
+
renderContent: (_a = this.renderArtifactContent) !== null && _a !== void 0 ? _a : this.getPluginArtifactRenderer(),
|
|
561
|
+
i18n,
|
|
466
562
|
} : undefined,
|
|
467
563
|
urlModal: this.isUrlModalOpen ? {
|
|
468
564
|
isOpen: this.isUrlModalOpen,
|
|
469
565
|
urlInput: this.urlInput,
|
|
470
566
|
isLoading: this.isUrlLoading,
|
|
471
567
|
error: this.urlModalError,
|
|
472
|
-
selectedFileName: this.selectedUrlFileName
|
|
568
|
+
selectedFileName: this.selectedUrlFileName,
|
|
569
|
+
i18n,
|
|
473
570
|
} : undefined
|
|
474
571
|
};
|
|
475
572
|
const templateHandlers = {
|
|
@@ -518,9 +615,10 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
518
615
|
}
|
|
519
616
|
} : undefined,
|
|
520
617
|
fileUploadArea: {
|
|
521
|
-
|
|
522
|
-
onDragOver: ()
|
|
523
|
-
onDragLeave: ()
|
|
618
|
+
onDragEnter: this.handleDragEnter.bind(this),
|
|
619
|
+
onDragOver: this.handleDragOver.bind(this),
|
|
620
|
+
onDragLeave: this.handleDragLeave.bind(this),
|
|
621
|
+
onDrop: this.handleDrop.bind(this),
|
|
524
622
|
},
|
|
525
623
|
urlModal: this.isUrlModalOpen ? {
|
|
526
624
|
onClose: this.handleUrlModalClose.bind(this),
|
|
@@ -577,7 +675,7 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
577
675
|
}
|
|
578
676
|
return html `
|
|
579
677
|
<span class="module-display-multiple">
|
|
580
|
-
${count} ${
|
|
678
|
+
${count} ${this.resolvedI18n.modules.modulesSelectedSuffix}
|
|
581
679
|
</span>
|
|
582
680
|
`;
|
|
583
681
|
}
|
|
@@ -828,6 +926,59 @@ let NrChatbotElement = class NrChatbotElement extends NuralyUIBaseMixin(LitEleme
|
|
|
828
926
|
var _a;
|
|
829
927
|
(_a = this.controller) === null || _a === void 0 ? void 0 : _a.removeFile(fileId);
|
|
830
928
|
}
|
|
929
|
+
dragHasFiles(e) {
|
|
930
|
+
var _a;
|
|
931
|
+
const types = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.types;
|
|
932
|
+
if (!types)
|
|
933
|
+
return false;
|
|
934
|
+
for (let i = 0; i < types.length; i++) {
|
|
935
|
+
if (types[i] === 'Files')
|
|
936
|
+
return true;
|
|
937
|
+
}
|
|
938
|
+
return false;
|
|
939
|
+
}
|
|
940
|
+
handleDragEnter(e) {
|
|
941
|
+
if (!this.enableFileUpload || this.disabled)
|
|
942
|
+
return;
|
|
943
|
+
if (!this.dragHasFiles(e))
|
|
944
|
+
return;
|
|
945
|
+
e.preventDefault();
|
|
946
|
+
this._dragDepth++;
|
|
947
|
+
this._isDragging = true;
|
|
948
|
+
}
|
|
949
|
+
handleDragOver(e) {
|
|
950
|
+
if (!this.enableFileUpload || this.disabled)
|
|
951
|
+
return;
|
|
952
|
+
if (!this.dragHasFiles(e))
|
|
953
|
+
return;
|
|
954
|
+
e.preventDefault();
|
|
955
|
+
if (e.dataTransfer)
|
|
956
|
+
e.dataTransfer.dropEffect = 'copy';
|
|
957
|
+
}
|
|
958
|
+
handleDragLeave(e) {
|
|
959
|
+
if (!this.enableFileUpload || this.disabled)
|
|
960
|
+
return;
|
|
961
|
+
if (!this.dragHasFiles(e))
|
|
962
|
+
return;
|
|
963
|
+
e.preventDefault();
|
|
964
|
+
this._dragDepth = Math.max(0, this._dragDepth - 1);
|
|
965
|
+
if (this._dragDepth === 0)
|
|
966
|
+
this._isDragging = false;
|
|
967
|
+
}
|
|
968
|
+
handleDrop(e) {
|
|
969
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
970
|
+
var _a, _b;
|
|
971
|
+
if (!this.enableFileUpload || this.disabled)
|
|
972
|
+
return;
|
|
973
|
+
e.preventDefault();
|
|
974
|
+
this._dragDepth = 0;
|
|
975
|
+
this._isDragging = false;
|
|
976
|
+
const files = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files;
|
|
977
|
+
if (!files || files.length === 0)
|
|
978
|
+
return;
|
|
979
|
+
yield ((_b = this.controller) === null || _b === void 0 ? void 0 : _b.uploadFiles(Array.from(files)));
|
|
980
|
+
});
|
|
981
|
+
}
|
|
831
982
|
handleFilePreview(file) {
|
|
832
983
|
this.previewFile = file;
|
|
833
984
|
this.isFilePreviewModalOpen = true;
|
|
@@ -1024,6 +1175,9 @@ __decorate([
|
|
|
1024
1175
|
__decorate([
|
|
1025
1176
|
property({ type: String })
|
|
1026
1177
|
], NrChatbotElement.prototype, "placeholder", void 0);
|
|
1178
|
+
__decorate([
|
|
1179
|
+
property({ type: Object })
|
|
1180
|
+
], NrChatbotElement.prototype, "i18n", void 0);
|
|
1027
1181
|
__decorate([
|
|
1028
1182
|
property({ type: Boolean })
|
|
1029
1183
|
], NrChatbotElement.prototype, "showSendButton", void 0);
|
|
@@ -1129,6 +1283,9 @@ __decorate([
|
|
|
1129
1283
|
__decorate([
|
|
1130
1284
|
state()
|
|
1131
1285
|
], NrChatbotElement.prototype, "previewFile", void 0);
|
|
1286
|
+
__decorate([
|
|
1287
|
+
state()
|
|
1288
|
+
], NrChatbotElement.prototype, "_isDragging", void 0);
|
|
1132
1289
|
NrChatbotElement = __decorate([
|
|
1133
1290
|
localized(),
|
|
1134
1291
|
customElement('nr-chatbot')
|
|
@@ -31,6 +31,7 @@ export default css `
|
|
|
31
31
|
flex: 1;
|
|
32
32
|
min-height: 0;
|
|
33
33
|
min-width: 300px;
|
|
34
|
+
position: relative;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
.chatbot-container--with-sidebar,
|
|
@@ -851,7 +852,9 @@ export default css `
|
|
|
851
852
|
}
|
|
852
853
|
|
|
853
854
|
.file-upload-area {
|
|
854
|
-
display:
|
|
855
|
+
display: flex;
|
|
856
|
+
align-items: center;
|
|
857
|
+
justify-content: center;
|
|
855
858
|
position: absolute;
|
|
856
859
|
top: 0;
|
|
857
860
|
left: 0;
|
|
@@ -861,16 +864,10 @@ export default css `
|
|
|
861
864
|
border: 0.25rem dashed var(--chatbot-user-message-bg);
|
|
862
865
|
border-radius: var(--chatbot-radius);
|
|
863
866
|
z-index: 10;
|
|
867
|
+
pointer-events: auto;
|
|
864
868
|
}
|
|
865
869
|
|
|
866
|
-
.file-upload-area--
|
|
867
|
-
display: flex;
|
|
868
|
-
align-items: center;
|
|
869
|
-
justify-content: center;
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
.file-upload-area--drag-over {
|
|
873
|
-
background-color: rgba(15, 98, 254, 0.1);
|
|
870
|
+
.file-upload-area--dragging {
|
|
874
871
|
border-color: var(--chatbot-user-message-bg);
|
|
875
872
|
}
|
|
876
873
|
|
|
@@ -236,6 +236,100 @@ export interface ChatbotAudioRecordingState {
|
|
|
236
236
|
duration: string;
|
|
237
237
|
bars: number[];
|
|
238
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* Customizable UI strings. Pass a partial object via the
|
|
241
|
+
* chatbot's `i18n` property to override any of the defaults.
|
|
242
|
+
* Defaults come from `@lit/localize`, so translation files keep working.
|
|
243
|
+
*/
|
|
244
|
+
export interface ChatbotI18nInput {
|
|
245
|
+
placeholder: string;
|
|
246
|
+
chatInputAriaLabel: string;
|
|
247
|
+
attachButton: string;
|
|
248
|
+
attachFilesAriaLabel: string;
|
|
249
|
+
removeFileLabel: string;
|
|
250
|
+
uploadingLabel: string;
|
|
251
|
+
uploadingProgress: string;
|
|
252
|
+
dropFilesHere: string;
|
|
253
|
+
}
|
|
254
|
+
export interface ChatbotI18nSend {
|
|
255
|
+
sendButton: string;
|
|
256
|
+
stopButton: string;
|
|
257
|
+
sendMessageLabel: string;
|
|
258
|
+
stopQueryLabel: string;
|
|
259
|
+
}
|
|
260
|
+
export interface ChatbotI18nAudio {
|
|
261
|
+
recordSpeechLabel: string;
|
|
262
|
+
sendVoiceMessageLabel: string;
|
|
263
|
+
cancelRecordingLabel: string;
|
|
264
|
+
speechToTextLabel: string;
|
|
265
|
+
voiceMessageLabel: string;
|
|
266
|
+
convertToTextLabel: string;
|
|
267
|
+
sendAsVoiceMessageLabel: string;
|
|
268
|
+
}
|
|
269
|
+
export interface ChatbotI18nModules {
|
|
270
|
+
moduleSelectionLabel: string;
|
|
271
|
+
moduleSearchPlaceholder: string;
|
|
272
|
+
moduleSelectAriaLabel: string;
|
|
273
|
+
modulesSelectedSuffix: string;
|
|
274
|
+
}
|
|
275
|
+
export interface ChatbotI18nThreads {
|
|
276
|
+
conversationsTitle: string;
|
|
277
|
+
bookmarksLabel: string;
|
|
278
|
+
allConversationsLabel: string;
|
|
279
|
+
noConversationsLabel: string;
|
|
280
|
+
newChatTitle: string;
|
|
281
|
+
newConversationLabel: string;
|
|
282
|
+
removeBookmarkLabel: string;
|
|
283
|
+
bookmarkLabel: string;
|
|
284
|
+
renameLabel: string;
|
|
285
|
+
deleteLabel: string;
|
|
286
|
+
moreOptionsLabel: string;
|
|
287
|
+
showThreadsLabel: string;
|
|
288
|
+
hideThreadsLabel: string;
|
|
289
|
+
}
|
|
290
|
+
export interface ChatbotI18nMessages {
|
|
291
|
+
attachedFilesLabel: string;
|
|
292
|
+
copyMessageLabel: string;
|
|
293
|
+
retryMessageLabel: string;
|
|
294
|
+
retryButton: string;
|
|
295
|
+
startConversationLabel: string;
|
|
296
|
+
suggestionPrefix: string;
|
|
297
|
+
}
|
|
298
|
+
export interface ChatbotI18nUrlModal {
|
|
299
|
+
addUrlTitle: string;
|
|
300
|
+
urlLabel: string;
|
|
301
|
+
urlPlaceholder: string;
|
|
302
|
+
loadFromUrlLabel: string;
|
|
303
|
+
selectedFileLabel: string;
|
|
304
|
+
loadingFromUrlLabel: string;
|
|
305
|
+
cancelButton: string;
|
|
306
|
+
addButton: string;
|
|
307
|
+
}
|
|
308
|
+
export interface ChatbotI18nArtifactPanel {
|
|
309
|
+
copyCodeLabel: string;
|
|
310
|
+
closePanelLabel: string;
|
|
311
|
+
}
|
|
312
|
+
export interface ChatbotI18nLoading {
|
|
313
|
+
agentWorkingLabel: string;
|
|
314
|
+
}
|
|
315
|
+
export interface ChatbotI18n {
|
|
316
|
+
input: ChatbotI18nInput;
|
|
317
|
+
send: ChatbotI18nSend;
|
|
318
|
+
audio: ChatbotI18nAudio;
|
|
319
|
+
modules: ChatbotI18nModules;
|
|
320
|
+
threads: ChatbotI18nThreads;
|
|
321
|
+
messages: ChatbotI18nMessages;
|
|
322
|
+
urlModal: ChatbotI18nUrlModal;
|
|
323
|
+
artifactPanel: ChatbotI18nArtifactPanel;
|
|
324
|
+
loading: ChatbotI18nLoading;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Partial override shape for the chatbot's `i18n` property.
|
|
328
|
+
* Each section is optional, and within each section each key is optional.
|
|
329
|
+
*/
|
|
330
|
+
export type ChatbotI18nOverrides = {
|
|
331
|
+
[K in keyof ChatbotI18n]?: Partial<ChatbotI18n[K]>;
|
|
332
|
+
};
|
|
239
333
|
/**
|
|
240
334
|
* Constants
|
|
241
335
|
*/
|
|
@@ -58,6 +58,50 @@ export declare class ArtifactPlugin extends ChatPluginBase implements ChatbotPlu
|
|
|
58
58
|
getAllArtifacts(): ChatbotArtifact[];
|
|
59
59
|
/** Get all artifacts belonging to a specific message */
|
|
60
60
|
getArtifactsForMessage(messageId: string): ChatbotArtifact[];
|
|
61
|
+
/**
|
|
62
|
+
* Force artifact extraction on a specific message NOW, regardless of
|
|
63
|
+
* streaming state. Useful when structured content arrives via a
|
|
64
|
+
* side-channel (e.g. tool result events delivered out-of-band) and the
|
|
65
|
+
* caller wants the artifact card to appear before the stream's
|
|
66
|
+
* `processing:end` fires.
|
|
67
|
+
*
|
|
68
|
+
* <p>Idempotent: if the message has already been processed
|
|
69
|
+
* (`metadata.hasArtifacts === true`), this is a no-op. The regular
|
|
70
|
+
* `processing:end` handler will also skip the message later for the
|
|
71
|
+
* same reason, so calling this method early does NOT cause duplicate
|
|
72
|
+
* processing on stream completion.
|
|
73
|
+
*
|
|
74
|
+
* <p>Typical usage from outside the plugin:
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const artifactPlugin = new ArtifactPlugin();
|
|
77
|
+
* const controller = new ChatbotCoreController({
|
|
78
|
+
* plugins: [new MarkdownPlugin(), artifactPlugin],
|
|
79
|
+
* // ...
|
|
80
|
+
* });
|
|
81
|
+
*
|
|
82
|
+
* // When a tool result arrives via a custom side-channel:
|
|
83
|
+
* provider.onMessage('TOOL_RESULT_JSON', (msg) => {
|
|
84
|
+
* const messages = controller.getMessages();
|
|
85
|
+
* const lastBotMsg = [...messages].reverse()
|
|
86
|
+
* .find(m => m.sender === ChatbotSender.Bot);
|
|
87
|
+
* if (lastBotMsg) {
|
|
88
|
+
* // 1) Append the fenced content to the bot message text
|
|
89
|
+
* controller.messageHandler.appendToBotMessage(
|
|
90
|
+
* lastBotMsg.id,
|
|
91
|
+
* '\n\n```json\n' + msg.content + '\n```\n\n'
|
|
92
|
+
* );
|
|
93
|
+
* // 2) Trigger artifact extraction right away
|
|
94
|
+
* artifactPlugin.processNow(lastBotMsg.id);
|
|
95
|
+
* }
|
|
96
|
+
* });
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @param messageId id of the bot message to process. If not found, or
|
|
100
|
+
* not a bot message, returns false.
|
|
101
|
+
* @returns true when the message was processed (or rebuilt from
|
|
102
|
+
* metadata); false when skipped or message not found.
|
|
103
|
+
*/
|
|
104
|
+
processNow(messageId: string): boolean;
|
|
61
105
|
/**
|
|
62
106
|
* Try to extract a meaningful title from the first comment line of the code.
|
|
63
107
|
* Falls back to a generic "Code Snippet #N" title.
|
|
@@ -196,6 +196,68 @@ export class ArtifactPlugin extends ChatPluginBase {
|
|
|
196
196
|
getArtifactsForMessage(messageId) {
|
|
197
197
|
return Array.from(this.artifacts.values()).filter(a => a.messageId === messageId);
|
|
198
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Force artifact extraction on a specific message NOW, regardless of
|
|
201
|
+
* streaming state. Useful when structured content arrives via a
|
|
202
|
+
* side-channel (e.g. tool result events delivered out-of-band) and the
|
|
203
|
+
* caller wants the artifact card to appear before the stream's
|
|
204
|
+
* `processing:end` fires.
|
|
205
|
+
*
|
|
206
|
+
* <p>Idempotent: if the message has already been processed
|
|
207
|
+
* (`metadata.hasArtifacts === true`), this is a no-op. The regular
|
|
208
|
+
* `processing:end` handler will also skip the message later for the
|
|
209
|
+
* same reason, so calling this method early does NOT cause duplicate
|
|
210
|
+
* processing on stream completion.
|
|
211
|
+
*
|
|
212
|
+
* <p>Typical usage from outside the plugin:
|
|
213
|
+
* ```typescript
|
|
214
|
+
* const artifactPlugin = new ArtifactPlugin();
|
|
215
|
+
* const controller = new ChatbotCoreController({
|
|
216
|
+
* plugins: [new MarkdownPlugin(), artifactPlugin],
|
|
217
|
+
* // ...
|
|
218
|
+
* });
|
|
219
|
+
*
|
|
220
|
+
* // When a tool result arrives via a custom side-channel:
|
|
221
|
+
* provider.onMessage('TOOL_RESULT_JSON', (msg) => {
|
|
222
|
+
* const messages = controller.getMessages();
|
|
223
|
+
* const lastBotMsg = [...messages].reverse()
|
|
224
|
+
* .find(m => m.sender === ChatbotSender.Bot);
|
|
225
|
+
* if (lastBotMsg) {
|
|
226
|
+
* // 1) Append the fenced content to the bot message text
|
|
227
|
+
* controller.messageHandler.appendToBotMessage(
|
|
228
|
+
* lastBotMsg.id,
|
|
229
|
+
* '\n\n```json\n' + msg.content + '\n```\n\n'
|
|
230
|
+
* );
|
|
231
|
+
* // 2) Trigger artifact extraction right away
|
|
232
|
+
* artifactPlugin.processNow(lastBotMsg.id);
|
|
233
|
+
* }
|
|
234
|
+
* });
|
|
235
|
+
* ```
|
|
236
|
+
*
|
|
237
|
+
* @param messageId id of the bot message to process. If not found, or
|
|
238
|
+
* not a bot message, returns false.
|
|
239
|
+
* @returns true when the message was processed (or rebuilt from
|
|
240
|
+
* metadata); false when skipped or message not found.
|
|
241
|
+
*/
|
|
242
|
+
processNow(messageId) {
|
|
243
|
+
var _a;
|
|
244
|
+
if (!this.controller || typeof this.controller.getMessages !== 'function') {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
const messages = this.controller.getMessages() || [];
|
|
248
|
+
const message = messages.find(m => m.id === messageId);
|
|
249
|
+
if (!message || message.sender !== ChatbotSender.Bot) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
if ((_a = message.metadata) === null || _a === void 0 ? void 0 : _a.hasArtifacts) {
|
|
253
|
+
// Already processed — but rebuild the in-memory artifacts Map so
|
|
254
|
+
// callers can immediately resolve artifact IDs via getArtifact().
|
|
255
|
+
this.rebuildArtifactsFromMetadata(message);
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
this.processMessage(message);
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
199
261
|
// ── Private helpers ────────────────────────────────────────────────
|
|
200
262
|
/**
|
|
201
263
|
* Try to extract a meaningful title from the first comment line of the code.
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
import { nothing, TemplateResult } from 'lit';
|
|
7
|
-
import type { ChatbotArtifact } from '../chatbot.types.js';
|
|
7
|
+
import type { ChatbotArtifact, ChatbotI18n } from '../chatbot.types.js';
|
|
8
8
|
export interface ArtifactPanelTemplateData {
|
|
9
9
|
artifact: ChatbotArtifact | null;
|
|
10
10
|
isOpen: boolean;
|
|
11
11
|
/** Custom content renderer. Return undefined/empty to fall back to default. */
|
|
12
12
|
renderContent?: (artifact: ChatbotArtifact) => TemplateResult | undefined;
|
|
13
|
+
i18n: ChatbotI18n;
|
|
13
14
|
}
|
|
14
15
|
export interface ArtifactPanelTemplateHandlers {
|
|
15
16
|
onClose: () => void;
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { html, nothing } from 'lit';
|
|
7
7
|
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
8
|
-
import { msg } from '@lit/localize';
|
|
9
8
|
import { getLangDisplayName, renderMarkdown } from '../utils/index.js';
|
|
10
9
|
/** Render the content area based on language */
|
|
11
10
|
function renderArtifactContent(artifact) {
|
|
@@ -58,16 +57,16 @@ export function renderArtifactPanel(data, handlers) {
|
|
|
58
57
|
size="small"
|
|
59
58
|
.icon=${['copy']}
|
|
60
59
|
@click=${() => handlers.onCopy(artifact)}
|
|
61
|
-
title="${
|
|
62
|
-
aria-label="${
|
|
60
|
+
title="${data.i18n.artifactPanel.copyCodeLabel}"
|
|
61
|
+
aria-label="${data.i18n.artifactPanel.copyCodeLabel}"
|
|
63
62
|
></nr-button>
|
|
64
63
|
<nr-button
|
|
65
64
|
type="text"
|
|
66
65
|
size="small"
|
|
67
66
|
.icon=${['x']}
|
|
68
67
|
@click=${handlers.onClose}
|
|
69
|
-
title="${
|
|
70
|
-
aria-label="${
|
|
68
|
+
title="${data.i18n.artifactPanel.closePanelLabel}"
|
|
69
|
+
aria-label="${data.i18n.artifactPanel.closePanelLabel}"
|
|
71
70
|
></nr-button>
|
|
72
71
|
</div>
|
|
73
72
|
</div>
|
|
@@ -11,7 +11,7 @@ import { ThreadSidebarTemplateData, ThreadSidebarTemplateHandlers } from './thre
|
|
|
11
11
|
import { FileUploadAreaTemplateHandlers } from './file-upload-area.template.js';
|
|
12
12
|
import { UrlModalTemplateData, UrlModalTemplateHandlers } from './url-modal.template.js';
|
|
13
13
|
import { ArtifactPanelTemplateData, ArtifactPanelTemplateHandlers } from './artifact-panel.template.js';
|
|
14
|
-
import { ChatbotMessage, ChatbotSuggestion, ChatbotLoadingType } from '../chatbot.types.js';
|
|
14
|
+
import { ChatbotMessage, ChatbotSuggestion, ChatbotLoadingType, ChatbotI18n } from '../chatbot.types.js';
|
|
15
15
|
export interface ChatbotMainTemplateData {
|
|
16
16
|
boxed?: boolean;
|
|
17
17
|
/** Show messages area (set to false for input-only mode) */
|
|
@@ -27,7 +27,9 @@ export interface ChatbotMainTemplateData {
|
|
|
27
27
|
enableThreadCreation: boolean;
|
|
28
28
|
isThreadSidebarOpen: boolean;
|
|
29
29
|
threadSidebar?: ThreadSidebarTemplateData;
|
|
30
|
+
enableFileUpload: boolean;
|
|
30
31
|
isDragging: boolean;
|
|
32
|
+
i18n: ChatbotI18n;
|
|
31
33
|
urlModal?: UrlModalTemplateData;
|
|
32
34
|
enableArtifacts?: boolean;
|
|
33
35
|
artifactPanel?: ArtifactPanelTemplateData;
|