@kodaris/krubble-app-components 1.0.70 → 1.0.72
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/chatbot.d.ts +137 -26
- package/dist/chatbot.d.ts.map +1 -1
- package/dist/chatbot.js +881 -206
- package/dist/chatbot.js.map +1 -1
- package/dist/krubble-app.bundled.js +878 -206
- package/dist/krubble-app.bundled.js.map +1 -1
- package/dist/krubble-app.bundled.min.js +563 -175
- package/dist/krubble-app.bundled.min.js.map +1 -1
- package/dist/krubble-app.umd.js +878 -206
- package/dist/krubble-app.umd.js.map +1 -1
- package/dist/krubble-app.umd.min.js +579 -191
- package/dist/krubble-app.umd.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -5567,7 +5567,7 @@ const ACCEPTED_IMAGE_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/web
|
|
|
5567
5567
|
* ## Usage
|
|
5568
5568
|
* ```html
|
|
5569
5569
|
* <kr-chatbot
|
|
5570
|
-
*
|
|
5570
|
+
* label="AI Assistant"
|
|
5571
5571
|
* .send=${(params) => {
|
|
5572
5572
|
* return fetch('/api/ai/chat/stream', {
|
|
5573
5573
|
* method: 'POST',
|
|
@@ -5610,16 +5610,25 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
5610
5610
|
/**
|
|
5611
5611
|
* Callback function for sending messages. Receives the user's message and
|
|
5612
5612
|
* current conversation history. Must return a Response with a streaming SSE body.
|
|
5613
|
+
*
|
|
5614
|
+
* Optional — when not set, the chatbot uses its built-in default that streams
|
|
5615
|
+
* from the Kodaris Bedrock conversation endpoints. Set this to override.
|
|
5613
5616
|
*/
|
|
5614
5617
|
this.send = null;
|
|
5615
5618
|
/**
|
|
5616
5619
|
* Callback function called when the user clears the conversation.
|
|
5617
5620
|
* Must return a Promise — messages are only cleared if it resolves.
|
|
5621
|
+
*
|
|
5622
|
+
* Optional — when not set, the chatbot uses its built-in default that clears
|
|
5623
|
+
* the Kodaris Bedrock conversation state. Set this to override.
|
|
5618
5624
|
*/
|
|
5619
5625
|
this.clear = null;
|
|
5620
5626
|
/**
|
|
5621
5627
|
* Callback function called on init to load existing conversation messages.
|
|
5622
5628
|
* Must return a Promise that resolves with an array of KRChatbotMessage.
|
|
5629
|
+
*
|
|
5630
|
+
* Optional — when not set, the chatbot uses its built-in default that loads
|
|
5631
|
+
* existing messages from the Kodaris Bedrock conversation. Set this to override.
|
|
5623
5632
|
*/
|
|
5624
5633
|
this.load = null;
|
|
5625
5634
|
/**
|
|
@@ -5628,17 +5637,19 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
5628
5637
|
*/
|
|
5629
5638
|
this.messages = [];
|
|
5630
5639
|
/**
|
|
5631
|
-
* Header
|
|
5640
|
+
* Header label text.
|
|
5632
5641
|
*/
|
|
5633
|
-
this.
|
|
5634
|
-
/**
|
|
5635
|
-
* Header subtitle text (shown below title with a green status dot).
|
|
5636
|
-
*/
|
|
5637
|
-
this.subtitle = '';
|
|
5642
|
+
this.label = 'Kat';
|
|
5638
5643
|
/**
|
|
5639
5644
|
* Input placeholder text.
|
|
5640
5645
|
*/
|
|
5641
5646
|
this.placeholder = 'Type a message...';
|
|
5647
|
+
/**
|
|
5648
|
+
* Skills the user can invoke by typing `/` in the composer. Selecting one
|
|
5649
|
+
* inserts `/name ` into the message. The `/` menu shows the first 15 (filtered
|
|
5650
|
+
* as the user types); "Browse all skills" opens a dialog with the full list.
|
|
5651
|
+
*/
|
|
5652
|
+
this.skills = [];
|
|
5642
5653
|
/**
|
|
5643
5654
|
* Whether the chat panel is open. Only relevant in floating mode.
|
|
5644
5655
|
*/
|
|
@@ -5649,15 +5660,39 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
5649
5660
|
* then driven via the `open()` / `close()` / `toggle()` methods.
|
|
5650
5661
|
*/
|
|
5651
5662
|
this.hideToggle = false;
|
|
5663
|
+
/**
|
|
5664
|
+
* Layout mode.
|
|
5665
|
+
* - `'floating'` (default): the chatbot is a fixed bottom-right widget with a
|
|
5666
|
+
* toggle button, and the panel can be dragged and resized. This is the
|
|
5667
|
+
* traditional chat-widget appearance.
|
|
5668
|
+
* - `'inline'`: the chatbot drops its fixed positioning and fills its parent
|
|
5669
|
+
* container (100% width/height, no border radius/shadow, no toggle, no
|
|
5670
|
+
* drag/resize). The panel is always open. Use this to embed the chat as a
|
|
5671
|
+
* full page or panel region.
|
|
5672
|
+
*/
|
|
5673
|
+
this.variant = 'floating';
|
|
5652
5674
|
// --- @state (internal) ---
|
|
5653
5675
|
this._inputValue = '';
|
|
5654
5676
|
this._isStreaming = false;
|
|
5655
|
-
this._statusText = '';
|
|
5656
5677
|
this._error = '';
|
|
5657
5678
|
/** Images staged in the composer, before the message is sent. */
|
|
5658
|
-
this.
|
|
5679
|
+
this._pendingInternalFiles = [];
|
|
5659
5680
|
/** True while a file is being dragged over the panel (shows the drop overlay). */
|
|
5660
5681
|
this._isDraggingFile = false;
|
|
5682
|
+
/** Whether the `/` skill menu is open above the composer. */
|
|
5683
|
+
this._skillMenuOpened = false;
|
|
5684
|
+
/** Current `/` query (text after the slash), used to filter the skill menu. */
|
|
5685
|
+
this._skillQuery = '';
|
|
5686
|
+
/** Highlighted item in the skill menu for keyboard navigation (-1 = none). */
|
|
5687
|
+
this._skillHighlighted = 0;
|
|
5688
|
+
/** Index of the message whose copy button just flashed "Copied" (-1 = none). */
|
|
5689
|
+
this._copiedIndex = -1;
|
|
5690
|
+
/** Whether the "Browse all skills" dialog is open. */
|
|
5691
|
+
this._skillBrowseOpened = false;
|
|
5692
|
+
/** Active tab in the browse dialog. */
|
|
5693
|
+
this._skillBrowseSource = 'org';
|
|
5694
|
+
/** Search text in the browse dialog. */
|
|
5695
|
+
this._skillBrowseQuery = '';
|
|
5661
5696
|
this._handleMouseMove = (e) => {
|
|
5662
5697
|
if (this._isDragging) {
|
|
5663
5698
|
let newLeft = this._dragStartLeft + (e.clientX - this._dragStartX);
|
|
@@ -5719,12 +5754,27 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
5719
5754
|
// --- Lifecycle ---
|
|
5720
5755
|
connectedCallback() {
|
|
5721
5756
|
super.connectedCallback();
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5757
|
+
// Default to loading existing messages from the Kodaris Bedrock conversation
|
|
5758
|
+
// when the consumer hasn't provided their own `load`. The endpoint returns
|
|
5759
|
+
// messages already in KRChatbotMessage shape ({ type, content, images }), so
|
|
5760
|
+
// they pass straight through.
|
|
5761
|
+
if (!this.load) {
|
|
5762
|
+
this.load = () => KRHttp.fetch({
|
|
5763
|
+
url: '/api/system/integration/aws/bedrock/getConversationMessages',
|
|
5764
|
+
})
|
|
5765
|
+
.then((r) => r.json())
|
|
5766
|
+
.then((res) => res.data || []);
|
|
5767
|
+
}
|
|
5768
|
+
this.load().then((messages) => {
|
|
5769
|
+
if (messages && messages.length) {
|
|
5770
|
+
this.messages = messages;
|
|
5771
|
+
}
|
|
5772
|
+
}).catch(() => { });
|
|
5773
|
+
// Inline mode fills its container and is always open — the floating widget's
|
|
5774
|
+
// toggle/drag/resize state (including any persisted layout) doesn't apply.
|
|
5775
|
+
if (this.variant === 'inline') {
|
|
5776
|
+
this.opened = true;
|
|
5777
|
+
return;
|
|
5728
5778
|
}
|
|
5729
5779
|
this._restoreState();
|
|
5730
5780
|
}
|
|
@@ -5737,10 +5787,10 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
5737
5787
|
document.removeEventListener('mousemove', this._handleMouseMove);
|
|
5738
5788
|
document.removeEventListener('mouseup', this._handleMouseUp);
|
|
5739
5789
|
// Release any object URLs still held by staged attachments.
|
|
5740
|
-
this.
|
|
5790
|
+
this._pendingInternalFiles.forEach((p) => URL.revokeObjectURL(p.previewUrl));
|
|
5741
5791
|
}
|
|
5742
5792
|
updated(changed) {
|
|
5743
|
-
if (changed.has('messages')
|
|
5793
|
+
if (changed.has('messages')) {
|
|
5744
5794
|
if (!this._userHasScrolledUp && !this._isStreaming && this._messagesEl) {
|
|
5745
5795
|
requestAnimationFrame(() => {
|
|
5746
5796
|
if (this._messagesEl) {
|
|
@@ -5756,6 +5806,40 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
5756
5806
|
}
|
|
5757
5807
|
}, 200);
|
|
5758
5808
|
}
|
|
5809
|
+
// Position the fixed skill menu above the composer, following the krubble
|
|
5810
|
+
// select-field pattern (fixed element positioned from the trigger's rect).
|
|
5811
|
+
if (this._skillMenuOpened) {
|
|
5812
|
+
this._positionSkillMenu();
|
|
5813
|
+
}
|
|
5814
|
+
// Keep the keyboard-highlighted skill scrolled into view.
|
|
5815
|
+
if (changed.has('_skillHighlighted') && this._skillMenuOpened) {
|
|
5816
|
+
this._skillMenuEl
|
|
5817
|
+
?.querySelector('.skill-menu__item--highlighted')
|
|
5818
|
+
?.scrollIntoView({ block: 'nearest' });
|
|
5819
|
+
}
|
|
5820
|
+
}
|
|
5821
|
+
/** Anchor the fixed skill menu to the composer, opening upward above it. */
|
|
5822
|
+
_positionSkillMenu() {
|
|
5823
|
+
requestAnimationFrame(() => {
|
|
5824
|
+
if (!this._skillMenuEl || !this._inputWrapperEl) {
|
|
5825
|
+
return;
|
|
5826
|
+
}
|
|
5827
|
+
const inputRect = this._inputWrapperEl.getBoundingClientRect();
|
|
5828
|
+
this._skillMenuEl.style.left = inputRect.left + 'px';
|
|
5829
|
+
this._skillMenuEl.style.width = inputRect.width + 'px';
|
|
5830
|
+
// Bound the menu by the chat panel's own top edge so it stays within the
|
|
5831
|
+
// widget. In floating mode that keeps it inside the card; in inline mode the
|
|
5832
|
+
// panel top sits just below the app header/breadcrumb, so it stays clear of
|
|
5833
|
+
// those too. An 8px gap keeps it off both edges.
|
|
5834
|
+
const topLimit = this._panelEl.getBoundingClientRect().top + 8;
|
|
5835
|
+
const spaceAbove = inputRect.top - 8 - topLimit;
|
|
5836
|
+
this._skillMenuEl.style.maxHeight = spaceAbove + 'px';
|
|
5837
|
+
// Measure after the cap is applied so the upward anchor uses the real
|
|
5838
|
+
// height, then clamp the top edge to the panel bound.
|
|
5839
|
+
const menuRect = this._skillMenuEl.getBoundingClientRect();
|
|
5840
|
+
const top = Math.max(topLimit, inputRect.top - menuRect.height - 8);
|
|
5841
|
+
this._skillMenuEl.style.top = top + 'px';
|
|
5842
|
+
});
|
|
5759
5843
|
}
|
|
5760
5844
|
// --- Public methods ---
|
|
5761
5845
|
/**
|
|
@@ -5814,6 +5898,10 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
5814
5898
|
}
|
|
5815
5899
|
}
|
|
5816
5900
|
_handleHeaderMouseDown(e) {
|
|
5901
|
+
// Inline mode fills its parent — dragging the panel doesn't apply.
|
|
5902
|
+
if (this.variant === 'inline') {
|
|
5903
|
+
return;
|
|
5904
|
+
}
|
|
5817
5905
|
// Ignore clicks on buttons inside the header
|
|
5818
5906
|
if (e.target.closest('button')) {
|
|
5819
5907
|
return;
|
|
@@ -5839,6 +5927,10 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
5839
5927
|
document.addEventListener('mouseup', this._handleMouseUp);
|
|
5840
5928
|
}
|
|
5841
5929
|
_handleResizeMouseDown(e) {
|
|
5930
|
+
// Inline mode fills its parent — resizing the panel doesn't apply.
|
|
5931
|
+
if (this.variant === 'inline') {
|
|
5932
|
+
return;
|
|
5933
|
+
}
|
|
5842
5934
|
if (!this._panelEl) {
|
|
5843
5935
|
return;
|
|
5844
5936
|
}
|
|
@@ -5941,13 +6033,129 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
5941
6033
|
const textarea = e.target;
|
|
5942
6034
|
textarea.style.height = 'auto';
|
|
5943
6035
|
textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px';
|
|
6036
|
+
// Open the skill menu while the message is a `/` command being typed (a
|
|
6037
|
+
// leading slash with no space yet). The text after the slash filters it.
|
|
6038
|
+
const slashMatch = this._inputValue.match(/^\/(\S*)$/);
|
|
6039
|
+
if (slashMatch && this.skills.length) {
|
|
6040
|
+
this._skillMenuOpened = true;
|
|
6041
|
+
this._skillQuery = slashMatch[1];
|
|
6042
|
+
this._skillHighlighted = 0;
|
|
6043
|
+
}
|
|
6044
|
+
else {
|
|
6045
|
+
this._skillMenuOpened = false;
|
|
6046
|
+
}
|
|
5944
6047
|
}
|
|
5945
6048
|
_handleKeyDown(e) {
|
|
6049
|
+
// When the skill menu is open, arrow keys / Enter / Escape drive it. The two
|
|
6050
|
+
// top actions (Attach Files, Browse All Skills) are index 0 and 1, then the
|
|
6051
|
+
// filtered skills follow — all navigable as one list.
|
|
6052
|
+
if (this._skillMenuOpened) {
|
|
6053
|
+
const count = 2 + this._filteredSkills().length;
|
|
6054
|
+
if (e.key === 'ArrowDown') {
|
|
6055
|
+
e.preventDefault();
|
|
6056
|
+
this._skillHighlighted = (this._skillHighlighted + 1) % count;
|
|
6057
|
+
return;
|
|
6058
|
+
}
|
|
6059
|
+
if (e.key === 'ArrowUp') {
|
|
6060
|
+
e.preventDefault();
|
|
6061
|
+
this._skillHighlighted = (this._skillHighlighted - 1 + count) % count;
|
|
6062
|
+
return;
|
|
6063
|
+
}
|
|
6064
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
6065
|
+
e.preventDefault();
|
|
6066
|
+
this._activateSkillMenuItem(this._skillHighlighted);
|
|
6067
|
+
return;
|
|
6068
|
+
}
|
|
6069
|
+
if (e.key === 'Escape') {
|
|
6070
|
+
e.preventDefault();
|
|
6071
|
+
this._skillMenuOpened = false;
|
|
6072
|
+
return;
|
|
6073
|
+
}
|
|
6074
|
+
}
|
|
5946
6075
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
5947
6076
|
e.preventDefault();
|
|
5948
6077
|
this._handleSubmit();
|
|
5949
6078
|
}
|
|
5950
6079
|
}
|
|
6080
|
+
/** Run the skill-menu item at the given flat index (0/1 = actions, then skills). */
|
|
6081
|
+
_activateSkillMenuItem(index) {
|
|
6082
|
+
if (index === 0) {
|
|
6083
|
+
this._openFilePicker();
|
|
6084
|
+
return;
|
|
6085
|
+
}
|
|
6086
|
+
if (index === 1) {
|
|
6087
|
+
this._handleSkillBrowseOpen();
|
|
6088
|
+
return;
|
|
6089
|
+
}
|
|
6090
|
+
const skill = this._filteredSkills()[index - 2];
|
|
6091
|
+
if (skill) {
|
|
6092
|
+
this._handleSkillSelect(skill);
|
|
6093
|
+
}
|
|
6094
|
+
}
|
|
6095
|
+
// --- Skills ---
|
|
6096
|
+
/** Skills matching the current `/` query, capped at the first 15. */
|
|
6097
|
+
_filteredSkills() {
|
|
6098
|
+
const query = this._skillQuery.toLowerCase();
|
|
6099
|
+
return this.skills
|
|
6100
|
+
.filter((skill) => skill.name.toLowerCase().includes(query) ||
|
|
6101
|
+
skill.label.toLowerCase().includes(query))
|
|
6102
|
+
.slice(0, 15);
|
|
6103
|
+
}
|
|
6104
|
+
/** The `+` button toggles the skill/attachment menu open (showing all skills). */
|
|
6105
|
+
_handlePlusClick() {
|
|
6106
|
+
if (this._skillMenuOpened) {
|
|
6107
|
+
this._skillMenuOpened = false;
|
|
6108
|
+
return;
|
|
6109
|
+
}
|
|
6110
|
+
this._skillQuery = '';
|
|
6111
|
+
this._skillHighlighted = 0;
|
|
6112
|
+
this._skillMenuOpened = true;
|
|
6113
|
+
}
|
|
6114
|
+
/** Insert `/name ` into the composer and focus it, ready for the message. */
|
|
6115
|
+
_handleSkillSelect(skill) {
|
|
6116
|
+
this._inputValue = `/${skill.name} `;
|
|
6117
|
+
this._skillMenuOpened = false;
|
|
6118
|
+
this._skillBrowseOpened = false;
|
|
6119
|
+
this._inputEl?.focus();
|
|
6120
|
+
}
|
|
6121
|
+
/** Copy a message's text to the clipboard and briefly flash "Copied". */
|
|
6122
|
+
_handleCopyMessage(content, index) {
|
|
6123
|
+
navigator.clipboard.writeText(content).then(() => {
|
|
6124
|
+
this._copiedIndex = index;
|
|
6125
|
+
setTimeout(() => {
|
|
6126
|
+
if (this._copiedIndex === index) {
|
|
6127
|
+
this._copiedIndex = -1;
|
|
6128
|
+
}
|
|
6129
|
+
}, 2000);
|
|
6130
|
+
}).catch(() => { });
|
|
6131
|
+
}
|
|
6132
|
+
_handleSkillBrowseOpen() {
|
|
6133
|
+
this._skillMenuOpened = false;
|
|
6134
|
+
this._skillBrowseQuery = '';
|
|
6135
|
+
this._skillBrowseOpened = true;
|
|
6136
|
+
}
|
|
6137
|
+
_handleSkillBrowseClose() {
|
|
6138
|
+
this._skillBrowseOpened = false;
|
|
6139
|
+
}
|
|
6140
|
+
_handleSkillBrowseSearch(e) {
|
|
6141
|
+
this._skillBrowseQuery = e.target.value;
|
|
6142
|
+
}
|
|
6143
|
+
_handleSkillBrowseTabChange(e) {
|
|
6144
|
+
this._skillBrowseSource = e.detail.activeTabId;
|
|
6145
|
+
}
|
|
6146
|
+
/** Skills for the browse dialog's active tab, filtered by its search box. */
|
|
6147
|
+
_browseSkills() {
|
|
6148
|
+
const query = this._skillBrowseQuery.toLowerCase();
|
|
6149
|
+
return this.skills.filter((skill) => {
|
|
6150
|
+
const source = skill.source || 'org';
|
|
6151
|
+
if (source !== this._skillBrowseSource) {
|
|
6152
|
+
return false;
|
|
6153
|
+
}
|
|
6154
|
+
return skill.name.toLowerCase().includes(query) ||
|
|
6155
|
+
skill.label.toLowerCase().includes(query) ||
|
|
6156
|
+
(skill.description || '').toLowerCase().includes(query);
|
|
6157
|
+
});
|
|
6158
|
+
}
|
|
5951
6159
|
// --- Attachments ---
|
|
5952
6160
|
_openFilePicker() {
|
|
5953
6161
|
this._fileInputEl?.click();
|
|
@@ -6031,54 +6239,49 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6031
6239
|
name: file.name,
|
|
6032
6240
|
previewUrl: URL.createObjectURL(file),
|
|
6033
6241
|
};
|
|
6034
|
-
this.
|
|
6242
|
+
this._pendingInternalFiles = [...this._pendingInternalFiles, pending];
|
|
6035
6243
|
});
|
|
6036
6244
|
}
|
|
6037
6245
|
_removePending(localId) {
|
|
6038
|
-
const target = this.
|
|
6246
|
+
const target = this._pendingInternalFiles.find((p) => p.localId === localId);
|
|
6039
6247
|
if (target) {
|
|
6040
6248
|
URL.revokeObjectURL(target.previewUrl);
|
|
6041
6249
|
}
|
|
6042
|
-
this.
|
|
6250
|
+
this._pendingInternalFiles = this._pendingInternalFiles.filter((p) => p.localId !== localId);
|
|
6043
6251
|
}
|
|
6044
6252
|
_clearPending() {
|
|
6045
|
-
this.
|
|
6046
|
-
this.
|
|
6253
|
+
this._pendingInternalFiles.forEach((p) => URL.revokeObjectURL(p.previewUrl));
|
|
6254
|
+
this._pendingInternalFiles = [];
|
|
6047
6255
|
}
|
|
6048
|
-
/** Open the shared full-screen previewer for
|
|
6049
|
-
|
|
6256
|
+
/** Open the shared full-screen previewer for a message image. */
|
|
6257
|
+
_openImage(img) {
|
|
6050
6258
|
KRFilePreview.open({
|
|
6051
|
-
src:
|
|
6052
|
-
name:
|
|
6259
|
+
src: `/api/system/integration/aws/bedrock/conversationImage/${img.internalFileID}/view`,
|
|
6260
|
+
name: img.niceName || 'image',
|
|
6053
6261
|
});
|
|
6054
6262
|
}
|
|
6055
6263
|
/** Whether the send button is active: needs text or at least one image. */
|
|
6056
6264
|
_canSend() {
|
|
6057
|
-
return Boolean(this._inputValue.trim()) || this.
|
|
6265
|
+
return Boolean(this._inputValue.trim()) || this._pendingInternalFiles.length > 0;
|
|
6058
6266
|
}
|
|
6059
6267
|
_handleSubmit() {
|
|
6060
|
-
if (
|
|
6268
|
+
if (this._isStreaming) {
|
|
6061
6269
|
return;
|
|
6062
6270
|
}
|
|
6063
6271
|
const messageText = this._inputValue.trim();
|
|
6064
|
-
const pending = this.
|
|
6272
|
+
const pending = this._pendingInternalFiles;
|
|
6065
6273
|
// Allow sending an image with no text, but require at least one of them.
|
|
6066
6274
|
if (!messageText && !pending.length) {
|
|
6067
6275
|
return;
|
|
6068
6276
|
}
|
|
6069
|
-
// The raw files sent to the backend
|
|
6070
|
-
//
|
|
6071
|
-
//
|
|
6072
|
-
const
|
|
6073
|
-
const attachments = pending.map((p) => ({
|
|
6074
|
-
url: p.previewUrl,
|
|
6075
|
-
name: p.name,
|
|
6076
|
-
mimeType: p.file.type,
|
|
6077
|
-
}));
|
|
6277
|
+
// The raw files sent to the backend. Sent images are shown once the
|
|
6278
|
+
// conversation reloads and they come back as stored internal files; the
|
|
6279
|
+
// just-sent message itself carries text only.
|
|
6280
|
+
const internalFiles = pending.map((p) => p.file);
|
|
6078
6281
|
const submitEvent = new CustomEvent('message-submit', {
|
|
6079
6282
|
detail: {
|
|
6080
6283
|
message: messageText,
|
|
6081
|
-
|
|
6284
|
+
internalFiles,
|
|
6082
6285
|
},
|
|
6083
6286
|
bubbles: true,
|
|
6084
6287
|
composed: true,
|
|
@@ -6089,30 +6292,26 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6089
6292
|
return;
|
|
6090
6293
|
}
|
|
6091
6294
|
const userMessage = {
|
|
6092
|
-
|
|
6295
|
+
type: 'user',
|
|
6093
6296
|
content: messageText,
|
|
6094
6297
|
};
|
|
6095
|
-
if (attachments.length) {
|
|
6096
|
-
userMessage.attachments = attachments;
|
|
6097
|
-
}
|
|
6098
6298
|
this.messages = [...this.messages, userMessage];
|
|
6099
6299
|
this._inputValue = '';
|
|
6100
6300
|
this._error = '';
|
|
6101
6301
|
this._userHasScrolledUp = false;
|
|
6102
|
-
// Clear the composer
|
|
6103
|
-
|
|
6104
|
-
this.
|
|
6302
|
+
// Clear the composer and release its preview object URLs.
|
|
6303
|
+
this._pendingInternalFiles.forEach((p) => URL.revokeObjectURL(p.previewUrl));
|
|
6304
|
+
this._pendingInternalFiles = [];
|
|
6105
6305
|
// Reset textarea height
|
|
6106
6306
|
if (this._inputEl) {
|
|
6107
6307
|
this._inputEl.style.height = 'auto';
|
|
6108
6308
|
}
|
|
6109
6309
|
// Add empty assistant message to stream into
|
|
6110
6310
|
this.messages = [...this.messages, {
|
|
6111
|
-
|
|
6311
|
+
type: 'assistant',
|
|
6112
6312
|
content: '',
|
|
6113
6313
|
}];
|
|
6114
6314
|
this._isStreaming = true;
|
|
6115
|
-
this._statusText = '';
|
|
6116
6315
|
// Scroll user's message to the top (Gemini-style).
|
|
6117
6316
|
// Set min-height on the assistant message = container height so there's enough
|
|
6118
6317
|
// scroll room below the user message to push it to the top.
|
|
@@ -6134,10 +6333,34 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6134
6333
|
this._messagesEl.scrollTop = userMsgEl.offsetTop - this._messagesEl.offsetTop - 24;
|
|
6135
6334
|
}
|
|
6136
6335
|
});
|
|
6336
|
+
// Default to streaming from the Kodaris Bedrock conversation endpoints when
|
|
6337
|
+
// the consumer hasn't provided their own `send`.
|
|
6338
|
+
if (!this.send) {
|
|
6339
|
+
this.send = (params) => {
|
|
6340
|
+
// With images, post text + files as multipart; without, post plain JSON.
|
|
6341
|
+
if (params.internalFiles.length) {
|
|
6342
|
+
const form = new FormData();
|
|
6343
|
+
form.append('userText', params.message);
|
|
6344
|
+
params.internalFiles.forEach((file) => form.append('images', file));
|
|
6345
|
+
return KRHttp.fetch({
|
|
6346
|
+
url: '/api/system/integration/aws/bedrock/stream/invokeModelForConversationWithImages',
|
|
6347
|
+
method: 'POST',
|
|
6348
|
+
headers: { Accept: 'text/event-stream' },
|
|
6349
|
+
body: form,
|
|
6350
|
+
});
|
|
6351
|
+
}
|
|
6352
|
+
return KRHttp.fetch({
|
|
6353
|
+
url: '/api/system/integration/aws/bedrock/stream/invokeModelForConversationWithState',
|
|
6354
|
+
method: 'POST',
|
|
6355
|
+
headers: { Accept: 'text/event-stream' },
|
|
6356
|
+
body: { userText: params.message },
|
|
6357
|
+
});
|
|
6358
|
+
};
|
|
6359
|
+
}
|
|
6137
6360
|
this.send({
|
|
6138
6361
|
message: messageText,
|
|
6139
6362
|
messages: this.messages.slice(0, -1),
|
|
6140
|
-
|
|
6363
|
+
internalFiles,
|
|
6141
6364
|
}).then((response) => {
|
|
6142
6365
|
if (!response.ok) {
|
|
6143
6366
|
this._handleStreamError('Request failed: ' + response.status);
|
|
@@ -6163,11 +6386,15 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6163
6386
|
this._reader = null;
|
|
6164
6387
|
}
|
|
6165
6388
|
this._isStreaming = false;
|
|
6166
|
-
this._statusText = '';
|
|
6167
6389
|
}
|
|
6168
6390
|
_handleClear() {
|
|
6391
|
+
// Default to clearing the Kodaris Bedrock conversation state when the consumer
|
|
6392
|
+
// hasn't provided their own `clear`.
|
|
6169
6393
|
if (!this.clear) {
|
|
6170
|
-
|
|
6394
|
+
this.clear = () => KRHttp.fetch({
|
|
6395
|
+
url: '/api/system/integration/aws/bedrock/clearConversationWithState',
|
|
6396
|
+
method: 'POST',
|
|
6397
|
+
});
|
|
6171
6398
|
}
|
|
6172
6399
|
this.clear().then(() => {
|
|
6173
6400
|
if (this._reader) {
|
|
@@ -6176,7 +6403,6 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6176
6403
|
}
|
|
6177
6404
|
this.messages = [];
|
|
6178
6405
|
this._isStreaming = false;
|
|
6179
|
-
this._statusText = '';
|
|
6180
6406
|
this._error = '';
|
|
6181
6407
|
this._inputValue = '';
|
|
6182
6408
|
this._userHasScrolledUp = false;
|
|
@@ -6202,7 +6428,6 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6202
6428
|
this._reader.read().then((result) => {
|
|
6203
6429
|
if (result.done) {
|
|
6204
6430
|
this._isStreaming = false;
|
|
6205
|
-
this._statusText = '';
|
|
6206
6431
|
this._reader = null;
|
|
6207
6432
|
return;
|
|
6208
6433
|
}
|
|
@@ -6235,15 +6460,10 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6235
6460
|
bubbles: true,
|
|
6236
6461
|
composed: true,
|
|
6237
6462
|
}));
|
|
6238
|
-
if (data.type === '
|
|
6239
|
-
if (data.message) {
|
|
6240
|
-
this._statusText = String(data.message);
|
|
6241
|
-
}
|
|
6242
|
-
}
|
|
6243
|
-
else if (data.type === 'REASONING_PART') {
|
|
6463
|
+
if (data.type === 'REASONING_PART') {
|
|
6244
6464
|
if (data.message) {
|
|
6245
6465
|
const lastIndex = this.messages.length - 1;
|
|
6246
|
-
if (lastIndex >= 0 && this.messages[lastIndex].
|
|
6466
|
+
if (lastIndex >= 0 && this.messages[lastIndex].type === 'assistant') {
|
|
6247
6467
|
if (!this.messages[lastIndex].reasoning) {
|
|
6248
6468
|
this.messages[lastIndex].reasoning = '';
|
|
6249
6469
|
}
|
|
@@ -6254,9 +6474,8 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6254
6474
|
}
|
|
6255
6475
|
else if (data.type === 'RESPONSE_PART') {
|
|
6256
6476
|
if (data.message) {
|
|
6257
|
-
this._statusText = '';
|
|
6258
6477
|
const lastIndex = this.messages.length - 1;
|
|
6259
|
-
if (lastIndex >= 0 && this.messages[lastIndex].
|
|
6478
|
+
if (lastIndex >= 0 && this.messages[lastIndex].type === 'assistant') {
|
|
6260
6479
|
this.messages[lastIndex].content += String(data.message);
|
|
6261
6480
|
this.requestUpdate();
|
|
6262
6481
|
}
|
|
@@ -6267,7 +6486,6 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6267
6486
|
}
|
|
6268
6487
|
if (data.finished) {
|
|
6269
6488
|
this._isStreaming = false;
|
|
6270
|
-
this._statusText = '';
|
|
6271
6489
|
this._reader = null;
|
|
6272
6490
|
}
|
|
6273
6491
|
}
|
|
@@ -6281,7 +6499,6 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6281
6499
|
}
|
|
6282
6500
|
_handleStreamError(message) {
|
|
6283
6501
|
this._isStreaming = false;
|
|
6284
|
-
this._statusText = '';
|
|
6285
6502
|
this._error = message;
|
|
6286
6503
|
if (this._reader) {
|
|
6287
6504
|
this._reader.cancel();
|
|
@@ -6290,15 +6507,128 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6290
6507
|
// Remove the empty assistant message if it has no content
|
|
6291
6508
|
if (this.messages.length > 0) {
|
|
6292
6509
|
const lastMessage = this.messages[this.messages.length - 1];
|
|
6293
|
-
if (lastMessage.
|
|
6510
|
+
if (lastMessage.type === 'assistant' && !lastMessage.content) {
|
|
6294
6511
|
this.messages = this.messages.slice(0, -1);
|
|
6295
6512
|
}
|
|
6296
6513
|
}
|
|
6297
6514
|
}
|
|
6298
6515
|
// --- Render ---
|
|
6516
|
+
/** The `/` skill menu shown above the composer while typing a slash command. */
|
|
6517
|
+
_renderSkillMenu() {
|
|
6518
|
+
const skills = this._filteredSkills();
|
|
6519
|
+
return b `
|
|
6520
|
+
<div class="skill-menu">
|
|
6521
|
+
<div class="skill-menu__actions">
|
|
6522
|
+
<button
|
|
6523
|
+
class=${e({
|
|
6524
|
+
'skill-menu__action': true,
|
|
6525
|
+
'skill-menu__item--highlighted': this._skillHighlighted === 0,
|
|
6526
|
+
})}
|
|
6527
|
+
@click=${this._openFilePicker}
|
|
6528
|
+
>
|
|
6529
|
+
Attach Files
|
|
6530
|
+
</button>
|
|
6531
|
+
<button
|
|
6532
|
+
class=${e({
|
|
6533
|
+
'skill-menu__action': true,
|
|
6534
|
+
'skill-menu__item--highlighted': this._skillHighlighted === 1,
|
|
6535
|
+
})}
|
|
6536
|
+
@click=${this._handleSkillBrowseOpen}
|
|
6537
|
+
>
|
|
6538
|
+
Browse All Skills
|
|
6539
|
+
</button>
|
|
6540
|
+
</div>
|
|
6541
|
+
${skills.length ? b `
|
|
6542
|
+
<ul class="skill-menu__list">
|
|
6543
|
+
${skills.map((skill, index) => b `
|
|
6544
|
+
<li>
|
|
6545
|
+
<button
|
|
6546
|
+
class=${e({
|
|
6547
|
+
'skill-menu__item': true,
|
|
6548
|
+
'skill-menu__item--highlighted': index + 2 === this._skillHighlighted,
|
|
6549
|
+
})}
|
|
6550
|
+
@click=${() => this._handleSkillSelect(skill)}
|
|
6551
|
+
>
|
|
6552
|
+
<span class="skill-menu__name">${skill.label}</span>
|
|
6553
|
+
${skill.description ? b `
|
|
6554
|
+
<span class="skill-menu__desc">${skill.description}</span>
|
|
6555
|
+
` : A}
|
|
6556
|
+
</button>
|
|
6557
|
+
</li>
|
|
6558
|
+
`)}
|
|
6559
|
+
</ul>
|
|
6560
|
+
` : b `
|
|
6561
|
+
<div class="skill-menu__empty">No matching skills</div>
|
|
6562
|
+
`}
|
|
6563
|
+
</div>
|
|
6564
|
+
`;
|
|
6565
|
+
}
|
|
6566
|
+
/** The "Browse all skills" dialog — a searchable grid of Org / Kodaris cards. */
|
|
6567
|
+
_renderSkillBrowse() {
|
|
6568
|
+
return b `
|
|
6569
|
+
<kr-dialog
|
|
6570
|
+
opened
|
|
6571
|
+
label="Browse Skills"
|
|
6572
|
+
width="720px"
|
|
6573
|
+
@close=${this._handleSkillBrowseClose}
|
|
6574
|
+
>
|
|
6575
|
+
<div class="skill-browse">
|
|
6576
|
+
<kr-text-field
|
|
6577
|
+
placeholder="Search skills..."
|
|
6578
|
+
.value=${this._skillBrowseQuery}
|
|
6579
|
+
@input=${this._handleSkillBrowseSearch}
|
|
6580
|
+
></kr-text-field>
|
|
6581
|
+
<kr-tab-group
|
|
6582
|
+
active-tab-id=${this._skillBrowseSource}
|
|
6583
|
+
@tab-change=${this._handleSkillBrowseTabChange}
|
|
6584
|
+
>
|
|
6585
|
+
<kr-tab id="org" label="Your Org">
|
|
6586
|
+
${this._renderSkillGrid()}
|
|
6587
|
+
</kr-tab>
|
|
6588
|
+
<kr-tab id="kodaris" label="Kodaris">
|
|
6589
|
+
${this._renderSkillGrid()}
|
|
6590
|
+
</kr-tab>
|
|
6591
|
+
</kr-tab-group>
|
|
6592
|
+
</div>
|
|
6593
|
+
</kr-dialog>
|
|
6594
|
+
`;
|
|
6595
|
+
}
|
|
6596
|
+
/** The card grid for the browse dialog's active tab. */
|
|
6597
|
+
_renderSkillGrid() {
|
|
6598
|
+
const skills = this._browseSkills();
|
|
6599
|
+
if (!skills.length) {
|
|
6600
|
+
return b `<div class="skill-browse__empty">No matching skills</div>`;
|
|
6601
|
+
}
|
|
6602
|
+
return b `
|
|
6603
|
+
<div class="skill-browse__grid">
|
|
6604
|
+
${skills.map((skill) => b `
|
|
6605
|
+
<button
|
|
6606
|
+
class="skill-card"
|
|
6607
|
+
@click=${() => this._handleSkillSelect(skill)}
|
|
6608
|
+
>
|
|
6609
|
+
<span class="skill-card__name">${skill.label}</span>
|
|
6610
|
+
${skill.description ? b `
|
|
6611
|
+
<span class="skill-card__desc">${skill.description}</span>
|
|
6612
|
+
` : A}
|
|
6613
|
+
</button>
|
|
6614
|
+
`)}
|
|
6615
|
+
</div>
|
|
6616
|
+
`;
|
|
6617
|
+
}
|
|
6618
|
+
/**
|
|
6619
|
+
* Render a user message, highlighting a leading `/skill-name` token when it
|
|
6620
|
+
* matches a known skill (like the way Claude highlights slash commands).
|
|
6621
|
+
*/
|
|
6622
|
+
_renderUserContent(content) {
|
|
6623
|
+
const match = content.match(/^\/(\S+)(\s[\s\S]*)?$/);
|
|
6624
|
+
if (match && this.skills.some((skill) => skill.name === match[1])) {
|
|
6625
|
+
return b `<span class="message-skill">/${match[1]}</span>${match[2] || ''}`;
|
|
6626
|
+
}
|
|
6627
|
+
return content;
|
|
6628
|
+
}
|
|
6299
6629
|
render() {
|
|
6300
6630
|
return b `
|
|
6301
|
-
${this.hideToggle ? A : b `
|
|
6631
|
+
${(this.hideToggle || this.variant === 'inline') ? A : b `
|
|
6302
6632
|
<button
|
|
6303
6633
|
class=${e({
|
|
6304
6634
|
'toggle': true,
|
|
@@ -6349,53 +6679,52 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6349
6679
|
<span>Drop images to attach</span>
|
|
6350
6680
|
</div>
|
|
6351
6681
|
` : A}
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6682
|
+
${this.variant === 'inline' ? A : b `
|
|
6683
|
+
<div
|
|
6684
|
+
class="resize resize--n"
|
|
6685
|
+
data-dir="n"
|
|
6686
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6687
|
+
></div>
|
|
6688
|
+
<div
|
|
6689
|
+
class="resize resize--s"
|
|
6690
|
+
data-dir="s"
|
|
6691
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6692
|
+
></div>
|
|
6693
|
+
<div
|
|
6694
|
+
class="resize resize--w"
|
|
6695
|
+
data-dir="w"
|
|
6696
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6697
|
+
></div>
|
|
6698
|
+
<div
|
|
6699
|
+
class="resize resize--e"
|
|
6700
|
+
data-dir="e"
|
|
6701
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6702
|
+
></div>
|
|
6703
|
+
<div
|
|
6704
|
+
class="resize resize--nw"
|
|
6705
|
+
data-dir="nw"
|
|
6706
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6707
|
+
></div>
|
|
6708
|
+
<div
|
|
6709
|
+
class="resize resize--ne"
|
|
6710
|
+
data-dir="ne"
|
|
6711
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6712
|
+
></div>
|
|
6713
|
+
<div
|
|
6714
|
+
class="resize resize--sw"
|
|
6715
|
+
data-dir="sw"
|
|
6716
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6717
|
+
></div>
|
|
6718
|
+
<div
|
|
6719
|
+
class="resize resize--se"
|
|
6720
|
+
data-dir="se"
|
|
6721
|
+
@mousedown=${this._handleResizeMouseDown}
|
|
6722
|
+
></div>
|
|
6723
|
+
`}
|
|
6392
6724
|
<div class="header" @mousedown=${this._handleHeaderMouseDown}>
|
|
6393
6725
|
<div class="header-left">
|
|
6394
6726
|
<div class="header-info">
|
|
6395
|
-
<span class="header-title">${this.
|
|
6396
|
-
${this.subtitle ? b `
|
|
6397
|
-
<span class="header-subtitle">${this.subtitle}</span>
|
|
6398
|
-
` : A}
|
|
6727
|
+
<span class="header-title">${this.label}</span>
|
|
6399
6728
|
</div>
|
|
6400
6729
|
</div>
|
|
6401
6730
|
<div class="header-actions">
|
|
@@ -6421,77 +6750,124 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6421
6750
|
</svg>
|
|
6422
6751
|
</button>
|
|
6423
6752
|
` : A}
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
<svg
|
|
6430
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
6431
|
-
fill="none"
|
|
6432
|
-
viewBox="0 0 24 24"
|
|
6433
|
-
stroke-width="2"
|
|
6434
|
-
stroke="currentColor"
|
|
6435
|
-
class="header-action-icon"
|
|
6753
|
+
${this.variant === 'inline' ? A : b `
|
|
6754
|
+
<button
|
|
6755
|
+
class="header-action"
|
|
6756
|
+
@click=${this._handleToggle}
|
|
6757
|
+
title="Close"
|
|
6436
6758
|
>
|
|
6437
|
-
<
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6759
|
+
<svg
|
|
6760
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6761
|
+
fill="none"
|
|
6762
|
+
viewBox="0 0 24 24"
|
|
6763
|
+
stroke-width="2"
|
|
6764
|
+
stroke="currentColor"
|
|
6765
|
+
class="header-action-icon"
|
|
6766
|
+
>
|
|
6767
|
+
<path
|
|
6768
|
+
stroke-linecap="round"
|
|
6769
|
+
stroke-linejoin="round"
|
|
6770
|
+
d="M6 18 18 6M6 6l12 12"
|
|
6771
|
+
/>
|
|
6772
|
+
</svg>
|
|
6773
|
+
</button>
|
|
6774
|
+
`}
|
|
6444
6775
|
</div>
|
|
6445
6776
|
</div>
|
|
6446
6777
|
|
|
6447
6778
|
<div class="messages" @scroll=${this._handleMessagesScroll}>
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
<
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6779
|
+
<div class="messages-inner">
|
|
6780
|
+
${this.messages.length === 0 ? b `
|
|
6781
|
+
<div class="empty">
|
|
6782
|
+
<span class="empty-text">What can I help you with?</span>
|
|
6783
|
+
</div>
|
|
6784
|
+
` : A}
|
|
6785
|
+
${this.messages.map((msg, index) => b `
|
|
6786
|
+
<div class=${e({
|
|
6455
6787
|
'message': true,
|
|
6456
|
-
'message--user': msg.
|
|
6457
|
-
'message--assistant': msg.
|
|
6788
|
+
'message--user': msg.type === 'user',
|
|
6789
|
+
'message--assistant': msg.type === 'assistant',
|
|
6458
6790
|
})}>
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6791
|
+
${msg.reasoning ? b `
|
|
6792
|
+
<details class="reasoning">
|
|
6793
|
+
<summary>Thinking</summary>
|
|
6794
|
+
<div class="reasoning-content">${msg.reasoning}</div>
|
|
6795
|
+
</details>
|
|
6796
|
+
` : A}
|
|
6797
|
+
${msg.internalFiles && msg.internalFiles.length ? b `
|
|
6798
|
+
<div class="attachments">
|
|
6799
|
+
${msg.internalFiles.map((img) => b `
|
|
6800
|
+
<button
|
|
6801
|
+
class="attachment"
|
|
6802
|
+
type="button"
|
|
6803
|
+
title=${img.niceName || 'View image'}
|
|
6804
|
+
@click=${() => this._openImage(img)}
|
|
6805
|
+
>
|
|
6806
|
+
<img
|
|
6807
|
+
src="/api/system/integration/aws/bedrock/conversationImage/${img.internalFileID}/view"
|
|
6808
|
+
alt=${img.niceName || ''}
|
|
6809
|
+
/>
|
|
6810
|
+
</button>
|
|
6811
|
+
`)}
|
|
6812
|
+
</div>
|
|
6813
|
+
` : A}
|
|
6814
|
+
${msg.content ? b `
|
|
6815
|
+
<div class="message-content">
|
|
6816
|
+
${msg.type === 'user'
|
|
6817
|
+
? this._renderUserContent(msg.content)
|
|
6483
6818
|
: o(marked.parse(msg.content, { breaks: true }))}
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6819
|
+
</div>
|
|
6820
|
+
` : A}
|
|
6821
|
+
${msg.type === 'assistant' && this._isStreaming && msg === this.messages[this.messages.length - 1] ? b `
|
|
6822
|
+
<div class="typing">
|
|
6823
|
+
<span></span>
|
|
6824
|
+
<span></span>
|
|
6825
|
+
<span></span>
|
|
6826
|
+
</div>
|
|
6827
|
+
` : A}
|
|
6828
|
+
${msg.content ? b `
|
|
6829
|
+
<button
|
|
6830
|
+
class="message-copy"
|
|
6831
|
+
title="Copy"
|
|
6832
|
+
@click=${() => this._handleCopyMessage(msg.content, index)}
|
|
6833
|
+
>
|
|
6834
|
+
${this._copiedIndex === index ? b `
|
|
6835
|
+
<svg
|
|
6836
|
+
viewBox="0 0 24 24"
|
|
6837
|
+
fill="none"
|
|
6838
|
+
stroke="currentColor"
|
|
6839
|
+
stroke-width="1.5"
|
|
6840
|
+
stroke-linecap="round"
|
|
6841
|
+
stroke-linejoin="round"
|
|
6842
|
+
>
|
|
6843
|
+
<path d="M20 6 9 17l-5-5" />
|
|
6844
|
+
</svg>
|
|
6845
|
+
Copied
|
|
6846
|
+
` : b `
|
|
6847
|
+
<svg
|
|
6848
|
+
viewBox="0 0 24 24"
|
|
6849
|
+
fill="none"
|
|
6850
|
+
stroke="currentColor"
|
|
6851
|
+
stroke-width="1.5"
|
|
6852
|
+
stroke-linecap="round"
|
|
6853
|
+
stroke-linejoin="round"
|
|
6854
|
+
>
|
|
6855
|
+
<rect
|
|
6856
|
+
x="9"
|
|
6857
|
+
y="9"
|
|
6858
|
+
width="13"
|
|
6859
|
+
height="13"
|
|
6860
|
+
rx="2"
|
|
6861
|
+
/>
|
|
6862
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
|
|
6863
|
+
</svg>
|
|
6864
|
+
Copy
|
|
6865
|
+
`}
|
|
6866
|
+
</button>
|
|
6867
|
+
` : A}
|
|
6868
|
+
</div>
|
|
6869
|
+
`)}
|
|
6870
|
+
</div>
|
|
6495
6871
|
</div>
|
|
6496
6872
|
|
|
6497
6873
|
${this._error ? b `
|
|
@@ -6517,9 +6893,9 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6517
6893
|
` : A}
|
|
6518
6894
|
|
|
6519
6895
|
<div class="footer">
|
|
6520
|
-
${this.
|
|
6896
|
+
${this._pendingInternalFiles.length ? b `
|
|
6521
6897
|
<div class="composer-attachments">
|
|
6522
|
-
${c(this.
|
|
6898
|
+
${c(this._pendingInternalFiles, (p) => p.localId, (p) => b `
|
|
6523
6899
|
<div class="chip">
|
|
6524
6900
|
<img src=${p.previewUrl} alt=${p.name} />
|
|
6525
6901
|
<button
|
|
@@ -6553,11 +6929,11 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6553
6929
|
hidden
|
|
6554
6930
|
@change=${this._handleFileInputChange}
|
|
6555
6931
|
/>
|
|
6932
|
+
${this._skillMenuOpened ? this._renderSkillMenu() : A}
|
|
6556
6933
|
<div class="input-wrapper">
|
|
6557
6934
|
<button
|
|
6558
6935
|
class="input-plus"
|
|
6559
|
-
|
|
6560
|
-
@click=${this._openFilePicker}
|
|
6936
|
+
@click=${this._handlePlusClick}
|
|
6561
6937
|
>+</button>
|
|
6562
6938
|
<textarea
|
|
6563
6939
|
class="input"
|
|
@@ -6614,6 +6990,7 @@ let KRChatbot = class KRChatbot extends i$2 {
|
|
|
6614
6990
|
`}
|
|
6615
6991
|
</div>
|
|
6616
6992
|
</div>
|
|
6993
|
+
${this._skillBrowseOpened ? this._renderSkillBrowse() : A}
|
|
6617
6994
|
</div>
|
|
6618
6995
|
`;
|
|
6619
6996
|
}
|
|
@@ -6708,6 +7085,28 @@ KRChatbot.styles = i$5 `
|
|
|
6708
7085
|
display: flex;
|
|
6709
7086
|
}
|
|
6710
7087
|
|
|
7088
|
+
/* Inline mode: fill the parent container instead of floating bottom-right. */
|
|
7089
|
+
:host([variant='inline']) {
|
|
7090
|
+
position: static;
|
|
7091
|
+
bottom: auto;
|
|
7092
|
+
right: auto;
|
|
7093
|
+
z-index: auto;
|
|
7094
|
+
height: 100%;
|
|
7095
|
+
}
|
|
7096
|
+
|
|
7097
|
+
:host([variant='inline']) .panel {
|
|
7098
|
+
position: relative;
|
|
7099
|
+
bottom: auto;
|
|
7100
|
+
right: auto;
|
|
7101
|
+
width: 100%;
|
|
7102
|
+
height: 100%;
|
|
7103
|
+
max-height: none;
|
|
7104
|
+
border-radius: 0;
|
|
7105
|
+
box-shadow: none;
|
|
7106
|
+
border: none;
|
|
7107
|
+
animation: none;
|
|
7108
|
+
}
|
|
7109
|
+
|
|
6711
7110
|
@keyframes chatbot-panel-in {
|
|
6712
7111
|
from {
|
|
6713
7112
|
opacity: 0;
|
|
@@ -6738,7 +7137,7 @@ KRChatbot.styles = i$5 `
|
|
|
6738
7137
|
gap: 10px;
|
|
6739
7138
|
}
|
|
6740
7139
|
|
|
6741
|
-
.header-info {
|
|
7140
|
+
.header-info {
|
|
6742
7141
|
display: flex;
|
|
6743
7142
|
flex-direction: column;
|
|
6744
7143
|
}
|
|
@@ -6748,22 +7147,6 @@ KRChatbot.styles = i$5 `
|
|
|
6748
7147
|
font-weight: 600;
|
|
6749
7148
|
}
|
|
6750
7149
|
|
|
6751
|
-
.header-subtitle {
|
|
6752
|
-
color: rgba(255, 255, 255, 0.5);
|
|
6753
|
-
font-size: 11px;
|
|
6754
|
-
display: flex;
|
|
6755
|
-
align-items: center;
|
|
6756
|
-
gap: 4px;
|
|
6757
|
-
}
|
|
6758
|
-
|
|
6759
|
-
.header-subtitle::before {
|
|
6760
|
-
content: '';
|
|
6761
|
-
width: 5px;
|
|
6762
|
-
height: 5px;
|
|
6763
|
-
background: var(--kr-chatbot-success);
|
|
6764
|
-
border-radius: 50%;
|
|
6765
|
-
}
|
|
6766
|
-
|
|
6767
7150
|
.header-actions {
|
|
6768
7151
|
display: flex;
|
|
6769
7152
|
align-items: center;
|
|
@@ -6795,17 +7178,29 @@ KRChatbot.styles = i$5 `
|
|
|
6795
7178
|
}
|
|
6796
7179
|
|
|
6797
7180
|
/* Messages */
|
|
7181
|
+
/* Full-width scroll container — keeps the scrollbar at the panel edge. */
|
|
6798
7182
|
.messages {
|
|
6799
7183
|
flex: 1;
|
|
6800
7184
|
overflow-y: auto;
|
|
6801
|
-
padding: 32px;
|
|
6802
7185
|
display: flex;
|
|
6803
7186
|
flex-direction: column;
|
|
6804
|
-
gap: 24px;
|
|
6805
7187
|
scroll-behavior: smooth;
|
|
6806
7188
|
background: white;
|
|
6807
7189
|
}
|
|
6808
7190
|
|
|
7191
|
+
/* Centered, width-capped column that actually holds the messages. */
|
|
7192
|
+
.messages-inner {
|
|
7193
|
+
flex: 1;
|
|
7194
|
+
display: flex;
|
|
7195
|
+
flex-direction: column;
|
|
7196
|
+
gap: 24px;
|
|
7197
|
+
padding: 32px;
|
|
7198
|
+
width: 100%;
|
|
7199
|
+
max-width: 768px;
|
|
7200
|
+
margin-left: auto;
|
|
7201
|
+
margin-right: auto;
|
|
7202
|
+
}
|
|
7203
|
+
|
|
6809
7204
|
.messages::-webkit-scrollbar {
|
|
6810
7205
|
width: 4px;
|
|
6811
7206
|
}
|
|
@@ -6829,12 +7224,13 @@ KRChatbot.styles = i$5 `
|
|
|
6829
7224
|
gap: 8px;
|
|
6830
7225
|
}
|
|
6831
7226
|
|
|
6832
|
-
.empty-text {
|
|
7227
|
+
.empty-text {
|
|
6833
7228
|
font-size: 14px;
|
|
6834
7229
|
color: rgb(0 0 0 / 80%);
|
|
6835
7230
|
}
|
|
6836
7231
|
|
|
6837
7232
|
.message {
|
|
7233
|
+
position: relative;
|
|
6838
7234
|
display: flex;
|
|
6839
7235
|
flex-direction: column;
|
|
6840
7236
|
max-width: 100%;
|
|
@@ -6879,6 +7275,58 @@ KRChatbot.styles = i$5 `
|
|
|
6879
7275
|
font-size: 14px;
|
|
6880
7276
|
}
|
|
6881
7277
|
|
|
7278
|
+
/* Highlighted leading /skill token in a sent user message. Monospace + a
|
|
7279
|
+
stronger color makes it read as a distinct command without a pill. */
|
|
7280
|
+
.message-skill {
|
|
7281
|
+
font-family: 'SF Mono', SFMono-Regular, ui-monospace, Menlo, Consolas, monospace;
|
|
7282
|
+
font-weight: 600;
|
|
7283
|
+
color: #b45309;
|
|
7284
|
+
}
|
|
7285
|
+
|
|
7286
|
+
/* Per-message copy button. Kept in flow with a fixed height that is always
|
|
7287
|
+
reserved (via a negative bottom margin that cancels it) so message spacing
|
|
7288
|
+
is identical whether or not it's shown; only its opacity toggles on hover. */
|
|
7289
|
+
.message-copy {
|
|
7290
|
+
align-self: flex-start;
|
|
7291
|
+
margin-top: 4px;
|
|
7292
|
+
margin-bottom: -27px;
|
|
7293
|
+
display: inline-flex;
|
|
7294
|
+
align-items: center;
|
|
7295
|
+
gap: 4px;
|
|
7296
|
+
height: 23px;
|
|
7297
|
+
padding: 4px 8px;
|
|
7298
|
+
background: none;
|
|
7299
|
+
border: none;
|
|
7300
|
+
border-radius: 6px;
|
|
7301
|
+
font: inherit;
|
|
7302
|
+
font-size: 12px;
|
|
7303
|
+
color: #64668b;
|
|
7304
|
+
cursor: pointer;
|
|
7305
|
+
opacity: 0;
|
|
7306
|
+
pointer-events: none;
|
|
7307
|
+
transition: opacity 0.15s, background-color 0.15s, color 0.15s;
|
|
7308
|
+
}
|
|
7309
|
+
|
|
7310
|
+
.message--user .message-copy {
|
|
7311
|
+
align-self: flex-end;
|
|
7312
|
+
}
|
|
7313
|
+
|
|
7314
|
+
.message:hover .message-copy,
|
|
7315
|
+
.message-copy:focus-visible {
|
|
7316
|
+
opacity: 1;
|
|
7317
|
+
pointer-events: auto;
|
|
7318
|
+
}
|
|
7319
|
+
|
|
7320
|
+
.message-copy:hover {
|
|
7321
|
+
background: rgba(0, 0, 0, 0.06);
|
|
7322
|
+
color: #1a1a2e;
|
|
7323
|
+
}
|
|
7324
|
+
|
|
7325
|
+
.message-copy svg {
|
|
7326
|
+
width: 14px;
|
|
7327
|
+
height: 14px;
|
|
7328
|
+
}
|
|
7329
|
+
|
|
6882
7330
|
.message--assistant .message-content {
|
|
6883
7331
|
background: transparent;
|
|
6884
7332
|
color: #000000;
|
|
@@ -6941,7 +7389,7 @@ KRChatbot.styles = i$5 `
|
|
|
6941
7389
|
word-wrap: break-word;
|
|
6942
7390
|
}
|
|
6943
7391
|
|
|
6944
|
-
.typing {
|
|
7392
|
+
.typing {
|
|
6945
7393
|
display: flex;
|
|
6946
7394
|
gap: 4px;
|
|
6947
7395
|
padding: 4px 0;
|
|
@@ -7009,6 +7457,15 @@ KRChatbot.styles = i$5 `
|
|
|
7009
7457
|
padding: 16px 16px 16px;
|
|
7010
7458
|
flex-shrink: 0;
|
|
7011
7459
|
background: white;
|
|
7460
|
+
width: 100%;
|
|
7461
|
+
max-width: 768px;
|
|
7462
|
+
margin-left: auto;
|
|
7463
|
+
margin-right: auto;
|
|
7464
|
+
}
|
|
7465
|
+
|
|
7466
|
+
/* Inline mode: keep the composer clear of the bottom edge. */
|
|
7467
|
+
:host([variant='inline']) .footer {
|
|
7468
|
+
padding-bottom: 40px;
|
|
7012
7469
|
}
|
|
7013
7470
|
|
|
7014
7471
|
.input-wrapper {
|
|
@@ -7027,6 +7484,15 @@ KRChatbot.styles = i$5 `
|
|
|
7027
7484
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.04);
|
|
7028
7485
|
}
|
|
7029
7486
|
|
|
7487
|
+
/* Inline mode: keep the border and add a soft floating shadow (ChatGPT/Gemini style). */
|
|
7488
|
+
:host([variant='inline']) .input-wrapper {
|
|
7489
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06), 0 8px 24px rgba(0, 0, 0, 0.1);
|
|
7490
|
+
}
|
|
7491
|
+
|
|
7492
|
+
:host([variant='inline']) .input-wrapper:focus-within {
|
|
7493
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 12px 32px rgba(0, 0, 0, 0.14);
|
|
7494
|
+
}
|
|
7495
|
+
|
|
7030
7496
|
.input-plus {
|
|
7031
7497
|
width: 34px;
|
|
7032
7498
|
height: 34px;
|
|
@@ -7134,6 +7600,12 @@ KRChatbot.styles = i$5 `
|
|
|
7134
7600
|
cursor: grabbing;
|
|
7135
7601
|
}
|
|
7136
7602
|
|
|
7603
|
+
/* Inline mode isn't draggable — don't show the grab/hand cursor. */
|
|
7604
|
+
:host([variant='inline']) .header,
|
|
7605
|
+
:host([variant='inline']) .header:active {
|
|
7606
|
+
cursor: default;
|
|
7607
|
+
}
|
|
7608
|
+
|
|
7137
7609
|
/* Drag / Resize states */
|
|
7138
7610
|
.panel--dragging,
|
|
7139
7611
|
.panel--resizing {
|
|
@@ -7190,6 +7662,176 @@ KRChatbot.styles = i$5 `
|
|
|
7190
7662
|
display: block;
|
|
7191
7663
|
}
|
|
7192
7664
|
|
|
7665
|
+
/* Skill menu (opened by typing '/'). Fixed + JS-positioned above the
|
|
7666
|
+
composer, following the krubble select-field dropdown pattern. */
|
|
7667
|
+
.skill-menu {
|
|
7668
|
+
position: fixed;
|
|
7669
|
+
z-index: 10000;
|
|
7670
|
+
background: white;
|
|
7671
|
+
border: 1px solid #9ba7b6;
|
|
7672
|
+
border-radius: 8px;
|
|
7673
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
|
7674
|
+
overflow: hidden;
|
|
7675
|
+
display: flex;
|
|
7676
|
+
flex-direction: column;
|
|
7677
|
+
/* max-height is set dynamically to the space above the composer. */
|
|
7678
|
+
}
|
|
7679
|
+
|
|
7680
|
+
/* Floating mode is a compact card — use a lighter shadow and softer border. */
|
|
7681
|
+
:host(:not([variant='inline'])) .skill-menu {
|
|
7682
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
7683
|
+
border-color: #b0b0b0;
|
|
7684
|
+
}
|
|
7685
|
+
|
|
7686
|
+
.skill-menu__list {
|
|
7687
|
+
list-style: none;
|
|
7688
|
+
margin: 0;
|
|
7689
|
+
padding: 8px 0;
|
|
7690
|
+
overflow-y: auto;
|
|
7691
|
+
}
|
|
7692
|
+
|
|
7693
|
+
.skill-menu__item {
|
|
7694
|
+
display: flex;
|
|
7695
|
+
flex-direction: column;
|
|
7696
|
+
gap: 2px;
|
|
7697
|
+
width: 100%;
|
|
7698
|
+
padding: 8px 16px;
|
|
7699
|
+
background: none;
|
|
7700
|
+
border: none;
|
|
7701
|
+
text-align: left;
|
|
7702
|
+
cursor: pointer;
|
|
7703
|
+
font: inherit;
|
|
7704
|
+
color: #000000;
|
|
7705
|
+
}
|
|
7706
|
+
|
|
7707
|
+
|
|
7708
|
+
/* Floating mode is a compact card — tighten name/description spacing. */
|
|
7709
|
+
:host(:not([variant='inline'])) .skill-menu__item {
|
|
7710
|
+
gap: 1px;
|
|
7711
|
+
}
|
|
7712
|
+
|
|
7713
|
+
.skill-menu__name {
|
|
7714
|
+
font-weight: 500;
|
|
7715
|
+
}
|
|
7716
|
+
|
|
7717
|
+
/* Floating mode is a compact card — shrink the skill name a touch. */
|
|
7718
|
+
:host(:not([variant='inline'])) .skill-menu__name {
|
|
7719
|
+
font-size: 13px;
|
|
7720
|
+
}
|
|
7721
|
+
|
|
7722
|
+
.skill-menu__desc {
|
|
7723
|
+
font-size: 12px;
|
|
7724
|
+
color: #000000;
|
|
7725
|
+
overflow: hidden;
|
|
7726
|
+
text-overflow: ellipsis;
|
|
7727
|
+
white-space: nowrap;
|
|
7728
|
+
}
|
|
7729
|
+
|
|
7730
|
+
.skill-menu__empty {
|
|
7731
|
+
padding: 16px;
|
|
7732
|
+
text-align: center;
|
|
7733
|
+
color: #000000;
|
|
7734
|
+
}
|
|
7735
|
+
|
|
7736
|
+
.skill-menu__actions {
|
|
7737
|
+
display: flex;
|
|
7738
|
+
flex-direction: column;
|
|
7739
|
+
padding: 8px 0;
|
|
7740
|
+
border-bottom: 1px solid #eee;
|
|
7741
|
+
flex-shrink: 0;
|
|
7742
|
+
}
|
|
7743
|
+
|
|
7744
|
+
.skill-menu__action {
|
|
7745
|
+
width: 100%;
|
|
7746
|
+
padding: 6px 16px;
|
|
7747
|
+
background: transparent;
|
|
7748
|
+
border: none;
|
|
7749
|
+
text-align: left;
|
|
7750
|
+
cursor: pointer;
|
|
7751
|
+
font: inherit;
|
|
7752
|
+
font-size: 13px;
|
|
7753
|
+
color: var(--kr-chatbot-primary);
|
|
7754
|
+
font-weight: 500;
|
|
7755
|
+
}
|
|
7756
|
+
|
|
7757
|
+
/* Highlight (keyboard) and hover (mouse) are independent — either shades the
|
|
7758
|
+
row. Declared after the base rules so it wins the cascade for both the
|
|
7759
|
+
action buttons and the skill items. */
|
|
7760
|
+
.skill-menu__action.skill-menu__item--highlighted,
|
|
7761
|
+
.skill-menu__item.skill-menu__item--highlighted,
|
|
7762
|
+
.skill-menu__action:hover,
|
|
7763
|
+
.skill-menu__item:hover {
|
|
7764
|
+
background: #f3f4f6;
|
|
7765
|
+
}
|
|
7766
|
+
|
|
7767
|
+
/* Browse-all dialog body. Owns the height so the dialog is the same size on
|
|
7768
|
+
every tab; the search is fixed and the card grid flexes/scrolls to fill. */
|
|
7769
|
+
.skill-browse {
|
|
7770
|
+
display: flex;
|
|
7771
|
+
flex-direction: column;
|
|
7772
|
+
height: 70vh;
|
|
7773
|
+
}
|
|
7774
|
+
|
|
7775
|
+
.skill-browse kr-text-field {
|
|
7776
|
+
display: block;
|
|
7777
|
+
margin: 20px 20px 16px;
|
|
7778
|
+
flex-shrink: 0;
|
|
7779
|
+
}
|
|
7780
|
+
|
|
7781
|
+
.skill-browse kr-tab-group {
|
|
7782
|
+
flex: 1;
|
|
7783
|
+
min-height: 0;
|
|
7784
|
+
}
|
|
7785
|
+
|
|
7786
|
+
/* The grid is the scroller and spans the full width, so its scrollbar sits
|
|
7787
|
+
flush against the dialog edge; padding-right insets the cards from it. */
|
|
7788
|
+
.skill-browse__grid {
|
|
7789
|
+
height: 100%;
|
|
7790
|
+
overflow-y: auto;
|
|
7791
|
+
display: grid;
|
|
7792
|
+
grid-template-columns: repeat(3, 1fr);
|
|
7793
|
+
grid-auto-rows: min-content;
|
|
7794
|
+
align-content: start;
|
|
7795
|
+
gap: 12px;
|
|
7796
|
+
padding: 16px 20px 20px;
|
|
7797
|
+
}
|
|
7798
|
+
|
|
7799
|
+
.skill-card {
|
|
7800
|
+
display: flex;
|
|
7801
|
+
flex-direction: column;
|
|
7802
|
+
gap: 6px;
|
|
7803
|
+
padding: 14px;
|
|
7804
|
+
background: white;
|
|
7805
|
+
border: 1px solid #e5e7eb;
|
|
7806
|
+
border-radius: 10px;
|
|
7807
|
+
text-align: left;
|
|
7808
|
+
cursor: pointer;
|
|
7809
|
+
font: inherit;
|
|
7810
|
+
color: #000000;
|
|
7811
|
+
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
7812
|
+
}
|
|
7813
|
+
|
|
7814
|
+
.skill-card:hover {
|
|
7815
|
+
border-color: var(--kr-chatbot-primary);
|
|
7816
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
7817
|
+
}
|
|
7818
|
+
|
|
7819
|
+
.skill-card__name {
|
|
7820
|
+
font-weight: 600;
|
|
7821
|
+
}
|
|
7822
|
+
|
|
7823
|
+
.skill-card__desc {
|
|
7824
|
+
font-size: 12px;
|
|
7825
|
+
color: #000000;
|
|
7826
|
+
}
|
|
7827
|
+
|
|
7828
|
+
.skill-browse__empty {
|
|
7829
|
+
height: 100%;
|
|
7830
|
+
padding: 32px;
|
|
7831
|
+
text-align: center;
|
|
7832
|
+
color: #000000;
|
|
7833
|
+
}
|
|
7834
|
+
|
|
7193
7835
|
/* Composer attachment chips (pre-send) */
|
|
7194
7836
|
.composer-attachments {
|
|
7195
7837
|
display: flex;
|
|
@@ -7285,13 +7927,13 @@ __decorate([
|
|
|
7285
7927
|
], KRChatbot.prototype, "messages", void 0);
|
|
7286
7928
|
__decorate([
|
|
7287
7929
|
n({ type: String })
|
|
7288
|
-
], KRChatbot.prototype, "
|
|
7289
|
-
__decorate([
|
|
7290
|
-
n({ type: String })
|
|
7291
|
-
], KRChatbot.prototype, "subtitle", void 0);
|
|
7930
|
+
], KRChatbot.prototype, "label", void 0);
|
|
7292
7931
|
__decorate([
|
|
7293
7932
|
n({ type: String })
|
|
7294
7933
|
], KRChatbot.prototype, "placeholder", void 0);
|
|
7934
|
+
__decorate([
|
|
7935
|
+
n({ attribute: false })
|
|
7936
|
+
], KRChatbot.prototype, "skills", void 0);
|
|
7295
7937
|
__decorate([
|
|
7296
7938
|
n({
|
|
7297
7939
|
type: Boolean,
|
|
@@ -7305,24 +7947,48 @@ __decorate([
|
|
|
7305
7947
|
reflect: true
|
|
7306
7948
|
})
|
|
7307
7949
|
], KRChatbot.prototype, "hideToggle", void 0);
|
|
7950
|
+
__decorate([
|
|
7951
|
+
n({
|
|
7952
|
+
type: String,
|
|
7953
|
+
reflect: true
|
|
7954
|
+
})
|
|
7955
|
+
], KRChatbot.prototype, "variant", void 0);
|
|
7308
7956
|
__decorate([
|
|
7309
7957
|
r()
|
|
7310
7958
|
], KRChatbot.prototype, "_inputValue", void 0);
|
|
7311
7959
|
__decorate([
|
|
7312
7960
|
r()
|
|
7313
7961
|
], KRChatbot.prototype, "_isStreaming", void 0);
|
|
7314
|
-
__decorate([
|
|
7315
|
-
r()
|
|
7316
|
-
], KRChatbot.prototype, "_statusText", void 0);
|
|
7317
7962
|
__decorate([
|
|
7318
7963
|
r()
|
|
7319
7964
|
], KRChatbot.prototype, "_error", void 0);
|
|
7320
7965
|
__decorate([
|
|
7321
7966
|
r()
|
|
7322
|
-
], KRChatbot.prototype, "
|
|
7967
|
+
], KRChatbot.prototype, "_pendingInternalFiles", void 0);
|
|
7323
7968
|
__decorate([
|
|
7324
7969
|
r()
|
|
7325
7970
|
], KRChatbot.prototype, "_isDraggingFile", void 0);
|
|
7971
|
+
__decorate([
|
|
7972
|
+
r()
|
|
7973
|
+
], KRChatbot.prototype, "_skillMenuOpened", void 0);
|
|
7974
|
+
__decorate([
|
|
7975
|
+
r()
|
|
7976
|
+
], KRChatbot.prototype, "_skillQuery", void 0);
|
|
7977
|
+
__decorate([
|
|
7978
|
+
r()
|
|
7979
|
+
], KRChatbot.prototype, "_skillHighlighted", void 0);
|
|
7980
|
+
__decorate([
|
|
7981
|
+
r()
|
|
7982
|
+
], KRChatbot.prototype, "_copiedIndex", void 0);
|
|
7983
|
+
__decorate([
|
|
7984
|
+
r()
|
|
7985
|
+
], KRChatbot.prototype, "_skillBrowseOpened", void 0);
|
|
7986
|
+
__decorate([
|
|
7987
|
+
r()
|
|
7988
|
+
], KRChatbot.prototype, "_skillBrowseSource", void 0);
|
|
7989
|
+
__decorate([
|
|
7990
|
+
r()
|
|
7991
|
+
], KRChatbot.prototype, "_skillBrowseQuery", void 0);
|
|
7326
7992
|
__decorate([
|
|
7327
7993
|
e$3('.panel')
|
|
7328
7994
|
], KRChatbot.prototype, "_panelEl", void 0);
|
|
@@ -7335,6 +8001,12 @@ __decorate([
|
|
|
7335
8001
|
__decorate([
|
|
7336
8002
|
e$3('.file-input')
|
|
7337
8003
|
], KRChatbot.prototype, "_fileInputEl", void 0);
|
|
8004
|
+
__decorate([
|
|
8005
|
+
e$3('.input-wrapper')
|
|
8006
|
+
], KRChatbot.prototype, "_inputWrapperEl", void 0);
|
|
8007
|
+
__decorate([
|
|
8008
|
+
e$3('.skill-menu')
|
|
8009
|
+
], KRChatbot.prototype, "_skillMenuEl", void 0);
|
|
7338
8010
|
KRChatbot = __decorate([
|
|
7339
8011
|
t$2('kr-chatbot')
|
|
7340
8012
|
], KRChatbot);
|