@kodaris/krubble-app-components 1.0.123 → 1.0.125
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 +109 -8
- package/dist/chatbot.d.ts.map +1 -1
- package/dist/chatbot.js +603 -41
- package/dist/chatbot.js.map +1 -1
- package/dist/krubble-app.bundled.js +603 -41
- package/dist/krubble-app.bundled.js.map +1 -1
- package/dist/krubble-app.bundled.min.js +290 -49
- package/dist/krubble-app.bundled.min.js.map +1 -1
- package/dist/krubble-app.umd.js +603 -41
- package/dist/krubble-app.umd.js.map +1 -1
- package/dist/krubble-app.umd.min.js +276 -35
- package/dist/krubble-app.umd.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -2923,6 +2923,7 @@ class KRChatbot extends i$3 {
|
|
|
2923
2923
|
this._orgSkillRequestId = 0;
|
|
2924
2924
|
this._globalSkillRequestId = 0;
|
|
2925
2925
|
this._invocableSkillRequestId = 0;
|
|
2926
|
+
this._suggestedActionRequestId = 0;
|
|
2926
2927
|
/**
|
|
2927
2928
|
* Codes of global skills with an in-flight enable/disable request. The `+`
|
|
2928
2929
|
* button reads this to show a pending state and ignore repeat clicks. Mutated
|
|
@@ -3016,6 +3017,14 @@ class KRChatbot extends i$3 {
|
|
|
3016
3017
|
this._inputValue = '';
|
|
3017
3018
|
this._isStreaming = false;
|
|
3018
3019
|
this._error = '';
|
|
3020
|
+
/**
|
|
3021
|
+
* The current conversation's title. In the floating widget it replaces the
|
|
3022
|
+
* static header label so the user sees which conversation they're in. Set from
|
|
3023
|
+
* the loaded/switched conversation and from the live `CONVERSATION_TITLE` event
|
|
3024
|
+
* (the server generates a title at the end of a new conversation's first turn);
|
|
3025
|
+
* empty for a brand-new conversation, where the header falls back to `label`.
|
|
3026
|
+
*/
|
|
3027
|
+
this._conversationTitle = '';
|
|
3019
3028
|
/**
|
|
3020
3029
|
* User-facing context warning text (`CONVERSATION_TOKEN_WARNING`). Shown as a
|
|
3021
3030
|
* dismissible banner in all variants. Carries only friendly guidance, no numbers.
|
|
@@ -3075,12 +3084,23 @@ class KRChatbot extends i$3 {
|
|
|
3075
3084
|
*/
|
|
3076
3085
|
this._drawerOpen = false;
|
|
3077
3086
|
/**
|
|
3078
|
-
* Which view the drawer shows — settings, debug, or a single tool
|
|
3079
|
-
* detail. One drawer holds all
|
|
3080
|
-
* and clicking a tool line switches to `toolDetail`. The
|
|
3081
|
-
* inside. Never null, so the content stays visible while the
|
|
3087
|
+
* Which view the drawer shows — settings, debug, history, or a single tool
|
|
3088
|
+
* call's full detail. One drawer holds them all; header buttons switch
|
|
3089
|
+
* settings/debug/history and clicking a tool line switches to `toolDetail`. The
|
|
3090
|
+
* content/width swap inside. Never null, so the content stays visible while the
|
|
3091
|
+
* drawer slides shut. `history` is floating-only (the previous-conversations
|
|
3092
|
+
* picker); in floating the drawer fills the panel over the transcript.
|
|
3082
3093
|
*/
|
|
3083
3094
|
this._drawerView = 'settings';
|
|
3095
|
+
/**
|
|
3096
|
+
* The user's previous conversations, loaded from `/conversation/list` when the
|
|
3097
|
+
* history view opens. Each is the raw ConversationViewDto (we read conversationID,
|
|
3098
|
+
* title, lastModified). Empty until the first open; reloaded on each open so a
|
|
3099
|
+
* freshly-created or renamed conversation shows.
|
|
3100
|
+
*/
|
|
3101
|
+
this._conversations = [];
|
|
3102
|
+
/** True while the history list is being fetched (drives a loading state). */
|
|
3103
|
+
this._conversationsLoading = false;
|
|
3084
3104
|
/**
|
|
3085
3105
|
* The tool call whose full input/output the `toolDetail` drawer view shows —
|
|
3086
3106
|
* the clicked `tool_use` message and its paired `tool_result` message, stored
|
|
@@ -3126,6 +3146,12 @@ class KRChatbot extends i$3 {
|
|
|
3126
3146
|
* so installed globals in the menu never leak into the "Your Org" tab.
|
|
3127
3147
|
*/
|
|
3128
3148
|
this._invocableSkills = [];
|
|
3149
|
+
/**
|
|
3150
|
+
* Context-aware action chips for the empty state, from `/conversation/suggestedActions`.
|
|
3151
|
+
* Loaded fresh every time the panel opens on an empty conversation (see `_loadSuggestedActions`);
|
|
3152
|
+
* cleared when the first message is sent so they don't linger over a live conversation.
|
|
3153
|
+
*/
|
|
3154
|
+
this._suggestedActions = [];
|
|
3129
3155
|
/**
|
|
3130
3156
|
* AI framework UI config flags fetched from `aiFrameworkConfig` on connect.
|
|
3131
3157
|
* `debugTelemetryEnabled` (same server-side gate as TOKEN_USAGE emission) turns
|
|
@@ -3318,6 +3344,11 @@ class KRChatbot extends i$3 {
|
|
|
3318
3344
|
// --- Lifecycle ---
|
|
3319
3345
|
connectedCallback() {
|
|
3320
3346
|
super.connectedCallback();
|
|
3347
|
+
// Capture the consumer's targeting BEFORE we default `load` below: a custom
|
|
3348
|
+
// `load` or an explicitly-set `conversation-id` means the consumer owns which
|
|
3349
|
+
// conversation shows, so the tab-scoped resume must not override it.
|
|
3350
|
+
const usesBuiltInLoad = !this.load;
|
|
3351
|
+
const consumerSetConversationId = this.conversationId != null;
|
|
3321
3352
|
// Default to loading a conversation's messages when the consumer hasn't
|
|
3322
3353
|
// provided their own `load`. With `conversationId` set we rebuild that
|
|
3323
3354
|
// conversation; with none set the user wants a NEW conversation, so we start
|
|
@@ -3400,7 +3431,54 @@ class KRChatbot extends i$3 {
|
|
|
3400
3431
|
})));
|
|
3401
3432
|
};
|
|
3402
3433
|
}
|
|
3403
|
-
|
|
3434
|
+
// Tab-scoped resume (floating only): a reload should redisplay the exact
|
|
3435
|
+
// conversation this tab was on, and a brand-new tab should reopen the user's
|
|
3436
|
+
// most-recent one. The pinned id lives in sessionStorage (per-tab — unlike
|
|
3437
|
+
// localStorage it isn't shared across tabs, so two tabs can sit on different
|
|
3438
|
+
// conversations). We resolve the id FIRST, then run the built-in load so it
|
|
3439
|
+
// rebuilds the right transcript. Skipped when the consumer owns targeting (a
|
|
3440
|
+
// custom `load` or an explicit `conversation-id`) or in inline mode (embedded
|
|
3441
|
+
// as a page — the host route, not the tab, decides the conversation).
|
|
3442
|
+
const resolveConversationId = () => {
|
|
3443
|
+
if (this.variant !== 'floating' || !usesBuiltInLoad || consumerSetConversationId) {
|
|
3444
|
+
return Promise.resolve();
|
|
3445
|
+
}
|
|
3446
|
+
const stored = Number(sessionStorage.getItem('kr-chatbot-conversation-id'));
|
|
3447
|
+
if (stored > 0) {
|
|
3448
|
+
this.conversationId = stored;
|
|
3449
|
+
// Fetch the conversation so the header shows its title on reload (the
|
|
3450
|
+
// transcript load doesn't carry it). Best-effort — the header falls back
|
|
3451
|
+
// to the default label if this fails.
|
|
3452
|
+
return KRHttp.fetch({ url: `/api/system/conversation/${stored}` })
|
|
3453
|
+
.then((r) => r.json())
|
|
3454
|
+
.then((res) => {
|
|
3455
|
+
this._conversationTitle = res?.data?.title || '';
|
|
3456
|
+
})
|
|
3457
|
+
.catch(() => { });
|
|
3458
|
+
}
|
|
3459
|
+
// Fresh tab, nothing pinned yet — resume the user's most recent conversation
|
|
3460
|
+
// (404 when they have none, which leaves us blank for a new one).
|
|
3461
|
+
return KRHttp.fetch({ url: '/api/system/conversation/last' })
|
|
3462
|
+
.then((r) => {
|
|
3463
|
+
if (!r.ok) {
|
|
3464
|
+
return;
|
|
3465
|
+
}
|
|
3466
|
+
return r.json().then((res) => {
|
|
3467
|
+
const id = res?.data?.conversationID;
|
|
3468
|
+
if (typeof id === 'number') {
|
|
3469
|
+
this.conversationId = id;
|
|
3470
|
+
this._conversationTitle = res?.data?.title || '';
|
|
3471
|
+
this._persistConversationId();
|
|
3472
|
+
}
|
|
3473
|
+
});
|
|
3474
|
+
})
|
|
3475
|
+
.catch(() => { });
|
|
3476
|
+
};
|
|
3477
|
+
// `this.load` is always set by here (defaulted above when the consumer didn't
|
|
3478
|
+
// supply one), so capture it for the async chain — TS can't narrow the nullable
|
|
3479
|
+
// property across the promise boundary.
|
|
3480
|
+
const load = this.load;
|
|
3481
|
+
resolveConversationId().then(() => load()).then((messages) => {
|
|
3404
3482
|
if (messages && messages.length) {
|
|
3405
3483
|
this.messages = messages;
|
|
3406
3484
|
}
|
|
@@ -3480,6 +3558,13 @@ class KRChatbot extends i$3 {
|
|
|
3480
3558
|
}
|
|
3481
3559
|
}, 200);
|
|
3482
3560
|
}
|
|
3561
|
+
// Load context-aware action chips every time the panel opens on an empty conversation. Fires for
|
|
3562
|
+
// the floating variant on toggle-open and for the inline variant on its first render (which sets
|
|
3563
|
+
// `opened` true at connect). Only when empty — a resumed conversation shows its transcript, not chips.
|
|
3564
|
+
// The request-id guard inside handles a stale reply if the user closes/reopens quickly.
|
|
3565
|
+
if (changed.has('opened') && this.opened && this.messages.length === 0) {
|
|
3566
|
+
this._loadSuggestedActions();
|
|
3567
|
+
}
|
|
3483
3568
|
// Position the fixed skill menu above the composer, following the krubble
|
|
3484
3569
|
// select-field pattern (fixed element positioned from the trigger's rect).
|
|
3485
3570
|
if (this._skillMenuOpened) {
|
|
@@ -3635,12 +3720,31 @@ class KRChatbot extends i$3 {
|
|
|
3635
3720
|
}
|
|
3636
3721
|
this._saveState();
|
|
3637
3722
|
}
|
|
3723
|
+
/**
|
|
3724
|
+
* Persist the pinned conversation id per-tab so a reload redisplays this exact
|
|
3725
|
+
* conversation. sessionStorage (not localStorage) is deliberate: it's scoped to
|
|
3726
|
+
* the tab, so two tabs can sit on different conversations without clobbering
|
|
3727
|
+
* each other. Only meaningful for the floating widget's built-in flow — inline
|
|
3728
|
+
* embeds and custom-`load` consumers own their own targeting.
|
|
3729
|
+
*/
|
|
3730
|
+
_persistConversationId() {
|
|
3731
|
+
try {
|
|
3732
|
+
if (this.conversationId != null) {
|
|
3733
|
+
sessionStorage.setItem('kr-chatbot-conversation-id', String(this.conversationId));
|
|
3734
|
+
}
|
|
3735
|
+
else {
|
|
3736
|
+
sessionStorage.removeItem('kr-chatbot-conversation-id');
|
|
3737
|
+
}
|
|
3738
|
+
}
|
|
3739
|
+
catch { /* sessionStorage not available */ }
|
|
3740
|
+
}
|
|
3638
3741
|
_saveState() {
|
|
3639
3742
|
try {
|
|
3640
|
-
// `toolDetail`
|
|
3641
|
-
// real preference views so a reload never reopens a stale tool
|
|
3743
|
+
// `toolDetail` and `history` are transient views, not saved ones — persist
|
|
3744
|
+
// only the real preference views so a reload never reopens a stale tool or a
|
|
3745
|
+
// stale conversation list.
|
|
3642
3746
|
let persistedDrawerView = this._drawerView;
|
|
3643
|
-
if (persistedDrawerView === 'toolDetail') {
|
|
3747
|
+
if (persistedDrawerView === 'toolDetail' || persistedDrawerView === 'history') {
|
|
3644
3748
|
persistedDrawerView = 'settings';
|
|
3645
3749
|
}
|
|
3646
3750
|
const state = {
|
|
@@ -3912,6 +4016,41 @@ class KRChatbot extends i$3 {
|
|
|
3912
4016
|
console.error('kr-chatbot: invocable skill search failed', error);
|
|
3913
4017
|
});
|
|
3914
4018
|
}
|
|
4019
|
+
/**
|
|
4020
|
+
* Load the empty-state action chips from `/conversation/suggestedActions`, passing the user's
|
|
4021
|
+
* current page/selection context (captured live, same as a send). The server picks a few skills
|
|
4022
|
+
* the user can run that fit where they are and writes a label for each. Called every time the
|
|
4023
|
+
* panel opens on an empty conversation (per product decision — context can change between opens).
|
|
4024
|
+
*
|
|
4025
|
+
* AI-only, no fallback: any failure, or v2 chat being off (server returns `[]`), just leaves the
|
|
4026
|
+
* empty state with no chips. A request-id guard drops a response superseded by a newer open, so a
|
|
4027
|
+
* slow reply from a previous open can't land after the user has started typing.
|
|
4028
|
+
*/
|
|
4029
|
+
_loadSuggestedActions() {
|
|
4030
|
+
this._suggestedActionRequestId++;
|
|
4031
|
+
const requestId = this._suggestedActionRequestId;
|
|
4032
|
+
const context = this._captureContext();
|
|
4033
|
+
KRHttp.fetch({
|
|
4034
|
+
url: '/api/system/conversation/suggestedActions',
|
|
4035
|
+
method: 'POST',
|
|
4036
|
+
body: {
|
|
4037
|
+
pageContext: context.pageContext,
|
|
4038
|
+
selectionContext: context.selectionContext,
|
|
4039
|
+
},
|
|
4040
|
+
})
|
|
4041
|
+
.then((r) => r.json())
|
|
4042
|
+
.then((res) => {
|
|
4043
|
+
// Ignore a stale response from a prior open, and never overwrite chips once a conversation
|
|
4044
|
+
// has started (the user opened, the reply was slow, they typed and sent in the meantime).
|
|
4045
|
+
if (requestId !== this._suggestedActionRequestId || this.messages.length > 0) {
|
|
4046
|
+
return;
|
|
4047
|
+
}
|
|
4048
|
+
this._suggestedActions = (res?.data || []);
|
|
4049
|
+
})
|
|
4050
|
+
.catch((error) => {
|
|
4051
|
+
console.error('kr-chatbot: suggested actions load failed', error);
|
|
4052
|
+
});
|
|
4053
|
+
}
|
|
3915
4054
|
/**
|
|
3916
4055
|
* Load the browse dialog's "Kodaris" tab into `_globalSkills` — the whole
|
|
3917
4056
|
* published Kodaris catalog for discovery, installed or not, runnable by this
|
|
@@ -4155,6 +4294,17 @@ class KRChatbot extends i$3 {
|
|
|
4155
4294
|
this._handleSkillSelect(skill);
|
|
4156
4295
|
}
|
|
4157
4296
|
}
|
|
4297
|
+
/**
|
|
4298
|
+
* Click an empty-state suggestion chip: prefill `/code ` into the composer, same as picking the
|
|
4299
|
+
* skill from the `/` menu, and focus so the user can add details before sending. No permission
|
|
4300
|
+
* guards here (unlike `_handleSkillSelect`) — a suggested action's code always comes from the
|
|
4301
|
+
* server's role-filtered runnable set, so it's already known to be invokable by this user.
|
|
4302
|
+
*/
|
|
4303
|
+
_handleSuggestedActionClick(action) {
|
|
4304
|
+
this._inputValue = `/${action.code} `;
|
|
4305
|
+
this._saveState();
|
|
4306
|
+
this._inputEl?.focus();
|
|
4307
|
+
}
|
|
4158
4308
|
/** Copy a message's text to the clipboard and briefly flash "Copied". */
|
|
4159
4309
|
_handleCopyMessage(content, index) {
|
|
4160
4310
|
navigator.clipboard.writeText(content).then(() => {
|
|
@@ -4437,6 +4587,9 @@ class KRChatbot extends i$3 {
|
|
|
4437
4587
|
}
|
|
4438
4588
|
this.messages = [...this.messages, userMessage];
|
|
4439
4589
|
this._inputValue = '';
|
|
4590
|
+
// The conversation has started — drop the empty-state chips so they don't linger above the
|
|
4591
|
+
// transcript. A newer suggestedActions reply is also ignored now (its guard checks messages.length).
|
|
4592
|
+
this._suggestedActions = [];
|
|
4440
4593
|
this._saveState();
|
|
4441
4594
|
this._error = '';
|
|
4442
4595
|
this._userHasScrolledUp = false;
|
|
@@ -4596,6 +4749,8 @@ class KRChatbot extends i$3 {
|
|
|
4596
4749
|
const id = conversation?.conversationID;
|
|
4597
4750
|
if (typeof id === 'number') {
|
|
4598
4751
|
this.conversationId = id;
|
|
4752
|
+
// Pin it to this tab so a reload redisplays this new conversation.
|
|
4753
|
+
this._persistConversationId();
|
|
4599
4754
|
// Announce the newly-created conversation so consumers can react
|
|
4600
4755
|
// (e.g. update the route from /chat/new to /chat/{id}). The full
|
|
4601
4756
|
// conversation object is passed, not just the id, so consumers
|
|
@@ -4793,9 +4948,111 @@ class KRChatbot extends i$3 {
|
|
|
4793
4948
|
else {
|
|
4794
4949
|
this._drawerOpen = true;
|
|
4795
4950
|
this._drawerView = view;
|
|
4951
|
+
// Opening the history view refetches the user's previous conversations
|
|
4952
|
+
// (most-recently modified first) so a just-created or renamed conversation
|
|
4953
|
+
// shows without a reload. Ownership is enforced server-side (the endpoint
|
|
4954
|
+
// scopes to the current administrator), so we only filter to active ones.
|
|
4955
|
+
if (view === 'history') {
|
|
4956
|
+
this._conversationsLoading = true;
|
|
4957
|
+
KRHttp.fetch({
|
|
4958
|
+
url: '/api/system/conversation/list',
|
|
4959
|
+
method: 'POST',
|
|
4960
|
+
body: {
|
|
4961
|
+
page: 0,
|
|
4962
|
+
size: 50,
|
|
4963
|
+
sortBy: 'lastModified',
|
|
4964
|
+
sortDirection: 'desc',
|
|
4965
|
+
filterFields: [{
|
|
4966
|
+
name: 'active',
|
|
4967
|
+
operation: 'IS',
|
|
4968
|
+
value: 'true',
|
|
4969
|
+
}],
|
|
4970
|
+
},
|
|
4971
|
+
})
|
|
4972
|
+
.then((r) => r.json())
|
|
4973
|
+
.then((res) => {
|
|
4974
|
+
this._conversations = res?.data?.content || [];
|
|
4975
|
+
})
|
|
4976
|
+
.catch(() => {
|
|
4977
|
+
this._conversations = [];
|
|
4978
|
+
})
|
|
4979
|
+
.then(() => {
|
|
4980
|
+
this._conversationsLoading = false;
|
|
4981
|
+
});
|
|
4982
|
+
}
|
|
4796
4983
|
}
|
|
4797
4984
|
this._saveState();
|
|
4798
4985
|
}
|
|
4986
|
+
/**
|
|
4987
|
+
* Switch the floating widget to a previously-created conversation (clicked in the
|
|
4988
|
+
* history list): stop any live turn, reset the transient turn/context state, pin
|
|
4989
|
+
* the new id (persisted per-tab so a reload stays here), then rebuild its
|
|
4990
|
+
* transcript via the built-in `load`. The drawer closes so the user lands back
|
|
4991
|
+
* in the conversation.
|
|
4992
|
+
*/
|
|
4993
|
+
_handleSwitchConversation(conversationID) {
|
|
4994
|
+
if (conversationID === this.conversationId) {
|
|
4995
|
+
this._handleCloseDrawer();
|
|
4996
|
+
return;
|
|
4997
|
+
}
|
|
4998
|
+
this._handleStop();
|
|
4999
|
+
this.conversationId = conversationID;
|
|
5000
|
+
// Adopt the picked conversation's title for the header (empty for an untitled
|
|
5001
|
+
// one, so the header falls back to the default label).
|
|
5002
|
+
this._conversationTitle = this._conversations.find((c) => c.conversationID === conversationID)?.title || '';
|
|
5003
|
+
this._persistConversationId();
|
|
5004
|
+
this._resetConversationState();
|
|
5005
|
+
this._drawerOpen = false;
|
|
5006
|
+
this._saveState();
|
|
5007
|
+
if (this.load) {
|
|
5008
|
+
this.load().then((messages) => {
|
|
5009
|
+
this.messages = messages || [];
|
|
5010
|
+
// A turn may still be streaming server-side for the conversation we just
|
|
5011
|
+
// opened (started in another tab/device) — attach to it if so.
|
|
5012
|
+
if (this.conversationId && !this._isStreaming) {
|
|
5013
|
+
this._reconnectStream();
|
|
5014
|
+
}
|
|
5015
|
+
}).catch(() => { });
|
|
5016
|
+
}
|
|
5017
|
+
}
|
|
5018
|
+
/**
|
|
5019
|
+
* Start a brand-new conversation (clicked in the history list): unpin the id (the
|
|
5020
|
+
* next turn sends `createNew` and the resolved id re-pins), clear the transcript
|
|
5021
|
+
* and transient state, and close the drawer back to an empty composer.
|
|
5022
|
+
*/
|
|
5023
|
+
_handleNewConversation() {
|
|
5024
|
+
this._handleStop();
|
|
5025
|
+
this.conversationId = null;
|
|
5026
|
+
// New conversation has no title yet — the header shows the default label until
|
|
5027
|
+
// the server generates one at the end of the first turn.
|
|
5028
|
+
this._conversationTitle = '';
|
|
5029
|
+
this._persistConversationId();
|
|
5030
|
+
this.messages = [];
|
|
5031
|
+
this._resetConversationState();
|
|
5032
|
+
this._drawerOpen = false;
|
|
5033
|
+
this._saveState();
|
|
5034
|
+
}
|
|
5035
|
+
/**
|
|
5036
|
+
* Clear the transient, per-conversation state that must not bleed across a
|
|
5037
|
+
* conversation switch/new — pending confirmations, context banners, errors, the
|
|
5038
|
+
* reconnect counter, and staged composer files. The transcript itself is set by
|
|
5039
|
+
* the caller (loaded for a switch, emptied for new).
|
|
5040
|
+
*/
|
|
5041
|
+
_resetConversationState() {
|
|
5042
|
+
this._pendingActions = [];
|
|
5043
|
+
this._inlineConfirm = true;
|
|
5044
|
+
this._contextWarning = '';
|
|
5045
|
+
this._contextLimitReached = false;
|
|
5046
|
+
this._contextLimitMessage = '';
|
|
5047
|
+
this._error = '';
|
|
5048
|
+
this._reconnectAttempts = 0;
|
|
5049
|
+
this._pendingConversationFiles.forEach((p) => {
|
|
5050
|
+
if (p.previewUrl) {
|
|
5051
|
+
URL.revokeObjectURL(p.previewUrl);
|
|
5052
|
+
}
|
|
5053
|
+
});
|
|
5054
|
+
this._pendingConversationFiles = [];
|
|
5055
|
+
}
|
|
4799
5056
|
/** Close the drawer. `_drawerView` is left intact so its content stays visible
|
|
4800
5057
|
* while the drawer slides shut. */
|
|
4801
5058
|
_handleCloseDrawer() {
|
|
@@ -5077,7 +5334,7 @@ class KRChatbot extends i$3 {
|
|
|
5077
5334
|
// deliberately never show). Adopt it as the header label and pass it
|
|
5078
5335
|
// up so consumers can update their own chrome, e.g. a breadcrumb.
|
|
5079
5336
|
if (data.data?.title) {
|
|
5080
|
-
this.
|
|
5337
|
+
this._conversationTitle = data.data.title;
|
|
5081
5338
|
this.dispatchEvent(new CustomEvent('conversation-title', {
|
|
5082
5339
|
detail: { title: data.data.title },
|
|
5083
5340
|
bubbles: true,
|
|
@@ -5663,10 +5920,75 @@ class KRChatbot extends i$3 {
|
|
|
5663
5920
|
* lifetime — plus a verbose per-iteration table. Never customer-facing.
|
|
5664
5921
|
*/
|
|
5665
5922
|
/**
|
|
5666
|
-
* The
|
|
5667
|
-
*
|
|
5668
|
-
*
|
|
5669
|
-
*
|
|
5923
|
+
* The History view's body — the user's previous conversations (most recent
|
|
5924
|
+
* first) plus a "New conversation" action. Clicking a row switches the widget to
|
|
5925
|
+
* that conversation; the current one is marked so the user sees where they are.
|
|
5926
|
+
* Floating-only (opened from the header history button).
|
|
5927
|
+
*/
|
|
5928
|
+
_renderHistoryContent() {
|
|
5929
|
+
return b `
|
|
5930
|
+
<div class="history">
|
|
5931
|
+
${this._conversationsLoading ? b `
|
|
5932
|
+
<div class="history__empty">Loading…</div>
|
|
5933
|
+
` : this._conversations.length === 0 ? b `
|
|
5934
|
+
<div class="history__empty">No previous conversations</div>
|
|
5935
|
+
` : b `
|
|
5936
|
+
<div class="history__list">
|
|
5937
|
+
${this._conversations.map((conversation) => b `
|
|
5938
|
+
<button
|
|
5939
|
+
type="button"
|
|
5940
|
+
class=${e({
|
|
5941
|
+
'history__item': true,
|
|
5942
|
+
'history__item--active': conversation.conversationID === this.conversationId,
|
|
5943
|
+
})}
|
|
5944
|
+
@click=${() => this._handleSwitchConversation(conversation.conversationID)}
|
|
5945
|
+
>
|
|
5946
|
+
<span class="history__item-title">${conversation.title || 'Untitled conversation'}</span>
|
|
5947
|
+
${conversation.lastModified ? b `
|
|
5948
|
+
<span class="history__item-date">${this._renderConversationDate(conversation.lastModified)}</span>
|
|
5949
|
+
` : A}
|
|
5950
|
+
</button>
|
|
5951
|
+
`)}
|
|
5952
|
+
</div>
|
|
5953
|
+
`}
|
|
5954
|
+
</div>
|
|
5955
|
+
`;
|
|
5956
|
+
}
|
|
5957
|
+
/**
|
|
5958
|
+
* Format a conversation's lastModified for the history list: today shows the
|
|
5959
|
+
* time, this year shows month/day, older shows month/day/year. Falls back to the
|
|
5960
|
+
* raw value if it isn't a parseable date.
|
|
5961
|
+
*/
|
|
5962
|
+
_renderConversationDate(lastModified) {
|
|
5963
|
+
const date = new Date(lastModified);
|
|
5964
|
+
if (isNaN(date.getTime())) {
|
|
5965
|
+
return lastModified;
|
|
5966
|
+
}
|
|
5967
|
+
const now = new Date();
|
|
5968
|
+
if (date.toDateString() === now.toDateString()) {
|
|
5969
|
+
return date.toLocaleTimeString('en-US', {
|
|
5970
|
+
hour: 'numeric',
|
|
5971
|
+
minute: '2-digit',
|
|
5972
|
+
});
|
|
5973
|
+
}
|
|
5974
|
+
if (date.getFullYear() === now.getFullYear()) {
|
|
5975
|
+
return date.toLocaleDateString('en-US', {
|
|
5976
|
+
month: 'short',
|
|
5977
|
+
day: 'numeric',
|
|
5978
|
+
});
|
|
5979
|
+
}
|
|
5980
|
+
return date.toLocaleDateString('en-US', {
|
|
5981
|
+
month: 'short',
|
|
5982
|
+
day: 'numeric',
|
|
5983
|
+
year: 'numeric',
|
|
5984
|
+
});
|
|
5985
|
+
}
|
|
5986
|
+
/**
|
|
5987
|
+
* The side drawer — one sliding panel that holds the Settings, Debug, History,
|
|
5988
|
+
* and tool-detail views. The header buttons switch `_drawerView`; the title and
|
|
5989
|
+
* body swap inside. In inline mode it slides in beside the transcript at a
|
|
5990
|
+
* consistent (resizable) width; in floating mode it fills the panel over the
|
|
5991
|
+
* transcript with a back button (the panel is too narrow to show both).
|
|
5670
5992
|
*/
|
|
5671
5993
|
_renderDrawer() {
|
|
5672
5994
|
// The debug view is gated on the server-side flag (inline variant + debug
|
|
@@ -5684,41 +6006,101 @@ class KRChatbot extends i$3 {
|
|
|
5684
6006
|
title = this._toolDetail.use.data?.displayName || this._toolDetail.use.data?.toolName || 'Tool';
|
|
5685
6007
|
body = this._renderToolDetailContent();
|
|
5686
6008
|
}
|
|
6009
|
+
else if (this._drawerView === 'history') {
|
|
6010
|
+
title = 'Conversations';
|
|
6011
|
+
body = this._renderHistoryContent();
|
|
6012
|
+
}
|
|
6013
|
+
// In the floating widget the drawer fills the panel over the transcript (a
|
|
6014
|
+
// full-panel view with a back button) rather than sliding in beside it — the
|
|
6015
|
+
// panel is too narrow to show both. Inline keeps the side-drawer behavior.
|
|
6016
|
+
const fullPanel = this.variant === 'floating';
|
|
5687
6017
|
return b `
|
|
5688
6018
|
<div
|
|
5689
6019
|
class=${e({
|
|
5690
6020
|
'drawer': true,
|
|
5691
6021
|
'drawer--open': this._drawerOpen,
|
|
5692
6022
|
'drawer--resizing': this._isDrawerResizing,
|
|
6023
|
+
'drawer--full': fullPanel,
|
|
5693
6024
|
})}
|
|
5694
|
-
style=${o({ width: `${this._drawerWidth}px` })}
|
|
6025
|
+
style=${o(fullPanel ? {} : { width: `${this._drawerWidth}px` })}
|
|
5695
6026
|
>
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
6027
|
+
${fullPanel ? A : b `
|
|
6028
|
+
<div
|
|
6029
|
+
class="drawer__resize"
|
|
6030
|
+
@mousedown=${this._handleDrawerResizeMouseDown}
|
|
6031
|
+
></div>
|
|
6032
|
+
`}
|
|
5700
6033
|
<div class="drawer__header">
|
|
6034
|
+
${fullPanel ? b `
|
|
6035
|
+
<button
|
|
6036
|
+
class="header-action"
|
|
6037
|
+
@click=${this._handleCloseDrawer}
|
|
6038
|
+
title="Back"
|
|
6039
|
+
>
|
|
6040
|
+
<svg
|
|
6041
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6042
|
+
fill="none"
|
|
6043
|
+
viewBox="0 0 24 24"
|
|
6044
|
+
stroke-width="2"
|
|
6045
|
+
stroke="currentColor"
|
|
6046
|
+
class="header-action-icon"
|
|
6047
|
+
>
|
|
6048
|
+
<path
|
|
6049
|
+
stroke-linecap="round"
|
|
6050
|
+
stroke-linejoin="round"
|
|
6051
|
+
d="M15.75 19.5 8.25 12l7.5-7.5"
|
|
6052
|
+
/>
|
|
6053
|
+
</svg>
|
|
6054
|
+
</button>
|
|
6055
|
+
` : A}
|
|
5701
6056
|
<span class="drawer__title">${title}</span>
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
fill="none"
|
|
5710
|
-
viewBox="0 0 24 24"
|
|
5711
|
-
stroke-width="2"
|
|
5712
|
-
stroke="currentColor"
|
|
5713
|
-
class="header-action-icon"
|
|
6057
|
+
${this._drawerView === 'history' ? b `
|
|
6058
|
+
<kr-button
|
|
6059
|
+
class="history__new"
|
|
6060
|
+
variant="flat"
|
|
6061
|
+
color="primary"
|
|
6062
|
+
size="small"
|
|
6063
|
+
@click=${this._handleNewConversation}
|
|
5714
6064
|
>
|
|
5715
|
-
<
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
6065
|
+
<svg
|
|
6066
|
+
slot="icon"
|
|
6067
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6068
|
+
fill="none"
|
|
6069
|
+
viewBox="0 0 24 24"
|
|
6070
|
+
stroke-width="1.75"
|
|
6071
|
+
stroke="currentColor"
|
|
6072
|
+
>
|
|
6073
|
+
<path
|
|
6074
|
+
stroke-linecap="round"
|
|
6075
|
+
stroke-linejoin="round"
|
|
6076
|
+
d="M12 4.5v15m7.5-7.5h-15"
|
|
6077
|
+
/>
|
|
6078
|
+
</svg>
|
|
6079
|
+
New conversation
|
|
6080
|
+
</kr-button>
|
|
6081
|
+
` : A}
|
|
6082
|
+
${fullPanel ? A : b `
|
|
6083
|
+
<button
|
|
6084
|
+
class="header-action"
|
|
6085
|
+
@click=${this._handleCloseDrawer}
|
|
6086
|
+
title="Close"
|
|
6087
|
+
>
|
|
6088
|
+
<svg
|
|
6089
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6090
|
+
fill="none"
|
|
6091
|
+
viewBox="0 0 24 24"
|
|
6092
|
+
stroke-width="2"
|
|
6093
|
+
stroke="currentColor"
|
|
6094
|
+
class="header-action-icon"
|
|
6095
|
+
>
|
|
6096
|
+
<path
|
|
6097
|
+
stroke-linecap="round"
|
|
6098
|
+
stroke-linejoin="round"
|
|
6099
|
+
d="M6 18 18 6M6 6l12 12"
|
|
6100
|
+
/>
|
|
6101
|
+
</svg>
|
|
6102
|
+
</button>
|
|
6103
|
+
`}
|
|
5722
6104
|
</div>
|
|
5723
6105
|
<div class="drawer__body">
|
|
5724
6106
|
${body}
|
|
@@ -5979,9 +6361,10 @@ class KRChatbot extends i$3 {
|
|
|
5979
6361
|
const isDebugEnabled = this.variant === 'inline' && this._aiFrameworkConfig.debugTelemetryEnabled === true;
|
|
5980
6362
|
// Push the content over by the open drawer's width so the drawer sits beside
|
|
5981
6363
|
// the content rather than overlaying it. One consistent (resizable) width for
|
|
5982
|
-
// both views. Only pushes while the drawer is open
|
|
6364
|
+
// both views. Only pushes while the drawer is open, and only inline — the
|
|
6365
|
+
// floating drawer fills the panel over the transcript, so it must not push.
|
|
5983
6366
|
const contentPadding = {};
|
|
5984
|
-
if (this._drawerOpen) {
|
|
6367
|
+
if (this._drawerOpen && this.variant === 'inline') {
|
|
5985
6368
|
contentPadding.paddingRight = `${this._drawerWidth}px`;
|
|
5986
6369
|
}
|
|
5987
6370
|
// Group the transcript into runs so an agent turn (its reasoning/tool/text/
|
|
@@ -6099,10 +6482,52 @@ class KRChatbot extends i$3 {
|
|
|
6099
6482
|
<div class="header" @mousedown=${this._handleHeaderMouseDown}>
|
|
6100
6483
|
<div class="header-left">
|
|
6101
6484
|
<div class="header-info">
|
|
6102
|
-
<span class="header-title">${this.label}</span>
|
|
6485
|
+
<span class="header-title">${this._conversationTitle || this.label}</span>
|
|
6103
6486
|
</div>
|
|
6104
6487
|
</div>
|
|
6105
6488
|
<div class="header-actions">
|
|
6489
|
+
${this.variant === 'floating' ? b `
|
|
6490
|
+
<button
|
|
6491
|
+
class="header-action"
|
|
6492
|
+
@click=${this._handleNewConversation}
|
|
6493
|
+
title="New conversation"
|
|
6494
|
+
>
|
|
6495
|
+
<svg
|
|
6496
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6497
|
+
fill="none"
|
|
6498
|
+
viewBox="0 0 24 24"
|
|
6499
|
+
stroke-width="1.75"
|
|
6500
|
+
stroke="currentColor"
|
|
6501
|
+
class="header-action-icon"
|
|
6502
|
+
>
|
|
6503
|
+
<path
|
|
6504
|
+
stroke-linecap="round"
|
|
6505
|
+
stroke-linejoin="round"
|
|
6506
|
+
d="M12 4.5v15m7.5-7.5h-15"
|
|
6507
|
+
/>
|
|
6508
|
+
</svg>
|
|
6509
|
+
</button>
|
|
6510
|
+
<button
|
|
6511
|
+
class="header-action"
|
|
6512
|
+
@click=${() => this._toggleDrawer('history')}
|
|
6513
|
+
title="Conversations"
|
|
6514
|
+
>
|
|
6515
|
+
<svg
|
|
6516
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6517
|
+
fill="none"
|
|
6518
|
+
viewBox="0 0 24 24"
|
|
6519
|
+
stroke-width="1.5"
|
|
6520
|
+
stroke="currentColor"
|
|
6521
|
+
class="header-action-icon"
|
|
6522
|
+
>
|
|
6523
|
+
<path
|
|
6524
|
+
stroke-linecap="round"
|
|
6525
|
+
stroke-linejoin="round"
|
|
6526
|
+
d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
|
|
6527
|
+
/>
|
|
6528
|
+
</svg>
|
|
6529
|
+
</button>
|
|
6530
|
+
` : A}
|
|
6106
6531
|
<button
|
|
6107
6532
|
class="header-action"
|
|
6108
6533
|
@click=${() => this._toggleDrawer('settings')}
|
|
@@ -6180,6 +6605,17 @@ class KRChatbot extends i$3 {
|
|
|
6180
6605
|
${this.messages.length === 0 ? b `
|
|
6181
6606
|
<div class="empty">
|
|
6182
6607
|
<span class="empty-text">What can I help you with?</span>
|
|
6608
|
+
${this._suggestedActions.length ? b `
|
|
6609
|
+
<div class="empty-suggestions">
|
|
6610
|
+
${this._suggestedActions.map((action) => b `
|
|
6611
|
+
<button
|
|
6612
|
+
type="button"
|
|
6613
|
+
class="empty-suggestions__chip"
|
|
6614
|
+
@click=${() => this._handleSuggestedActionClick(action)}
|
|
6615
|
+
>${action.label}</button>
|
|
6616
|
+
`)}
|
|
6617
|
+
</div>
|
|
6618
|
+
` : A}
|
|
6183
6619
|
</div>
|
|
6184
6620
|
` : A}
|
|
6185
6621
|
${messageGroups.map((group) => {
|
|
@@ -6846,22 +7282,28 @@ KRChatbot.styles = i$6 `
|
|
|
6846
7282
|
display: flex;
|
|
6847
7283
|
align-items: center;
|
|
6848
7284
|
gap: 10px;
|
|
7285
|
+
min-width: 0;
|
|
6849
7286
|
}
|
|
6850
7287
|
|
|
6851
7288
|
.header-info {
|
|
6852
7289
|
display: flex;
|
|
6853
7290
|
flex-direction: column;
|
|
7291
|
+
min-width: 0;
|
|
6854
7292
|
}
|
|
6855
7293
|
|
|
6856
7294
|
.header-title {
|
|
6857
7295
|
font-size: 16px;
|
|
6858
7296
|
font-weight: 600;
|
|
7297
|
+
white-space: nowrap;
|
|
7298
|
+
overflow: hidden;
|
|
7299
|
+
text-overflow: ellipsis;
|
|
6859
7300
|
}
|
|
6860
7301
|
|
|
6861
7302
|
.header-actions {
|
|
6862
7303
|
display: flex;
|
|
6863
7304
|
align-items: center;
|
|
6864
7305
|
gap: 4px;
|
|
7306
|
+
flex-shrink: 0;
|
|
6865
7307
|
}
|
|
6866
7308
|
|
|
6867
7309
|
.header-action {
|
|
@@ -7035,7 +7477,7 @@ KRChatbot.styles = i$6 `
|
|
|
7035
7477
|
align-items: center;
|
|
7036
7478
|
justify-content: center;
|
|
7037
7479
|
color: var(--kr-chatbot-text-secondary);
|
|
7038
|
-
gap:
|
|
7480
|
+
gap: 16px;
|
|
7039
7481
|
}
|
|
7040
7482
|
|
|
7041
7483
|
.empty-text {
|
|
@@ -7043,6 +7485,35 @@ KRChatbot.styles = i$6 `
|
|
|
7043
7485
|
color: rgb(0 0 0 / 80%);
|
|
7044
7486
|
}
|
|
7045
7487
|
|
|
7488
|
+
/* Context-aware action chips under the empty-state prompt. A row of pills the user can click to
|
|
7489
|
+
prefill a skill — capped small server-side so this reads as a few suggestions, not a menu. */
|
|
7490
|
+
.empty-suggestions {
|
|
7491
|
+
display: flex;
|
|
7492
|
+
flex-wrap: wrap;
|
|
7493
|
+
justify-content: center;
|
|
7494
|
+
gap: 10px;
|
|
7495
|
+
max-width: 420px;
|
|
7496
|
+
margin-top: 4px;
|
|
7497
|
+
}
|
|
7498
|
+
|
|
7499
|
+
.empty-suggestions__chip {
|
|
7500
|
+
padding: 8px 12px;
|
|
7501
|
+
background: rgb(0 0 0 / 6%);
|
|
7502
|
+
border: none;
|
|
7503
|
+
border-radius: 16px;
|
|
7504
|
+
color: #000000;
|
|
7505
|
+
font: inherit;
|
|
7506
|
+
font-size: 13px;
|
|
7507
|
+
line-height: 1.2;
|
|
7508
|
+
cursor: pointer;
|
|
7509
|
+
white-space: nowrap;
|
|
7510
|
+
}
|
|
7511
|
+
|
|
7512
|
+
.empty-suggestions__chip:hover {
|
|
7513
|
+
background: rgb(0 0 0 / 10%);
|
|
7514
|
+
color: #000000;
|
|
7515
|
+
}
|
|
7516
|
+
|
|
7046
7517
|
.message {
|
|
7047
7518
|
position: relative;
|
|
7048
7519
|
display: flex;
|
|
@@ -7687,6 +8158,13 @@ KRChatbot.styles = i$6 `
|
|
|
7687
8158
|
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
|
|
7688
8159
|
}
|
|
7689
8160
|
|
|
8161
|
+
/* Full-panel (floating) header: back button then title, left-aligned. */
|
|
8162
|
+
.drawer--full .drawer__header {
|
|
8163
|
+
justify-content: flex-start;
|
|
8164
|
+
gap: 8px;
|
|
8165
|
+
padding: 0 12px;
|
|
8166
|
+
}
|
|
8167
|
+
|
|
7690
8168
|
.drawer__title {
|
|
7691
8169
|
font-size: 14px;
|
|
7692
8170
|
font-weight: 600;
|
|
@@ -7700,6 +8178,78 @@ KRChatbot.styles = i$6 `
|
|
|
7700
8178
|
padding: 4px 0;
|
|
7701
8179
|
}
|
|
7702
8180
|
|
|
8181
|
+
/* Floating variant: the drawer fills the whole panel over the transcript (a
|
|
8182
|
+
full-panel view with a back button), rather than sliding in beside it. */
|
|
8183
|
+
.drawer--full {
|
|
8184
|
+
left: 0;
|
|
8185
|
+
width: 100%;
|
|
8186
|
+
max-width: 100%;
|
|
8187
|
+
z-index: 6;
|
|
8188
|
+
}
|
|
8189
|
+
|
|
8190
|
+
.drawer--full.drawer--open {
|
|
8191
|
+
box-shadow: none;
|
|
8192
|
+
}
|
|
8193
|
+
|
|
8194
|
+
/* History (previous conversations) view. */
|
|
8195
|
+
.history {
|
|
8196
|
+
display: flex;
|
|
8197
|
+
flex-direction: column;
|
|
8198
|
+
}
|
|
8199
|
+
|
|
8200
|
+
/* "New conversation" action in the Conversations header — pushed to the right. */
|
|
8201
|
+
.history__new {
|
|
8202
|
+
margin-left: auto;
|
|
8203
|
+
}
|
|
8204
|
+
|
|
8205
|
+
.history__empty {
|
|
8206
|
+
padding: 24px 20px;
|
|
8207
|
+
text-align: center;
|
|
8208
|
+
font-size: 13px;
|
|
8209
|
+
color: rgb(0 0 0 / 50%);
|
|
8210
|
+
}
|
|
8211
|
+
|
|
8212
|
+
.history__list {
|
|
8213
|
+
display: flex;
|
|
8214
|
+
flex-direction: column;
|
|
8215
|
+
padding: 4px 0;
|
|
8216
|
+
}
|
|
8217
|
+
|
|
8218
|
+
.history__item {
|
|
8219
|
+
display: flex;
|
|
8220
|
+
flex-direction: column;
|
|
8221
|
+
align-items: flex-start;
|
|
8222
|
+
gap: 5px;
|
|
8223
|
+
padding: 10px 20px;
|
|
8224
|
+
background: transparent;
|
|
8225
|
+
border: none;
|
|
8226
|
+
text-align: left;
|
|
8227
|
+
cursor: pointer;
|
|
8228
|
+
transition: background 0.15s;
|
|
8229
|
+
}
|
|
8230
|
+
|
|
8231
|
+
.history__item:hover {
|
|
8232
|
+
background: rgba(0, 0, 0, 0.04);
|
|
8233
|
+
}
|
|
8234
|
+
|
|
8235
|
+
.history__item--active {
|
|
8236
|
+
background: rgba(0, 0, 0, 0.06);
|
|
8237
|
+
}
|
|
8238
|
+
|
|
8239
|
+
.history__item-title {
|
|
8240
|
+
font-size: 14px;
|
|
8241
|
+
color: #000000;
|
|
8242
|
+
white-space: nowrap;
|
|
8243
|
+
overflow: hidden;
|
|
8244
|
+
text-overflow: ellipsis;
|
|
8245
|
+
max-width: 100%;
|
|
8246
|
+
}
|
|
8247
|
+
|
|
8248
|
+
.history__item-date {
|
|
8249
|
+
font-size: 12px;
|
|
8250
|
+
color: rgb(0 0 0 / 60%);
|
|
8251
|
+
}
|
|
8252
|
+
|
|
7703
8253
|
.debug-section {
|
|
7704
8254
|
padding: 14px 20px;
|
|
7705
8255
|
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
|
@@ -8634,6 +9184,9 @@ __decorate$4([
|
|
|
8634
9184
|
__decorate$4([
|
|
8635
9185
|
r()
|
|
8636
9186
|
], KRChatbot.prototype, "_error", void 0);
|
|
9187
|
+
__decorate$4([
|
|
9188
|
+
r()
|
|
9189
|
+
], KRChatbot.prototype, "_conversationTitle", void 0);
|
|
8637
9190
|
__decorate$4([
|
|
8638
9191
|
r()
|
|
8639
9192
|
], KRChatbot.prototype, "_contextWarning", void 0);
|
|
@@ -8667,6 +9220,12 @@ __decorate$4([
|
|
|
8667
9220
|
__decorate$4([
|
|
8668
9221
|
r()
|
|
8669
9222
|
], KRChatbot.prototype, "_drawerView", void 0);
|
|
9223
|
+
__decorate$4([
|
|
9224
|
+
r()
|
|
9225
|
+
], KRChatbot.prototype, "_conversations", void 0);
|
|
9226
|
+
__decorate$4([
|
|
9227
|
+
r()
|
|
9228
|
+
], KRChatbot.prototype, "_conversationsLoading", void 0);
|
|
8670
9229
|
__decorate$4([
|
|
8671
9230
|
r()
|
|
8672
9231
|
], KRChatbot.prototype, "_toolDetail", void 0);
|
|
@@ -8706,6 +9265,9 @@ __decorate$4([
|
|
|
8706
9265
|
__decorate$4([
|
|
8707
9266
|
r()
|
|
8708
9267
|
], KRChatbot.prototype, "_invocableSkills", void 0);
|
|
9268
|
+
__decorate$4([
|
|
9269
|
+
r()
|
|
9270
|
+
], KRChatbot.prototype, "_suggestedActions", void 0);
|
|
8709
9271
|
__decorate$4([
|
|
8710
9272
|
r()
|
|
8711
9273
|
], KRChatbot.prototype, "_aiFrameworkConfig", void 0);
|