diff --git a/src/lib/helpers/enums.js b/src/lib/helpers/enums.js index 76087c4f..d3b1ef6a 100644 --- a/src/lib/helpers/enums.js +++ b/src/lib/helpers/enums.js @@ -83,6 +83,12 @@ const routingMode = { }; export const RoutingMode = Object.freeze(routingMode); +const functionVisMode = { + Manual: "manual", + Auto: "auto" +}; +export const FunctionVisMode = Object.freeze(functionVisMode); + const agentTaskStatus = { Scheduled: 'scheduled', New: 'new', @@ -117,6 +123,24 @@ const knowledgePayloadName = { }; export const KnowledgePayloadName = Object.freeze(knowledgePayloadName); +const vectorPayloadDataType = { + String: Object.freeze({ id: 1, name: 'String' }), + Boolean: Object.freeze({ id: 2, name: 'Boolean' }), + Integer: Object.freeze({ id: 3, name: 'Integer' }), + Double: Object.freeze({ id: 4, name: 'Double' }), + Datetime: Object.freeze({ id: 5, name: 'Datetime' }), +}; +export const VectorPayloadDataType = Object.freeze(vectorPayloadDataType); + +const vectorIndexSchemaType = { + Text: "text", + Integer: "integer", + Float: "float", + Boolean: "bool", + Datetime: "datetime" +}; +export const VectorIndexSchemaType = Object.freeze(vectorIndexSchemaType); + const vectorDataSource = { Api: 'api', User: 'user', diff --git a/src/lib/helpers/types/agentTypes.js b/src/lib/helpers/types/agentTypes.js index 846bf31c..056b75ed 100644 --- a/src/lib/helpers/types/agentTypes.js +++ b/src/lib/helpers/types/agentTypes.js @@ -46,6 +46,7 @@ * @property {string} description - Agent description. * @property {string} type - Agent type * @property {string?} mode - Agent routing mode + * @property {string?} function_visibility_mode - Agent function visibility mode * @property {string} instruction - System prompt * @property {ChannelInstruction[]} channel_instructions - Channel instructions * @property {boolean} disabled diff --git a/src/lib/helpers/types/commonTypes.js b/src/lib/helpers/types/commonTypes.js index 657f45ed..038079b5 100644 --- a/src/lib/helpers/types/commonTypes.js +++ b/src/lib/helpers/types/commonTypes.js @@ -55,6 +55,7 @@ * @typedef {Object} LlmModelSetting * @property {string} name * @property {string} type + * @property {any} reasoning */ @@ -70,4 +71,10 @@ * @property {string?} [displayName] */ +/** + * @typedef {Object} SuccessFailResponse + * @property {any[]} success + * @property {any[]} fail + */ + export default {}; \ No newline at end of file diff --git a/src/lib/helpers/types/knowledgeTypes.js b/src/lib/helpers/types/knowledgeTypes.js index 5fddff54..5ec0ccd7 100644 --- a/src/lib/helpers/types/knowledgeTypes.js +++ b/src/lib/helpers/types/knowledgeTypes.js @@ -30,8 +30,41 @@ /** * @typedef {Object} VectorFilterGroup - * @property {string} [filter_operator] - The filter operator. - * @property {{ key: string, value: string }[]} [filters] - Search filters. + * @property {string} [logical_operator] - The logical operator. + * @property {VectorFilterSubGroup[]} [filters] - Search filters. + */ + +/** + * @typedef {Object} VectorFilterSubGroup + * @property {string} [logical_operator] - The logical operator. + * @property {VectorFilterOperand[]} [operands] - Search operands. + */ + +/** + * @typedef {Object} VectorFilterOperand + * @property {VectorFilterMatch?} [match] - The match filter. + * @property {VectorFilterRange?} [range] -The range filter. + */ + +/** + * @typedef {Object} VectorFilterMatch + * @property {string} key - The field name. + * @property {string} value - The field value. + * @property {string} operator - The operator. + * @property {string} data_type -The field data type. + */ + +/** + * @typedef {Object} VectorFilterRange + * @property {string} key - The field name. + * @property {string} data_type -The field data type. + * @property {VectorFilterRangeCondition[]} conditions -The conditions. + */ + +/** + * @typedef {Object} VectorFilterRangeCondition + * @property {string} value - The field value. + * @property {string} operator -The operator. */ /** @@ -100,4 +133,25 @@ * @property {number} dimension */ +/** + * @typedef {Object} VectorCollectionDetails + * @property {string} status + * @property {number} vectors_count + * @property {number} points_count + * @property {PayloadSchemaDetail[]} payload_schema + */ + +/** + * @typedef {Object} PayloadSchemaDetail + * @property {string} field_name + * @property {string} field_data_type + * @property {number} data_count + */ + +/** + * @typedef {Object} VectorCollectionIndexOptions + * @property {string} field_name + * @property {string} field_schema_type + */ + export default {}; \ No newline at end of file diff --git a/src/lib/scss/custom/pages/_knowledgebase.scss b/src/lib/scss/custom/pages/_knowledgebase.scss index 4452f9c2..e5b91c64 100644 --- a/src/lib/scss/custom/pages/_knowledgebase.scss +++ b/src/lib/scss/custom/pages/_knowledgebase.scss @@ -67,10 +67,13 @@ display: flex; flex-wrap: wrap; justify-content: space-between; + gap: 10px; .search-input { display: flex; gap: 5px; + align-items: center; + flex-wrap: wrap; } .confidence-box { @@ -112,6 +115,141 @@ box-shadow: none !important; } } + + // Responsive design for tablets and mobile + @media (max-width: 768px) { + flex-direction: column; + gap: 15px; + + .search-input { + &:first-child { + // Confidence input section - centered + justify-content: center; + align-items: center; + gap: 10px; + + .confidence-box { + width: 60px; + flex-shrink: 0; + } + } + + &:nth-child(2) { + // Toggle section - keep horizontal + justify-content: center; + align-items: center; + gap: 15px; + flex-wrap: wrap; + + .input-text { + font-size: 13px; + } + + .search-toggle { + width: 50px; + height: 30px; + display: flex; + align-items: center; + justify-content: center; + + .form-switch { + margin: 0; + padding: 0; + display: flex; + align-items: center; + } + + input { + width: 40px !important; + height: 20px !important; + } + } + } + } + + // Center the search button + .line-align-center { + text-align: center; + } + } + + // Mobile and smaller screens - stack vertically + @media (max-width: 480px) { + .search-input { + &:first-child { + flex-direction: column; + + .input-text { + text-align: center; + } + + > div:last-child { + // Confidence input and buttons container + display: flex; + align-items: center; + justify-content: center; + gap: 5px; + width: 100%; + + .confidence-box { + width: 80px; + } + } + } + + &:nth-child(2) { + // Keep toggle section horizontal on mobile + justify-content: center; + align-items: center; + gap: 12px; + flex-wrap: wrap; + + .input-text { + font-size: 12px; + padding: 0.3rem 0px; + white-space: nowrap; + } + + .search-toggle { + width: 55px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + + .form-switch { + margin: 0; + padding: 0; + display: flex; + align-items: center; + } + + input { + width: 45px !important; + height: 22px !important; + margin: 0 !important; + } + } + } + } + } + + // Very small screens - further optimizations + @media (max-width: 360px) { + .search-input { + &:first-child { + > div:last-child { + .confidence-box { + width: 70px; + } + } + } + } + + .input-text { + font-size: 11px; + } + } } .graph-searh-result-container { @@ -126,15 +264,19 @@ } .knowledge-table-header { - justify-content: space-between; - .knowledge-header-text { margin-bottom: 0px !important; padding: 0.47rem 0.75rem; } + .collection-action-container { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + gap: 10px; + } + .collection-dropdown-container { - width: 20%; display: flex; gap: 5px; justify-content: flex-end; @@ -154,6 +296,18 @@ box-shadow: none !important; } } + + @media (max-width: 600px) { + justify-content: center !important; + + .collection-action-container { + justify-content: center !important; + } + + .collection-dropdown-container { + justify-content: center !important; + } + } } .knowledge-table { @@ -258,17 +412,14 @@ display: flex; flex-direction: column; gap: 10px; - max-height: 280px; + min-height: 100px; + max-height: 300px; overflow-y: auto; scrollbar-width: none; .payload-item { display: flex; gap: 10px; - - .payload-item-content { - flex: 0.5; - } } } } @@ -374,11 +525,17 @@ justify-content: flex-start; gap: 10px; font-size: 18px; - + input { outline: none !important; box-shadow: none !important; } + + @media (max-width: 480px) { + font-size: 16px; + gap: 8px; + flex-wrap: wrap; + } } .knowledge-adv-search-items { @@ -386,38 +543,105 @@ display: flex; flex-direction: column; gap: 10px; + min-height: 200px; max-height: 300px; overflow-y: auto; scrollbar-width: none; - + .knowledge-adv-search-item { display: flex; gap: 10px; - + .search-item-cb { flex: 0 0 20px; - + .form-check { font-size: 15px; margin-bottom: 0.125rem; } - + input[type="checkbox"] { outline: none !important; box-shadow: none !important; } } - + .search-item-name { font-size: 15px; flex: 0 0 100px; } - + .search-item-content { flex: 0.3; min-width: 150px; max-width: 350px; } + + // Responsive behavior for narrow screens + @media (max-width: 768px) { + flex-direction: column; + gap: 8px; + padding: 10px; + border: 1px solid #e0e0e0; + border-radius: 5px; + margin-bottom: 5px; + + .search-item-cb { + flex: none; + align-self: flex-start; + } + + .search-item-content { + flex: none; + min-width: unset; + max-width: unset; + width: 100%; + position: relative; + + // Show field labels on mobile + &[data-label]:before { + content: attr(data-label) ":"; + display: block; + font-weight: bold; + font-size: 14px; + margin-bottom: 4px; + color: #666; + } + } + + // Hide header row on mobile since items are stacked + &:first-child { + display: none; + } + } + + @media (max-width: 480px) { + padding: 8px; + gap: 6px; + } + + // Special styling for the add button row + &.add-item-row { + @media (max-width: 768px) { + flex-direction: row; + justify-content: center; + border: none; + + .search-item-cb, + .search-item-content:not(:last-child) { + display: none; + } + + .search-item-content:last-child { + flex: none; + width: auto; + + .d-flex { + justify-content: center !important; + } + } + } + } } } @@ -427,14 +651,24 @@ .operator-item { display: flex; - @media (max-width: 420px) { + @media (max-width: 768px) { flex-direction: column; gap: 10px !important; + align-items: flex-start; + } + + @media (max-width: 420px) { text-align: center; + align-items: center; } .operator-title { width: 120px; + + @media (max-width: 768px) { + width: auto; + margin-bottom: 5px; + } } } } @@ -459,4 +693,100 @@ justify-content: space-between; } } +} + +.vector-index-container { + .index-layout-container { + display: grid; + gap: 1rem; + grid-template-columns: 1fr auto 1fr; + grid-template-areas: "existing arrows delete"; + align-items: start; + } + + .index-block:first-child { + grid-area: existing; + } + + .index-block:last-child { + grid-area: delete; + } + + .arrow-container { + grid-area: arrows; + display: flex; + justify-content: center; + align-items: center; + height: 500px; /* Match the fixed height of the cards */ + } + + .arrow-buttons { + display: flex; + flex-direction: column; + gap: 0.75rem; + } + + .index-block-card { + height: 500px; + display: flex; + flex-direction: column; + + .card-body-scrollable { + flex: 1; + overflow-y: auto; + max-height: none; + padding: 5px; + } + + .field-row { + display: flex; + gap: 1rem; + } + + .field-item { + flex: 1; + } + } + + .arrow-horizontal { + display: inline; + } + + .arrow-vertical { + display: none; + } + + @media (max-width: 991.98px) { + .index-layout-container { + grid-template-columns: 1fr; + grid-template-areas: + "existing" + "arrows" + "delete"; + } + + .arrow-container { + height: auto; + min-height: 60px; + padding: 1rem 0; + } + + .arrow-buttons { + flex-direction: row; + justify-content: center; + } + + .arrow-horizontal { + display: none; + } + + .arrow-vertical { + display: inline; + } + + .field-row { + flex-direction: column; + gap: 0; + } + } } \ No newline at end of file diff --git a/src/lib/services/api-endpoints.js b/src/lib/services/api-endpoints.js index f2c03b43..12ab5ec3 100644 --- a/src/lib/services/api-endpoints.js +++ b/src/lib/services/api-endpoints.js @@ -88,6 +88,7 @@ export const endpoints = { // knowledge base vectorCollectionExistUrl: `${host}/knowledge/vector/{collection}/exist`, vectorCollectionsUrl: `${host}/knowledge/vector/collections`, + vectorCollectionDetailsUrl: `${host}/knowledge/vector/{collection}/details`, vectorKnowledgePageListUrl: `${host}/knowledge/vector/{collection}/page`, vectorKnowledgeSearchUrl: `${host}/knowledge/vector/{collection}/search`, vectorKnowledgeCreateUrl: `${host}/knowledge/vector/{collection}/create`, @@ -97,6 +98,8 @@ export const endpoints = { vectorKnowledgeUploadUrl: `${host}/knowledge/vector/{collection}/upload`, vectorCollectionCreateUrl: `${host}/knowledge/vector/create-collection`, vectorCollectionDeleteUrl: `${host}/knowledge/vector/{collection}/delete-collection`, + vectorIndexesCreateUrl: `${host}/knowledge/vector/{collection}/payload/indexes`, + vectorIndexesDeleteUrl: `${host}/knowledge/vector/{collection}/payload/indexes`, graphKnowledgeSearchUrl: `${host}/knowledge/graph/search`, diff --git a/src/lib/services/knowledge-base-service.js b/src/lib/services/knowledge-base-service.js index 165cc7fe..919d9214 100644 --- a/src/lib/services/knowledge-base-service.js +++ b/src/lib/services/knowledge-base-service.js @@ -61,18 +61,16 @@ export async function getVectorKnowledgePageList(collection, filter) { /** * @param {string} collection * @param {string} text - * @param {string} dataSource * @param {any} payload * @returns {Promise} */ -export async function createVectorKnowledgeData(collection, text, dataSource, payload = null) { +export async function createVectorKnowledgeData(collection, text, payload = null) { const url = replaceUrl(endpoints.vectorKnowledgeCreateUrl, { collection: collection }); const request = { text: text, - data_source: dataSource, payload: { ...payload, } @@ -86,11 +84,10 @@ export async function createVectorKnowledgeData(collection, text, dataSource, pa * @param {string} id * @param {string} collection * @param {string} text - * @param {string} dataSource * @param {any} payload * @returns {Promise} */ -export async function updateVectorKnowledgeData(id, collection, text, dataSource, payload = null) { +export async function updateVectorKnowledgeData(id, collection, text, payload = null) { const url = replaceUrl(endpoints.vectorKnowledgeUpdateUrl, { collection: collection }); @@ -98,7 +95,6 @@ export async function updateVectorKnowledgeData(id, collection, text, dataSource const request = { id: id, text: text, - data_source: dataSource, payload: { ...payload } @@ -231,4 +227,51 @@ export async function searchGraphKnowledge(text, method = "local") { const url = endpoints.graphKnowledgeSearchUrl; const response = await axios.post(url, { query: text, method: method }); return response.data; +} + +/** + * @param {string} collection + * @returns {Promise} + */ +export async function getVectorCollectionDetails(collection) { + const url = replaceUrl(endpoints.vectorCollectionDetailsUrl, { + collection: collection + }); + + const response = await axios.get(url); + return response.data; +} + +/** + * @param {string} collection + * @param {import('$knowledgeTypes').VectorCollectionIndexOptions[]} options + * @returns {Promise} + */ +export async function createVectorIndexes(collection, options) { + const url = replaceUrl(endpoints.vectorIndexesCreateUrl, { + collection: collection + }); + + const response = await axios.post(url, { + options: options || [] + }); + return response.data; +} + +/** + * @param {string} collection + * @param {import('$knowledgeTypes').VectorCollectionIndexOptions[]} options + * @returns {Promise} + */ +export async function deleteVectorIndexes(collection, options) { + const url = replaceUrl(endpoints.vectorIndexesDeleteUrl, { + collection: collection + }); + + const response = await axios.delete(url, { + data: { + options: options || [] + } + }); + return response.data; } \ No newline at end of file diff --git a/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte b/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte index dfd7cd18..82d53688 100644 --- a/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte +++ b/src/routes/chat/[agentId]/[conversationId]/chat-box.svelte @@ -535,7 +535,7 @@ ) { dialogs.push({ ...message, - is_chat_message: true + is_chat_message: false }); } refresh(); diff --git a/src/routes/chat/[agentId]/[conversationId]/rich-content/rc-js-interpreter.svelte b/src/routes/chat/[agentId]/[conversationId]/rich-content/rc-js-interpreter.svelte index 56057155..a71094f0 100644 --- a/src/routes/chat/[agentId]/[conversationId]/rich-content/rc-js-interpreter.svelte +++ b/src/routes/chat/[agentId]/[conversationId]/rich-content/rc-js-interpreter.svelte @@ -100,6 +100,6 @@
{message.text}
{/if}
-
+
\ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-components/agent-llm-config.svelte b/src/routes/page/agent/[agentId]/agent-components/agent-llm-config.svelte index 97393972..439a683e 100644 --- a/src/routes/page/agent/[agentId]/agent-components/agent-llm-config.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/agent-llm-config.svelte @@ -12,9 +12,11 @@ export let handleAgentChange = () => {}; export const fetchLlmConfig = () => { + const reasoningEffort = models.find(x => x.name === config.model)?.reasoning != null ? config.reasoning_effort_level : null; return { ...config, - max_output_tokens: Number(config.max_output_tokens) > 0 ? Number(config.max_output_tokens) : null + max_output_tokens: Number(config.max_output_tokens) > 0 ? Number(config.max_output_tokens) : null, + reasoning_effort_level: reasoningEffort }; } @@ -37,6 +39,8 @@ /** @type {import('$commonTypes').LlmModelSetting[]} */ let models = []; + $: isReasoningModel = models.find(x => x.name === config.model)?.reasoning != null; + onMount(async () =>{ await init(); }); @@ -63,6 +67,7 @@ if (!!!provider) { models = []; config.model = null; + config.reasoning_effort_level = null; handleAgentChange(); return; } @@ -181,6 +186,7 @@ + {#if isReasoningModel}
+ {/if} \ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-components/agent-overview.svelte b/src/routes/page/agent/[agentId]/agent-components/agent-overview.svelte index b5c77817..85df2a2c 100644 --- a/src/routes/page/agent/[agentId]/agent-components/agent-overview.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/agent-overview.svelte @@ -3,8 +3,9 @@ import { Button, Card, CardBody, CardHeader, Input, Table } from '@sveltestrap/sveltestrap'; import { _ } from 'svelte-i18n'; import InPlaceEdit from '$lib/common/InPlaceEdit.svelte'; + import Select from '$lib/common/Select.svelte'; import { utcToLocal } from '$lib/helpers/datetime'; - import { RoutingMode, AgentType } from '$lib/helpers/enums'; + import { RoutingMode, AgentType, FunctionVisMode } from '$lib/helpers/enums'; import { AgentExtensions } from '$lib/helpers/utils/agent'; const limit = 10; @@ -27,6 +28,9 @@ { id: v, name: v } )); + const functionVisibilityModeOptions = Object.entries(FunctionVisMode).map(([k, v]) => ( + { label: v, value: v } + )); onMount(() => { init(); @@ -73,12 +77,22 @@ /** * @param {any} e */ - function changeMode(e) { + function changeRoutingMode(e) { const value = e.target.value || null; agent.mode = value; handleAgentChange(); } + /** + * @param {any} e + */ + function changeFunctionVisibilityMode(e) { + // @ts-ignore + const values = e?.detail?.selecteds?.map(x => x.value) || []; + agent.function_visibility_mode = values[0] || null; + handleAgentChange(); + } + function chatWithAgent() { if (!!!agent?.id) return; @@ -145,7 +159,7 @@
changeMode(e)} + on:change={e => changeRoutingMode(e)} > {#each [...routingModeOptions] as option}
+ + {/each} + {/if} + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/routes/page/knowledge-base/common/search/advanced-search.svelte b/src/routes/page/knowledge-base/common/search/advanced-search.svelte index c2963bc5..2b4526a0 100644 --- a/src/routes/page/knowledge-base/common/search/advanced-search.svelte +++ b/src/routes/page/knowledge-base/common/search/advanced-search.svelte @@ -3,11 +3,13 @@ import { fly } from 'svelte/transition'; import { Input, Tooltip, Button } from '@sveltestrap/sveltestrap'; import { v4 as uuidv4 } from 'uuid'; + import Select from '$lib/common/Select.svelte'; + import { VectorPayloadDataType } from '$lib/helpers/enums'; /** @type {boolean} */ export let showAdvSearch = false; - /** @type {{ uuid: string, key: string, value: string, checked: boolean }[]} */ + /** @type {{ uuid: string, key: string, value: string, data_type: string, checked: boolean }[]} */ export let items = []; /** @type {string} */ @@ -58,6 +60,11 @@ } ]; + const dataTypeOptions = Object.entries(VectorPayloadDataType).map(([k, v]) => ({ + label: v.name.toLowerCase(), + value: v.name + })); + /** @type {HTMLElement} */ let scrollContainer; @@ -74,7 +81,7 @@ } function reset() { - items = [{ uuid: uuidv4(), key: '', value: '', checked: true }]; + items = [{ uuid: uuidv4(), key: '', value: '', data_type: '', checked: true }]; } @@ -95,11 +102,10 @@ /** @param {any} e */ async function addItem(e) { e.preventDefault(); - e.stopPropagation(); items = [ ...items, - { uuid: uuidv4(), key: '', value: '', checked: true } + { uuid: uuidv4(), key: '', value: '', data_type: '', checked: true } ]; // Wait for DOM to update, then scroll to bottom @@ -135,7 +141,12 @@ found.key = e.target.value; } else if (key === 'value') { found.value = e.target.value; + } else if (key === 'data_type') { + // @ts-ignore + const selectedValues = e?.detail?.selecteds?.map(x => x.value) || []; + found.data_type = selectedValues[0] || null; } + items = items.map((x, index) => { return index === idx ? { ...found } : x; }); @@ -191,6 +202,10 @@
{'Value'}
+
+
{'Data type'}
+
+
{#each items as item, idx (item.uuid)}
@@ -202,7 +217,7 @@ on:change={e => toggleItem(e, idx)} />
-
+
changeItem(e, idx, 'key')} />
-
+
changeItem(e, idx, 'value')} />
+
+ changePayloadItem(e, idx, 'key')} />
-
+
changePayloadItem(e, idx, 'value')} + value={payload.value.data_value} + on:input={e => changePayloadItem(e, idx, 'data_value')} + /> +
+
+ changeCollection(e)} - /> -
+ +
+ {#if selectedCollection}
-
-
-
-