diff --git a/package-lock.json b/package-lock.json
index e008ae2f..d00fdd51 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
"@fullcalendar/common": "^5.11.5",
"@microsoft/signalr": "^8.0.0",
"@pgrabovets/json-view": "^2.7.5",
+ "@popperjs/core": "^2.11.8",
"@sveltejs/adapter-static": "^3.0.0",
"@sveltestrap/sveltestrap": "^6.2.3",
"@twilio/voice-sdk": "^2.9.0",
diff --git a/package.json b/package.json
index 12daac75..bef3fca2 100644
--- a/package.json
+++ b/package.json
@@ -41,6 +41,7 @@
"@fullcalendar/common": "^5.11.5",
"@microsoft/signalr": "^8.0.0",
"@pgrabovets/json-view": "^2.7.5",
+ "@popperjs/core": "^2.11.8",
"@sveltejs/adapter-static": "^3.0.0",
"@sveltestrap/sveltestrap": "^6.2.3",
"@twilio/voice-sdk": "^2.9.0",
diff --git a/src/lib/common/markdown/Markdown.svelte b/src/lib/common/markdown/Markdown.svelte
index 8c95e9ea..70b16578 100644
--- a/src/lib/common/markdown/Markdown.svelte
+++ b/src/lib/common/markdown/Markdown.svelte
@@ -1,6 +1,10 @@
diff --git a/src/lib/common/tooltip/BotsharpTooltip.svelte b/src/lib/common/tooltip/BotsharpTooltip.svelte
new file mode 100644
index 00000000..c1d00bd2
--- /dev/null
+++ b/src/lib/common/tooltip/BotsharpTooltip.svelte
@@ -0,0 +1,232 @@
+
+
+{#if isOpen}
+
+
+
+{/if}
\ No newline at end of file
diff --git a/src/lib/helpers/types/agentTypes.js b/src/lib/helpers/types/agentTypes.js
index 21253f9b..5cf7c6b6 100644
--- a/src/lib/helpers/types/agentTypes.js
+++ b/src/lib/helpers/types/agentTypes.js
@@ -145,6 +145,7 @@
* @property {string?} [template_name]
* @property {string?} [template_display_name]
* @property {string?} [visibility_expression]
+ * @property {string?} [description]
*/
/**
diff --git a/src/lib/helpers/utils/common.js b/src/lib/helpers/utils/common.js
index daa9d96d..6ac0218d 100644
--- a/src/lib/helpers/utils/common.js
+++ b/src/lib/helpers/utils/common.js
@@ -76,4 +76,9 @@ export function truncateByPrefix(str, prefix) {
*/
export function removeDuplicates(arr, key) {
return [...new Map(arr.map(item => [item[key], item])).values()];
-}
\ No newline at end of file
+}
+
+/**
+ * @param {(string | null)[]} args
+ */
+export const classnames = (...args) => args.filter(Boolean).join(' ');
\ No newline at end of file
diff --git a/src/lib/scss/custom/pages/_agent.scss b/src/lib/scss/custom/pages/_agent.scss
index 2cddf4b5..15ef802d 100644
--- a/src/lib/scss/custom/pages/_agent.scss
+++ b/src/lib/scss/custom/pages/_agent.scss
@@ -249,4 +249,21 @@
gap: 5px;
flex-wrap: wrap;
margin: 5px 0px;
+}
+
+.agent-utility-desc {
+ .tooltip-inner {
+ text-align: start;
+ max-width: fit-content;
+ padding: 20px;
+ }
+
+ .markdown-div {
+ max-height: 500px;
+ font-size: 15px;
+ }
+
+ &.show {
+ opacity: 1 !important;
+ }
}
\ No newline at end of file
diff --git a/src/lib/services/signalr-service.js b/src/lib/services/signalr-service.js
index 83bc2ad8..d5f9c9ae 100644
--- a/src/lib/services/signalr-service.js
+++ b/src/lib/services/signalr-service.js
@@ -48,7 +48,7 @@ export const signalr = {
// create a new connection object with the hub URL and some options
let user = getUserStore();
connection = new HubConnectionBuilder()
- .withUrl(endpoints.chatHubUrl + `?conversationId=${conversationId}&access_token=${user.token}`) // the hub URL, change it according to your server
+ .withUrl(endpoints.chatHubUrl + `?conversation-id=${conversationId}&access_token=${user.token}`) // the hub URL, change it according to your server
.withAutomaticReconnect() // enable automatic reconnection
.configureLogging(LogLevel.Information) // configure the logging level
.build();
diff --git a/src/routes/chat/[agentId]/[conversationId]/persist-log/persist-log.svelte b/src/routes/chat/[agentId]/[conversationId]/persist-log/persist-log.svelte
index 8d44b09e..85537e98 100644
--- a/src/routes/chat/[agentId]/[conversationId]/persist-log/persist-log.svelte
+++ b/src/routes/chat/[agentId]/[conversationId]/persist-log/persist-log.svelte
@@ -48,9 +48,9 @@
let selectedTab = contentLogTab;
/** @type {import('$conversationTypes').ConversationLogFilter} */
- let contentLogFilter = { size: 100, startTime: utcNow };
+ let contentLogFilter = { size: 80, startTime: utcNow };
/** @type {import('$conversationTypes').ConversationLogFilter} */
- let stateLogFilter = { size: 100, startTime: utcNow };
+ let stateLogFilter = { size: 80, startTime: utcNow };
const options = {
scrollbars: {
@@ -59,7 +59,7 @@
autoHideDelay: 100,
dragScroll: true,
clickScroll: false,
- theme: 'os-theme-dark',
+ theme: 'os-theme-light',
pointers: ['mouse', 'touch', 'pen']
}
};
@@ -69,7 +69,7 @@
await getChatStateLogs();
initScrollbars();
- scrollToBottom();
+ scroll();
});
beforeUpdate(() => {});
@@ -84,17 +84,17 @@
function refresh() {
if (autoScroll) {
- scrollToBottom();
+ scroll();
}
-
}
- function scrollToBottom() {
+ /** @param {boolean} goToTop */
+ function scroll(goToTop = false) {
// @ts-ignore
scrollbars.forEach(scrollbar => {
setTimeout(() => {
const { viewport } = scrollbar.elements();
- viewport.scrollTo({ top: viewport.scrollHeight, behavior: 'smooth' });
+ viewport.scrollTo({ top: goToTop ? 0 : viewport.scrollHeight, behavior: 'smooth' });
}, 200);
});
}
@@ -104,18 +104,8 @@
const elem = document.querySelector(item.id);
if (!elem) return;
+ // @ts-ignore
const scrollbar = OverlayScrollbars(elem, options);
- scrollbar.on("scroll", async (e) => {
- const curScrollTop = e.elements().scrollOffsetElement.scrollTop;
- if (curScrollTop <= 3 && curScrollTop > 0) {
- if (item.type === contentLogTab) {
- await getChatContentLogs();
- } else if (item.type === conversationStateLogTab) {
- await getChatStateLogs();
- }
- }
- });
-
scrollbars = [ ...scrollbars, scrollbar];
});
}
@@ -161,7 +151,7 @@
function handleCleanScreen() {
cleanLogs();
- cleanScreen && cleanScreen();
+ cleanScreen?.();
}
/** @param {number} selected */
@@ -171,6 +161,15 @@
}
selectedTab = selected;
}
+
+ async function goToTopLog() {
+ scroll(true);
+ if (selectedTab === contentLogTab) {
+ await getChatContentLogs();
+ } else if (selectedTab === conversationStateLogTab) {
+ await getChatStateLogs();
+ }
+ }
@@ -180,9 +179,34 @@
+
+
+
+
@@ -191,7 +215,7 @@
class="btn btn-sm btn-secondary btn-rounded chat-send waves-effect waves-light"
on:click={() => closeWindow()}
>
-
+
diff --git a/src/routes/page/agent/[agentId]/agent-components/agent-utility.svelte b/src/routes/page/agent/[agentId]/agent-components/agent-utility.svelte
index 69f54f87..e76f2a79 100644
--- a/src/routes/page/agent/[agentId]/agent-components/agent-utility.svelte
+++ b/src/routes/page/agent/[agentId]/agent-components/agent-utility.svelte
@@ -3,10 +3,15 @@
import { Card, CardBody, Input, Button } from '@sveltestrap/sveltestrap';
import { getAgentUtilityOptions } from '$lib/services/agent-service';
import { truncateByPrefix } from '$lib/helpers/utils/common';
+ import Markdown from '$lib/common/markdown/Markdown.svelte';
+ import BotSharpTooltip from '$lib/common/tooltip/BotSharpTooltip.svelte';
const limit = 100;
const prefix = "util-";
+ let windowWidth = 0;
+ let windowHeight = 0;
+
/** @type {import('$agentTypes').AgentModel} */
export let agent;
@@ -38,7 +43,7 @@
let innerUtilities = [];
onMount(async () =>{
- init();
+ resizeWindow();
getAgentUtilityOptions().then(data => {
const list = data || [];
list.forEach(utility => {
@@ -55,6 +60,7 @@
contents.push(content);
utilityMapper[utility.category] = contents;
});
+ init();
});
});
@@ -72,6 +78,11 @@
innerRefresh(list);
}
+ function resizeWindow() {
+ windowWidth = window.innerWidth;
+ windowHeight = window.innerHeight;
+ }
+
/**
* @param {any} e
* @param {number} idx
@@ -164,6 +175,8 @@
if (type === 'function') {
foundItem.function_name = null;
foundItem.function_display_name = null;
+ foundItem.template_name = null;
+ foundItem.template_display_name = null;
} else if (type === 'template') {
foundItem.template_name = null;
foundItem.template_display_name = null;
@@ -199,7 +212,7 @@
name: x.name,
disabled: x.disabled,
visibility_expression: x.visibility_expression,
- items: x.items.map(it => ({ ...it }))
+ items: x.items.map(it => ({ ...it, description: null }))
}
}) || [];
}
@@ -233,6 +246,17 @@
return list;
}
+ /**
+ * @param {string} category
+ * @param {string} name
+ * @param {string} key
+ */
+ function getUtilityItemDescription(category, name, key) {
+ // @ts-ignore
+ const desc = utilityMapper[category]?.find(x => x.name === name)?.items?.find(x => x.function_name === key)?.description;
+ return desc || '';
+ }
+
/** @param {number} uid */
function resetUtility(uid) {
const found = innerUtilities.find((_, index) => index === uid);
@@ -245,6 +269,8 @@
}
+ resizeWindow()}/>
+
@@ -258,7 +284,7 @@
{ toggleMergeUtility(e);}}
+ on:change={e => toggleMergeUtility(e)}
/>
Merge utilities
@@ -275,6 +301,9 @@
{/if}
{#each innerUtilities as utility, uid (uid)}
+ {
+ @const utilityCategoryOptions = getUtilityOptions(Object.keys(utilityMapper), 'Select a category')
+ }
@@ -293,7 +322,7 @@
data-bs-placement="top"
title="Uncheck to disable utility"
>
-
+
@@ -305,7 +334,7 @@
disabled={utility.disabled}
on:change={e => changeUtilityCategory(e, uid)}
>
- {#each getUtilityOptions(Object.keys(utilityMapper), 'Select a category') as option}
+ {#each utilityCategoryOptions as option}
@@ -326,6 +355,9 @@
{#if utility.category}
+ {
+ @const utilityOptions = getUtilityOptions(utilityMapper[utility.category]?.map((/** @type {any} */ x) => x.name), 'Select a utility')
+ }
@@ -336,6 +368,7 @@
changeUtilityName(e, uid)}
>
- {#each getUtilityOptions(utilityMapper[utility.category]?.map((/** @type {any} */ x) => x.name), 'Select a utility') as option}
+ {#each utilityOptions as option}
@@ -384,9 +417,35 @@
{#each utility.items as item, fid (fid)}
{#if item.function_name}
+ {
+ @const description = getUtilityItemDescription(utility.category, utility.name, item.function_name)
+ }
-
- {'Function'}
+
+
{'Function'}
+ {#if description}
+
+
+
+
+
+
+ {/if}