From 1dfae15806ab11226c0b5140b49a730074932a65 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Mon, 26 Jan 2026 16:33:16 -0600 Subject: [PATCH 01/21] add agent rule action --- package-lock.json | 7 +- package.json | 1 + src/lib/helpers/types/agentTypes.js | 8 + src/lib/scss/custom/pages/_agent.scss | 5 + src/lib/services/agent-service.js | 10 + src/lib/services/api-endpoints.js | 1 + .../agent-components/agent-rule.svelte | 181 +++++++++++++++--- 7 files changed, 188 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index aab7e87d..3f242cdc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@codemirror/commands": "^6.10.0", "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/lang-json": "^6.0.2", "@codemirror/lang-python": "^6.2.1", "@codemirror/language": "^6.11.3", "@codemirror/state": "^6.5.2", @@ -133,9 +134,9 @@ } }, "node_modules/@codemirror/lang-json": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz", - "integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz", + "integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==", "dependencies": { "@codemirror/language": "^6.0.0", "@lezer/json": "^1.0.0" diff --git a/package.json b/package.json index 222400ea..ecd73242 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "dependencies": { "@codemirror/commands": "^6.10.0", "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/lang-json": "^6.0.2", "@codemirror/lang-python": "^6.2.1", "@codemirror/language": "^6.11.3", "@codemirror/state": "^6.5.2", diff --git a/src/lib/helpers/types/agentTypes.js b/src/lib/helpers/types/agentTypes.js index be941c2a..fb100d57 100644 --- a/src/lib/helpers/types/agentTypes.js +++ b/src/lib/helpers/types/agentTypes.js @@ -229,11 +229,19 @@ * @property {string} criteria * @property {string?} [displayName] * @property {boolean} disabled + * @property {AgentAction?} [action] * @property {any?} [output_args] * @property {string?} [json_args] * @property {string?} [statement] */ +/** + * @typedef {Object} AgentAction + * @property {string?} [name] + * @property {boolean} disabled + * @property {any} [config] + */ + /** * @typedef {Object} AgentTaskSearchOption diff --git a/src/lib/scss/custom/pages/_agent.scss b/src/lib/scss/custom/pages/_agent.scss index 1117ffab..97e5dd9a 100644 --- a/src/lib/scss/custom/pages/_agent.scss +++ b/src/lib/scss/custom/pages/_agent.scss @@ -323,6 +323,11 @@ } } +.agent-action-config { + min-height: 0px; + max-height: 200px; +} + .code-editor { max-height: 500px; overflow-y: auto; diff --git a/src/lib/services/agent-service.js b/src/lib/services/agent-service.js index caa9e172..a8018f37 100644 --- a/src/lib/services/agent-service.js +++ b/src/lib/services/agent-service.js @@ -115,6 +115,16 @@ export async function getAgentRuleOptions() { return response.data; } +/** + * Get agent rule actions + * @returns {Promise} + */ +export async function getAgentRuleActions() { + const url = endpoints.agentRuleActionsUrl; + const response = await axios.get(url); + return response.data; +} + /** * Get agent labels * @param {number?} [size] diff --git a/src/lib/services/api-endpoints.js b/src/lib/services/api-endpoints.js index 38d18ac1..bd275f08 100644 --- a/src/lib/services/api-endpoints.js +++ b/src/lib/services/api-endpoints.js @@ -40,6 +40,7 @@ export const endpoints = { agentCreateUrl: `${host}/agent`, agentUtilityOptionsUrl: `${host}/agent/utility/options`, agentRuleOptionsUrl: `${host}/rule/triggers`, + agentRuleActionsUrl: `${host}/rule/actions`, agentLabelsUrl: `${host}/agent/labels`, // agent code script: diff --git a/src/routes/page/agent/[agentId]/agent-components/agent-rule.svelte b/src/routes/page/agent/[agentId]/agent-components/agent-rule.svelte index a93d2962..03220cce 100644 --- a/src/routes/page/agent/[agentId]/agent-components/agent-rule.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/agent-rule.svelte @@ -2,10 +2,11 @@ import { onMount } from 'svelte'; import Swal from 'sweetalert2'; import { Card, CardBody, Input, Button } from '@sveltestrap/sveltestrap'; - import { getAgentRuleOptions, generateAgentCodeScript } from '$lib/services/agent-service'; + import { getAgentRuleOptions, generateAgentCodeScript, getAgentRuleActions } from '$lib/services/agent-service'; import Markdown from '$lib/common/markdown/Markdown.svelte'; import BotsharpTooltip from '$lib/common/tooltip/BotsharpTooltip.svelte'; import LoadingToComplete from '$lib/common/spinners/LoadingToComplete.svelte'; + import CodeScript from '$lib/common/shared/CodeScript.svelte'; import { ADMIN_ROLES, AI_PROGRAMMER_AGENT_ID, RULE_TRIGGER_CODE_GENERATE_TEMPLATE } from '$lib/helpers/constants'; import { AgentCodeScriptType } from '$lib/helpers/enums'; import { scrollToBottom } from '$lib/helpers/utils/common'; @@ -42,7 +43,8 @@ return { trigger_name: x.trigger_name, disabled: x.disabled, - criteria: x.criteria?.trim() + criteria: x.criteria?.trim(), + action: !!x.action?.name ? x.action : null }; }); @@ -63,6 +65,9 @@ /** @type {any[]} */ let ruleOptions = []; + /** @type {any[]} */ + let actionOptions = []; + /** @type {import('$agentTypes').AgentRule[]} */ let innerRules = []; @@ -71,24 +76,34 @@ onMount(async () =>{ resizeWindow(); - getAgentRuleOptions().then(data => { - const list = data?.map(x => { - return { - name: x.trigger_name, - displayName: "", - output_args: x.output_args, - json_args: x.json_args, - statement: x.statement - }; - }) || []; - ruleOptions = [{ - name: "", - displayName: "" - }, ...list]; - init(); - }); + Promise.all([ + loadAgentRuleOptions(), + loadAgentRuleActions() + ]); }); + function loadAgentRuleOptions() { + return new Promise((resolve, reject) => { + getAgentRuleOptions().then(data => { + const list = data?.map(x => { + return { + name: x.trigger_name, + displayName: "", + output_args: x.output_args, + json_args: x.json_args, + statement: x.statement + }; + }) || []; + ruleOptions = [{ + name: "", + displayName: "" + }, ...list]; + init(); + resolve('done'); + }); + }); + } + function init() { const list = agent.rules?.map(x => { return { @@ -98,6 +113,18 @@ }) || []; innerRefresh(list); } + + function loadAgentRuleActions() { + return new Promise((resolve, reject) => { + getAgentRuleActions().then(data => { + const list = data?.map(x => ({ name: x })) || []; + actionOptions = [{ + name: "" + }, ...list]; + resolve('done'); + }); + }); + } /** * @param {any} e @@ -155,12 +182,25 @@ const found = innerRules.find((_, index) => index === uid); if (!found) return; - const val = e.target.value; if (field === 'criteria') { - found.criteria = val; + found.criteria = e.target.value; + innerRefresh(innerRules); + handleAgentChange(); + } else if (field === 'action-config') { + if (found.action == null) { + found.action = { + name: '', + disabled: false, + config: {} + }; + } + try { + found.action.config = JSON.parse(e.detail?.text || '{}'); + handleAgentChange(); + } catch { + // ignore invalid JSON while typing + } } - innerRefresh(innerRules); - handleAgentChange(); } /** @@ -258,6 +298,44 @@ return scriptName; } + /** + * @param {any} e + * @param {number} idx + */ + function changeAction(e, idx) { + const found = innerRules.find((_, index) => index === idx); + if (!found) return; + + const val = e.target.value; + found.action = { + ...found.action || {}, + name: val, + disabled: found.action?.disabled || false + }; + innerRefresh(innerRules); + handleAgentChange(); + } + + /** + * @param {any} e + * @param {number} uid + */ + function toggleAction(e, uid) { + const found = innerRules.find((_, index) => index === uid); + if (!found) return; + + if (!found.action) { + found.action = { + name: '', + disabled: false + }; + } + + found.action.disabled = !e.target.checked; + innerRefresh(innerRules); + handleAgentChange(); + } + function resizeWindow() { windowWidth = window.innerWidth; windowHeight = window.innerHeight; @@ -421,6 +499,65 @@ + +
+
+
+
+
+
+ {'Action'} +
+
+ toggleAction(e, uid)} + /> +
+
+
+
+
+ changeAction(e, uid)} + > + {#each [...actionOptions] as option} + + {/each} + +
+
+
+
+ {#if rule.action?.name} +
+
+
+
+ {'Config'} +
+
+
+
+
+ changeContent(e, uid, 'action-config')} + /> +
+
+
+
+ {/if} +
+
{/each} From 238e0e09132db62ec9df24fb0cda1c8145d853f5 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Tue, 27 Jan 2026 13:38:59 -0600 Subject: [PATCH 02/21] refine code script --- src/lib/common/shared/CodeScript.svelte | 9 ++++++++- .../agent/[agentId]/agent-components/agent-rule.svelte | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lib/common/shared/CodeScript.svelte b/src/lib/common/shared/CodeScript.svelte index 4a1c42fe..0414fbd0 100644 --- a/src/lib/common/shared/CodeScript.svelte +++ b/src/lib/common/shared/CodeScript.svelte @@ -20,6 +20,12 @@ /** @type {string} */ export let containerClasses = ''; + /** @type {boolean} */ + export let darkTheme = true; + + /** @type {boolean} */ + export let useBasicSetup = true; + /** @type {import("@codemirror/state").Extension[]} */ const baseExtensions = [ @@ -73,8 +79,9 @@ handleChange(e)} diff --git a/src/routes/page/agent/[agentId]/agent-components/agent-rule.svelte b/src/routes/page/agent/[agentId]/agent-components/agent-rule.svelte index 03220cce..f587bac2 100644 --- a/src/routes/page/agent/[agentId]/agent-components/agent-rule.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/agent-rule.svelte @@ -548,6 +548,7 @@ changeContent(e, uid, 'action-config')} /> From 54080f9c28b91489bbadfa56f23587d6d53f8390 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 28 Jan 2026 14:37:08 -0600 Subject: [PATCH 03/21] refine agent rule structure --- src/lib/common/shared/CodeScript.svelte | 26 +- src/lib/helpers/types/agentTypes.js | 14 +- src/lib/scss/custom/pages/_agent.scss | 2 +- src/lib/services/agent-service.js | 10 + src/lib/services/api-endpoints.js | 1 + .../[conversationId]/chat-box.svelte | 1 + .../agent-components/agent-rule.svelte | 232 ++++++++++++------ 7 files changed, 207 insertions(+), 79 deletions(-) diff --git a/src/lib/common/shared/CodeScript.svelte b/src/lib/common/shared/CodeScript.svelte index 0414fbd0..a95851fc 100644 --- a/src/lib/common/shared/CodeScript.svelte +++ b/src/lib/common/shared/CodeScript.svelte @@ -1,7 +1,7 @@ + +
+
+
+
+ {}} + on:click={() => toggleCollapse()} + /> +
+
+ {`Rule #${ruleIndex + 1}`} +
+
+
+ toggleRule(e, 'rule')} + /> +
+ {#if rule.statement} +
+ + + + +
+ {/if} +
+
+
+
+ changeRule(e, 'rule')} + > + {#each [...ruleOptions] as option} + + {/each} + +
+
+ {}} + on:click={() => deleteRule()} + /> +
+
+
+ + {#if !collapsed} +
+
+
+
+
+
+ {'Criteria'} +
+
+ toggleRule(e, 'criteria')} + /> +
+
+
+
+
+ changeRule(e, 'criteria')} + > + {#each [...criteriaOptions] as option} + + {/each} + +
+
+
+
+
+
+
+
+ {'Text'} +
+ {#if ADMIN_ROLES.includes(user?.role || '') && !!rule.trigger_name && !!rule.rule_criteria?.criteria_text?.trim()} +
+ {}} + on:click={() => compileCodeScript()} + /> +
+ {/if} +
+
+
+
+ changeContent(e, 'criteria-text')} + /> +
+
+ {#if rule.json_args} +
+ + + + +
+ {/if} +
+
+
+ {#if rule.rule_criteria?.name} +
+
+
+
+ {'Config'} +
+
+
+
+
+ changeContent(e, 'criteria-config')} + /> +
+
+
+
+ {/if} +
+
+ +
+
+
+
+
+
+ {'Action'} +
+
+ toggleRule(e, 'action')} + /> +
+
+
+
+
+ changeRule(e, 'action')} + > + {#each [...actionOptions] as option} + + {/each} + +
+
+
+
+ {#if rule.rule_action?.name} +
+
+
+
+ {'Config'} +
+
+
+
+
+ changeContent(e, 'action-config')} + /> +
+
+
+
+ {/if} +
+
+ {/if} +
\ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-components/agent-rule.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte similarity index 90% rename from src/routes/page/agent/[agentId]/agent-components/agent-rule.svelte rename to src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte index 6b698758..129b69ed 100644 --- a/src/routes/page/agent/[agentId]/agent-components/agent-rule.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte @@ -10,6 +10,7 @@ import CodeScript from '$lib/common/shared/CodeScript.svelte'; import { AgentCodeScriptType } from '$lib/helpers/enums'; import { scrollToBottom } from '$lib/helpers/utils/common'; + import AgentRuleItem from './agent-rule-item.svelte'; const limit = 100; const textLimit = 1024; @@ -150,19 +151,20 @@ function changeRule(e, idx, field) { const found = innerRules.find((_, index) => index === idx); if (!found) return; - + + const value = e.detail.value; if (field === 'rule') { - found.trigger_name = e.target.value; + found.trigger_name = value; } else if (field === 'criteria') { found.rule_criteria = { ...found.rule_criteria || {}, - name: e.target.value, + name: value, disabled: found.rule_criteria?.disabled || false }; } else if (field === 'action') { found.rule_action = { ...found.rule_action || {}, - name: e.target.value, + name: value, disabled: found.rule_action?.disabled || false }; } @@ -177,7 +179,8 @@ { trigger_name: '', displayName: '', - disabled: false + disabled: false, + collapsed: false } ]; scrollToBottom(scrollContainer); @@ -200,7 +203,7 @@ if (!found) return; if (field === 'rule') { - found.disabled = !e.target.checked; + found.disabled = !e.detail.checked; } else if (field === 'criteria') { if (!found.rule_criteria) { found.rule_criteria = { @@ -208,7 +211,7 @@ disabled: false }; } - found.rule_criteria.disabled = !e.target.checked; + found.rule_criteria.disabled = !e.detail.checked; } else if (field === 'action') { if (!found.rule_action) { found.rule_action = { @@ -216,7 +219,7 @@ disabled: false }; } - found.rule_action.disabled = !e.target.checked; + found.rule_action.disabled = !e.detail.checked; } innerRefresh(innerRules); @@ -232,6 +235,7 @@ const found = innerRules.find((_, index) => index === uid); if (!found) return; + const value = e.detail.value; if (field === 'criteria-text') { if (found.rule_criteria == null) { found.rule_criteria = { @@ -240,7 +244,7 @@ config: {} }; } - found.rule_criteria.criteria_text = e.target.value; + found.rule_criteria.criteria_text = value; innerRefresh(innerRules); handleAgentChange(); } else if (field === 'criteria-config') { @@ -252,7 +256,7 @@ }; } try { - found.rule_criteria.config = JSON.parse(e.detail?.text || '{}'); + found.rule_criteria.config = JSON.parse(value || '{}'); handleAgentChange(); } catch { // ignore invalid JSON while typing @@ -266,7 +270,7 @@ }; } try { - found.rule_action.config = JSON.parse(e.detail?.text || '{}'); + found.rule_action.config = JSON.parse(value || '{}'); handleAgentChange(); } catch { // ignore invalid JSON while typing @@ -274,6 +278,20 @@ } } + /** + * @param {any} e + * @param {number} uid + * @param {boolean} collapsed + */ + function toggleCollapse(e, uid, collapsed) { + const found = innerRules.find((_, index) => index === uid); + if (!found) return; + + found.collapsed = !collapsed; + innerRefresh(innerRules); + handleAgentChange(); + } + /** * @param {import("$agentTypes").AgentRule} rule */ @@ -398,10 +416,21 @@
{#each innerRules as rule, uid (uid)} -
+ + toggleRule(e, uid, e.detail.field)} + on:delete={() => deleteRule(uid)} + on:changeOption={e => changeRule(e, uid, e.detail.field)} + on:changeContent={e => changeContent(e, uid, e.detail.field)} + on:compile={e => compileCodeScript(e.detail.rule)} + on:collapse={e => toggleCollapse(e, uid, e.detail.collapsed)} + /> {/each} {#if innerRules.length < limit} diff --git a/src/routes/page/agent/[agentId]/agent-tabs.svelte b/src/routes/page/agent/[agentId]/agent-tabs.svelte index a585c546..76080fa3 100644 --- a/src/routes/page/agent/[agentId]/agent-tabs.svelte +++ b/src/routes/page/agent/[agentId]/agent-tabs.svelte @@ -7,7 +7,7 @@ import AgentUtility from './agent-components/agent-utility.svelte'; import AgentKnowledgeBase from './agent-components/agent-knowledge-base.svelte'; import AgentRouting from './agent-components/agent-routing.svelte'; - import AgentEventRule from './agent-components/agent-rule.svelte'; + import AgentEventRule from './agent-components/rules/agent-rule.svelte'; import AgentMcpTool from './agent-components/agent-mcp-tool.svelte'; /** @type {import('$agentTypes').AgentModel} */ From 0a09eac5ee00f07d274341d90ca510489f403f95 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Tue, 10 Feb 2026 16:20:54 -0600 Subject: [PATCH 08/21] refine agent rule item --- src/lib/helpers/types/agentTypes.js | 2 +- src/lib/scss/custom/common/_common.scss | 8 + src/lib/scss/custom/pages/_agent.scss | 4 - .../rules/agent-rule-item.svelte | 11 +- .../agent-components/rules/agent-rule.svelte | 290 +----------------- .../{ => utilities}/agent-utility.svelte | 0 .../page/agent/[agentId]/agent-tabs.svelte | 2 +- 7 files changed, 26 insertions(+), 291 deletions(-) rename src/routes/page/agent/[agentId]/agent-components/{ => utilities}/agent-utility.svelte (100%) diff --git a/src/lib/helpers/types/agentTypes.js b/src/lib/helpers/types/agentTypes.js index 78259132..8e0eff3b 100644 --- a/src/lib/helpers/types/agentTypes.js +++ b/src/lib/helpers/types/agentTypes.js @@ -233,7 +233,7 @@ * @property {any?} [output_args] * @property {string?} [json_args] * @property {string?} [statement] - * @property {boolean} [collapsed] + * @property {boolean} [expanded] */ /** diff --git a/src/lib/scss/custom/common/_common.scss b/src/lib/scss/custom/common/_common.scss index 8a0c1f6e..c2584b22 100644 --- a/src/lib/scss/custom/common/_common.scss +++ b/src/lib/scss/custom/common/_common.scss @@ -225,4 +225,12 @@ button:focus { text-decoration: none !important; transform: none !important; } +} + +.collapse-toggle { + transition: transform 0.2s ease-in-out; +} + +.collapse-toggle.rotated { + transform: rotate(90deg); } \ 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 10c6a72b..618a37bd 100644 --- a/src/lib/scss/custom/pages/_agent.scss +++ b/src/lib/scss/custom/pages/_agent.scss @@ -250,10 +250,6 @@ display: flex; gap: 10px; - .collapse-toggle { - transition: transform 0.2s ease; - } - .utility-tooltip { display: flex; } diff --git a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte index b36e2e5e..a560085e 100644 --- a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte @@ -1,5 +1,6 @@ + +
+
+
+
+ {}} + on:click={() => toggleCollapse()} + /> +
+
+ {`Utility #${utilityIndex + 1}`} +
+
+
+ toggleUtility(e)} + /> +
+ +
+
+
+
+ changeUtilityCategory(e)} + > + {#each utilityCategoryOptions as option} + + {/each} + +
+
+ {}} + on:click={() => deleteUtility()} + /> +
+
+
+ + {#if !collapsed} +
+ {#if utility.category} + { + @const utilityOptions = getUtilityOptions(utilityMapper[utility.category]?.map((/** @type {any} */ x) => x.name), 'Select a utility') + } +
+
+
+
{'Name'}
+ {#if utility.name} +
+ + + resetUtility()} + /> +
+ {/if} +
+
+
+ changeUtilityName(e)} + > + {#each utilityOptions as option} + + {/each} + +
+
+
+
+
+
+ {'Visibility'} +
+
+
+ changeUtilityVisibility(e)} + /> +
+
+
+
+
+ {/if} + {#each utility.items as item, fid (fid)} +
+ {#if item.function_name} + { + @const description = getUtilityItemDescription(utility.category, utility.name, item.function_name) + } +
+
+
{'Function'}
+ {#if description} +
+ + + + +
+ {/if} +
+
+
+ +
+
+ {}} + on:click={() => deleteUtilityItem(fid, 'function')} + /> +
+
+
+ {/if} + {#if item.template_name} +
+
+ {'Template'} +
+
+
+ +
+
+ {}} + on:click={() => deleteUtilityItem(fid, 'template')} + /> +
+
+
+ {/if} +
+
+ {'Visibility'} +
+
+
+ changeUtilityItemVisibility(e, fid)} + /> +
+
+
+
+
+ {/each} +
+ {/if} +
\ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-components/utilities/agent-utility.svelte b/src/routes/page/agent/[agentId]/agent-components/utilities/agent-utility.svelte index 40510dcb..f9f289f6 100644 --- a/src/routes/page/agent/[agentId]/agent-components/utilities/agent-utility.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/utilities/agent-utility.svelte @@ -3,8 +3,7 @@ import { Card, CardBody, Input, Button } from '@sveltestrap/sveltestrap'; import { getAgentUtilityOptions } from '$lib/services/agent-service'; import { scrollToBottom, truncateByPrefix } from '$lib/helpers/utils/common'; - import Markdown from '$lib/common/markdown/Markdown.svelte'; - import BotsharpTooltip from '$lib/common/tooltip/BotsharpTooltip.svelte'; + import AgentUtilityItem from './agent-utility-item.svelte'; const limit = 100; const prefix = "util-"; @@ -86,39 +85,6 @@ windowHeight = window.innerHeight; } - /** - * @param {any} e - * @param {number} idx - */ - function changeUtilityCategory(e, idx) { - const found = innerUtilities.find((_, index) => index === idx); - if (!found) return; - - const category = e.target.value; - found.category = category; - found.name = ''; - found.items = []; - innerRefresh(innerUtilities); - handleAgentChange(); - } - - /** - * @param {any} e - * @param {number} idx - */ - function changeUtilityName(e, idx) { - const found = innerUtilities.find((_, index) => index === idx); - if (!found) return; - - const name = e.target.value; - found.name = name; - - const foundUtility = utilityMapper[found.category]?.find((/** @type {any} */ x) => x.name == name); - found.items = foundUtility?.items?.map((/** @type {any} */ x) => ({...x})) || []; - - innerRefresh(innerUtilities); - handleAgentChange(); - } function addUtility() { innerUtilities = [ @@ -127,68 +93,72 @@ category: '', name: '', disabled: false, - items: [] + items: [], + expanded: true } ]; scrollToBottom(scrollContainer); handleAgentChange(); } - /** @param {number} idx */ - function deleteUtility(idx) { - innerUtilities = innerUtilities.filter((_, index) => index !== idx); - handleAgentChange(); - } - /** * @param {any} e - * @param {number} uid + * @param {number} idx */ - function changeUtilityVisibility(e, uid) { - const found = innerUtilities.find((_, index) => index === uid); - if (!found) return; + function deleteUtility(e, idx) { + if (e.detail.field == 'utility') { + innerUtilities = innerUtilities.filter((_, index) => index !== idx); + } else if (e.detail.field == 'utility-item') { + const foundUtility = innerUtilities.find((_, index) => index === idx); + const foundItem = foundUtility?.items?.find((_, index) => index === e.detail.itemIdx); + if (!foundUtility || !foundItem) return; + + if (e.detail.subfield === 'function') { + foundItem.function_name = null; + foundItem.function_display_name = null; + foundItem.template_name = null; + foundItem.template_display_name = null; + } else if (e.detail.subfield === 'template') { + foundItem.template_name = null; + foundItem.template_display_name = null; + } - found.visibility_expression = e.target.value || null; - innerRefresh(innerUtilities); - handleAgentChange(); - } + if (foundItem.function_name == null && foundItem.template_name == null) { + foundUtility.items = foundUtility.items.filter((_, index) => index !== e.detail.itemIdx); + } - /** - * @param {any} e - * @param {number} uid - * @param {number} fid - */ - function changeUtilityItemVisibility(e, uid, fid) { - const found = innerUtilities.find((_, index) => index === uid)?.items?.find((_, index) => index === fid); - if (!found) return; + innerRefresh(innerUtilities); + } - found.visibility_expression = e.target.value || null; - innerRefresh(innerUtilities); handleAgentChange(); } + /** + * @param {any} e * @param {number} uid - * @param {number} fid - * @param {string} type */ - function deleteUtilityItem(uid, fid, type) { - const foundUtility = innerUtilities.find((_, index) => index === uid); - const foundItem = foundUtility?.items?.find((_, index) => index === fid); - if (!foundUtility || !foundItem) return; - - 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; - } + function changeUtility(e, uid) { + const found = innerUtilities.find((_, index) => index === uid); + if (!found) return; - if (foundItem.function_name == null && foundItem.template_name == null) { - foundUtility.items = foundUtility.items.filter((_, index) => index !== fid); + if (e.detail.field === 'utility-category') { + const category = e.detail.value; + found.category = category; + found.name = ''; + found.items = []; + } else if (e.detail.field === 'utility-name') { + const name = e.detail.value; + found.name = name; + const foundUtility = utilityMapper[found.category]?.find((/** @type {any} */ x) => x.name == name); + found.items = foundUtility?.items?.map((/** @type {any} */ x) => ({...x})) || []; + } else if (e.detail.field === 'utility-visibility') { + found.visibility_expression = e.detail.value || null; + } else if (e.detail.field === 'utility-item-visibility') { + const foundItem = found.items.find((_, index) => index === e.detail.itemIdx); + if (foundItem) { + foundItem.visibility_expression = e.detail.value || null; + } } innerRefresh(innerUtilities); @@ -203,7 +173,7 @@ const found = innerUtilities.find((_, index) => index === uid); if (!found) return; - found.disabled = !e.target.checked; + found.disabled = !e.detail.checked; innerRefresh(innerUtilities); handleAgentChange(); } @@ -213,6 +183,7 @@ function innerRefresh(list) { innerUtilities = list?.map(x => { return { + ...x, category: x.category, name: x.name, disabled: x.disabled, @@ -232,6 +203,31 @@ handleAgentChange(); } + /** @param {number} uid */ + function resetUtility(uid) { + const found = innerUtilities.find((_, index) => index === uid); + if (!found) return; + + const originalItems = utilityMapper[found.category]?.find((/** @type {any} */ x) => x.name === found.name)?.items || []; + found.items = [...originalItems]; + innerRefresh(innerUtilities); + handleAgentChange(); + } + + /** + * @param {any} e + * @param {number} uid + * @param {boolean} collapsed + */ + function toggleCollapse(e, uid, collapsed) { + const found = innerUtilities.find((_, index) => index === uid); + if (!found) return; + + found.expanded = !collapsed; + innerRefresh(innerUtilities); + handleAgentChange(); + } + /** * @param {string[]} options * @param {string} placeholder @@ -250,28 +246,6 @@ }, ...list]; 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); - if (!found) return; - - const originalItems = utilityMapper[found.category]?.find((/** @type {any} */ x) => x.name === found.name)?.items || []; - found.items = [...originalItems]; - innerRefresh(innerUtilities); - handleAgentChange(); - } resizeWindow()}/> @@ -309,215 +283,19 @@ { @const utilityCategoryOptions = getUtilityOptions(Object.keys(utilityMapper), 'Select a category') } -
-
-
-
{`Utility #${uid + 1}`}
-
-
- toggleUtility(e, uid)} - /> -
- -
-
-
-
- changeUtilityCategory(e, uid)} - > - {#each utilityCategoryOptions as option} - - {/each} - -
-
- {}} - on:click={() => deleteUtility(uid)} - /> -
-
-
- -
- {#if utility.category} - { - @const utilityOptions = getUtilityOptions(utilityMapper[utility.category]?.map((/** @type {any} */ x) => x.name), 'Select a utility') - } -
-
-
-
{'Name'}
- {#if utility.name} -
- - - resetUtility(uid)} - /> -
- {/if} -
-
-
- changeUtilityName(e, uid)} - > - {#each utilityOptions as option} - - {/each} - -
-
-
-
-
-
- {'Visibility'} -
-
-
- changeUtilityVisibility(e, uid)} - /> -
-
-
-
-
- {/if} - {#each utility.items as item, fid (fid)} -
- {#if item.function_name} - { - @const description = getUtilityItemDescription(utility.category, utility.name, item.function_name) - } -
-
-
{'Function'}
- {#if description} -
- - - - -
- {/if} -
-
-
- -
-
- {}} - on:click={() => deleteUtilityItem(uid, fid, 'function')} - /> -
-
-
- {/if} - {#if item.template_name} -
-
- {'Template'} -
-
-
- -
-
- {}} - on:click={() => deleteUtilityItem(uid, fid, 'template')} - /> -
-
-
- {/if} -
-
- {'Visibility'} -
-
-
- changeUtilityItemVisibility(e, uid, fid)} - /> -
-
-
-
-
- {/each} -
-
+ toggleUtility(e, uid)} + on:delete={e => deleteUtility(e, uid)} + on:reset={() => resetUtility(uid)} + on:change={e => changeUtility(e, uid)} + on:collapse={e => toggleCollapse(e, uid, e.detail.collapsed)} + /> {/each} {#if innerUtilities.length < limit} From 6c144e14bb30e8a5db15789b7f8a0b6d1fddbadd Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 11 Feb 2026 13:15:12 -0600 Subject: [PATCH 10/21] refine agent rule change event --- .../rules/agent-rule-item.svelte | 22 +---- .../agent-components/rules/agent-rule.svelte | 95 ++++++++----------- .../utilities/agent-utility-item.svelte | 24 ++--- 3 files changed, 57 insertions(+), 84 deletions(-) diff --git a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte index a560085e..f97ce060 100644 --- a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte @@ -55,10 +55,10 @@ * @param {string} field */ function changeRule(e, field) { - svelteDispatch('changeOption', { + svelteDispatch('change', { ruleIdx: ruleIndex, field: field, - value: e.target.value + value: e?.target?.value || e?.detail?.text || '' }); } @@ -68,18 +68,6 @@ }); } - /** - * @param {any} e - * @param {string} field - */ - function changeContent(e, field) { - svelteDispatch('changeContent', { - ruleIdx: ruleIndex, - field: field, - value: e?.target?.value || e?.detail?.text || '' - }); - } - function toggleCollapse() { svelteDispatch('collapse', { @@ -243,7 +231,7 @@ disabled={!!rule.rule_criteria?.disabled} maxlength={textLimit} value={rule.rule_criteria?.criteria_text} - on:input={e => changeContent(e, 'criteria-text')} + on:input={e => changeRule(e, 'criteria-text')} />
@@ -293,7 +281,7 @@ hideLineNumber={true} editable={!rule.rule_criteria?.disabled} scriptText={JSON.stringify(rule.rule_criteria?.config || {}, null, 2)} - on:change={(e) => changeContent(e, 'criteria-config')} + on:change={(e) => changeRule(e, 'criteria-config')} />
@@ -354,7 +342,7 @@ hideLineNumber={true} editable={!rule.rule_action?.disabled} scriptText={JSON.stringify(rule.rule_action?.config || {}, null, 2)} - on:change={(e) => changeContent(e, 'action-config')} + on:change={(e) => changeRule(e, 'action-config')} />
diff --git a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte index b42fe2b4..f6d508f0 100644 --- a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte @@ -152,21 +152,59 @@ const value = e.detail.value; if (field === 'rule') { found.trigger_name = value; + innerRefresh(innerRules); } else if (field === 'criteria') { found.rule_criteria = { ...found.rule_criteria || {}, name: value, disabled: found.rule_criteria?.disabled || false }; + innerRefresh(innerRules); } else if (field === 'action') { found.rule_action = { ...found.rule_action || {}, name: value, disabled: found.rule_action?.disabled || false }; + innerRefresh(innerRules); + } else if (field === 'criteria-text') { + if (found.rule_criteria == null) { + found.rule_criteria = { + name: '', + disabled: false, + config: {} + }; + } + found.rule_criteria.criteria_text = value; + innerRefresh(innerRules); + } else if (field === 'criteria-config') { + if (found.rule_criteria == null) { + found.rule_criteria = { + name: '', + disabled: false, + config: {} + }; + } + try { + found.rule_criteria.config = JSON.parse(value || '{}'); + } catch { + // ignore invalid JSON while typing + } + } else if (field === 'action-config') { + if (found.rule_action == null) { + found.rule_action = { + name: '', + disabled: false, + config: {} + }; + } + try { + found.rule_action.config = JSON.parse(value || '{}'); + } catch { + // ignore invalid JSON while typing + } } - innerRefresh(innerRules); handleAgentChange(); } @@ -223,58 +261,6 @@ handleAgentChange(); } - /** - * @param {any} e - * @param {number} uid - * @param {string} field - */ - function changeContent(e, uid, field) { - const found = innerRules.find((_, index) => index === uid); - if (!found) return; - - const value = e.detail.value; - if (field === 'criteria-text') { - if (found.rule_criteria == null) { - found.rule_criteria = { - name: '', - disabled: false, - config: {} - }; - } - found.rule_criteria.criteria_text = value; - innerRefresh(innerRules); - handleAgentChange(); - } else if (field === 'criteria-config') { - if (found.rule_criteria == null) { - found.rule_criteria = { - name: '', - disabled: false, - config: {} - }; - } - try { - found.rule_criteria.config = JSON.parse(value || '{}'); - handleAgentChange(); - } catch { - // ignore invalid JSON while typing - } - } else if (field === 'action-config') { - if (found.rule_action == null) { - found.rule_action = { - name: '', - disabled: false, - config: {} - }; - } - try { - found.rule_action.config = JSON.parse(value || '{}'); - handleAgentChange(); - } catch { - // ignore invalid JSON while typing - } - } - } - /** * @param {any} e * @param {number} uid @@ -424,8 +410,7 @@ windowWidth={windowWidth} on:toggle={e => toggleRule(e, uid, e.detail.field)} on:delete={() => deleteRule(uid)} - on:changeOption={e => changeRule(e, uid, e.detail.field)} - on:changeContent={e => changeContent(e, uid, e.detail.field)} + on:change={e => changeRule(e, uid, e.detail.field)} on:compile={e => compileCodeScript(e.detail.rule)} on:collapse={e => toggleCollapse(e, uid, e.detail.collapsed)} /> diff --git a/src/routes/page/agent/[agentId]/agent-components/utilities/agent-utility-item.svelte b/src/routes/page/agent/[agentId]/agent-components/utilities/agent-utility-item.svelte index 44a84d22..96f1c453 100644 --- a/src/routes/page/agent/[agentId]/agent-components/utilities/agent-utility-item.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/utilities/agent-utility-item.svelte @@ -85,28 +85,28 @@ } /** + * @param {any} e * @param {number} fid - * @param {string} type */ - function deleteUtilityItem(fid, type) { - svelteDispatch('delete', { + function changeUtilityItemVisibility(e, fid) { + svelteDispatch('change', { utilityIdx: utilityIndex, - field: 'utility-item', - subfield: type, - itemIdx: fid + field: 'utility-item-visibility', + itemIdx: fid, + value: e.target.value }); } /** - * @param {any} e * @param {number} fid + * @param {string} type */ - function changeUtilityItemVisibility(e, fid) { - svelteDispatch('change', { + function deleteUtilityItem(fid, type) { + svelteDispatch('delete', { utilityIdx: utilityIndex, - field: 'utility-item-visibility', - itemIdx: fid, - value: e.target.value + field: 'utility-item', + subfield: type, + itemIdx: fid }); } From 0dd17378a0e40514be2bbec7c2bd5d9be0a93863 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 11 Feb 2026 13:45:00 -0600 Subject: [PATCH 11/21] refine mcp tools --- src/lib/helpers/types/agentTypes.js | 1 + .../agent-components/agent-mcp-tool.svelte | 358 ------------------ .../mcp-tools/agent-mcp-tool-item.svelte | 226 +++++++++++ .../mcp-tools/agent-mcp-tool.svelte | 248 ++++++++++++ .../agent-components/rules/agent-rule.svelte | 7 +- .../utilities/agent-utility.svelte | 7 +- .../page/agent/[agentId]/agent-tabs.svelte | 4 +- 7 files changed, 483 insertions(+), 368 deletions(-) delete mode 100644 src/routes/page/agent/[agentId]/agent-components/agent-mcp-tool.svelte create mode 100644 src/routes/page/agent/[agentId]/agent-components/mcp-tools/agent-mcp-tool-item.svelte create mode 100644 src/routes/page/agent/[agentId]/agent-components/mcp-tools/agent-mcp-tool.svelte diff --git a/src/lib/helpers/types/agentTypes.js b/src/lib/helpers/types/agentTypes.js index b8e540df..9d3260fc 100644 --- a/src/lib/helpers/types/agentTypes.js +++ b/src/lib/helpers/types/agentTypes.js @@ -213,6 +213,7 @@ * @property {string} server_id * @property {boolean} disabled * @property {import('$commonTypes').NameBase[]} functions + * @property {boolean} [expanded] */ /** diff --git a/src/routes/page/agent/[agentId]/agent-components/agent-mcp-tool.svelte b/src/routes/page/agent/[agentId]/agent-components/agent-mcp-tool.svelte deleted file mode 100644 index d85f5624..00000000 --- a/src/routes/page/agent/[agentId]/agent-components/agent-mcp-tool.svelte +++ /dev/null @@ -1,358 +0,0 @@ - - - - -
-
MCP Tools
-
Tools powered by MCP Servers
-
- -
- {#each innerMcps as mcp, uid (uid)} -
-
-
-
{`MCP #${uid + 1}`}
-
-
- toggleMcp(e, uid)} - /> -
- -
-
-
-
- changeMcp(e, uid)} - > - {#each [...mcpOptions] as option} - - {/each} - -
-
- {}} - on:click={() => deleteMcp(uid)} - /> -
-
-
- -
-
-
-
- {'Server'} -
-
-
- -
-
-
-
-
-
- {#each mcp.functions as fn, fid (fid)} -
-
- {fid === 0 ? 'Tools' : ''} -
-
-
- changeMcpContent(e, uid, fid, 'function')} - > - {#each [...mcpOptions.find(x => x.id === mcp.server_id)?.tools || []] as option} - - {/each} - -
-
- {}} - on:click={() => deleteMcpContent(uid, fid, 'function')} - /> -
-
-
- {/each} - - {#if mcp.functions?.length < limit} -
-
- {mcp.functions.length === 0 ? 'Functions' : ''} -
-
- {}} - on:click={() => addMcpContent(uid, 'function')} - /> -
-
- {/if} -
-
-
- {/each} - - {#if innerMcps.length < limit} -
- -
- {/if} -
-
-
\ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-components/mcp-tools/agent-mcp-tool-item.svelte b/src/routes/page/agent/[agentId]/agent-components/mcp-tools/agent-mcp-tool-item.svelte new file mode 100644 index 00000000..e0750d32 --- /dev/null +++ b/src/routes/page/agent/[agentId]/agent-components/mcp-tools/agent-mcp-tool-item.svelte @@ -0,0 +1,226 @@ + + +
+
+
+
+ {}} + on:click={() => toggleCollapse()} + /> +
+
+ {`MCP #${mcpIndex + 1}`} +
+
+
+ toggleMcp(e)} + /> +
+ +
+
+
+
+ changeMcp(e)} + > + {#each [...mcpOptions] as option} + + {/each} + +
+
+ {}} + on:click={() => deleteMcp()} + /> +
+
+
+ + {#if !collapsed} +
+
+
+
+ {'Server'} +
+
+
+ +
+
+
+
+
+
+ {#each mcp.functions as fn, fid (fid)} +
+
+ {fid === 0 ? 'Tools' : ''} +
+
+
+ changeMcpItem(e, fid, 'function')} + > + {#each [...mcpOptions.find(x => x.id === mcp.server_id)?.tools || []] as option} + + {/each} + +
+
+ {}} + on:click={() => deleteMcpItem(fid, 'function')} + /> +
+
+
+ {/each} + + {#if mcp.functions?.length < limit} +
+
+ {mcp.functions.length === 0 ? 'Functions' : ''} +
+
+ {}} + on:click={() => addMcpItem('function')} + /> +
+
+ {/if} +
+
+ {/if} +
\ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-components/mcp-tools/agent-mcp-tool.svelte b/src/routes/page/agent/[agentId]/agent-components/mcp-tools/agent-mcp-tool.svelte new file mode 100644 index 00000000..618fc8dc --- /dev/null +++ b/src/routes/page/agent/[agentId]/agent-components/mcp-tools/agent-mcp-tool.svelte @@ -0,0 +1,248 @@ + + + + +
+
MCP Tools
+
Tools powered by MCP Servers
+
+ +
+ {#each innerMcps as mcp, uid (uid)} + toggleMcp(e, uid)} + on:delete={e => deleteMcp(e, uid)} + on:change={e => changeMcpContent(e, uid)} + on:add={e => addMcpContent(e, uid)} + on:collapse={e => toggleCollapse(e, uid)} + /> + {/each} + + {#if innerMcps.length < limit} +
+ +
+ {/if} +
+
+
\ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte index f6d508f0..f7b6e8c1 100644 --- a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte @@ -264,13 +264,12 @@ /** * @param {any} e * @param {number} uid - * @param {boolean} collapsed */ - function toggleCollapse(e, uid, collapsed) { + function toggleCollapse(e, uid) { const found = innerRules.find((_, index) => index === uid); if (!found) return; - found.expanded = !collapsed; + found.expanded = !e.detail.collapsed; innerRefresh(innerRules); handleAgentChange(); } @@ -412,7 +411,7 @@ on:delete={() => deleteRule(uid)} on:change={e => changeRule(e, uid, e.detail.field)} on:compile={e => compileCodeScript(e.detail.rule)} - on:collapse={e => toggleCollapse(e, uid, e.detail.collapsed)} + on:collapse={e => toggleCollapse(e, uid)} /> {/each} diff --git a/src/routes/page/agent/[agentId]/agent-components/utilities/agent-utility.svelte b/src/routes/page/agent/[agentId]/agent-components/utilities/agent-utility.svelte index f9f289f6..a2239b29 100644 --- a/src/routes/page/agent/[agentId]/agent-components/utilities/agent-utility.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/utilities/agent-utility.svelte @@ -217,13 +217,12 @@ /** * @param {any} e * @param {number} uid - * @param {boolean} collapsed */ - function toggleCollapse(e, uid, collapsed) { + function toggleCollapse(e, uid) { const found = innerUtilities.find((_, index) => index === uid); if (!found) return; - found.expanded = !collapsed; + found.expanded = !e.detail.collapsed; innerRefresh(innerUtilities); handleAgentChange(); } @@ -294,7 +293,7 @@ on:delete={e => deleteUtility(e, uid)} on:reset={() => resetUtility(uid)} on:change={e => changeUtility(e, uid)} - on:collapse={e => toggleCollapse(e, uid, e.detail.collapsed)} + on:collapse={e => toggleCollapse(e, uid)} /> {/each} diff --git a/src/routes/page/agent/[agentId]/agent-tabs.svelte b/src/routes/page/agent/[agentId]/agent-tabs.svelte index 0d8dbbdc..f43236aa 100644 --- a/src/routes/page/agent/[agentId]/agent-tabs.svelte +++ b/src/routes/page/agent/[agentId]/agent-tabs.svelte @@ -8,7 +8,7 @@ import AgentKnowledgeBase from './agent-components/agent-knowledge-base.svelte'; import AgentRouting from './agent-components/agent-routing.svelte'; import AgentEventRule from './agent-components/rules/agent-rule.svelte'; - import AgentMcpTool from './agent-components/agent-mcp-tool.svelte'; + import AgentMcpTool from './agent-components/mcp-tools/agent-mcp-tool.svelte'; /** @type {import('$agentTypes').AgentModel} */ export let agent; @@ -60,7 +60,7 @@ ]; onMount(() => { - selectedTab = tabs[0]?.name; + selectedTab = tabs[5]?.name; }); /** @param {string} selected */ From 7d7ab15fbe872975ba9f5196cf1e045464a27c58 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 11 Feb 2026 14:30:24 -0600 Subject: [PATCH 12/21] refine knowledgebase --- src/lib/helpers/types/agentTypes.js | 1 + .../agent-knowledge-base-item.svelte | 161 ++++++++++++++++++ .../agent-knowledge-base.svelte | 151 ++++++---------- .../mcp-tools/agent-mcp-tool-item.svelte | 2 +- .../mcp-tools/agent-mcp-tool.svelte | 2 +- .../agent-components/rules/agent-rule.svelte | 16 +- .../utilities/agent-utility.svelte | 24 +-- .../page/agent/[agentId]/agent-tabs.svelte | 4 +- 8 files changed, 234 insertions(+), 127 deletions(-) create mode 100644 src/routes/page/agent/[agentId]/agent-components/knowledge-bases/agent-knowledge-base-item.svelte rename src/routes/page/agent/[agentId]/agent-components/{ => knowledge-bases}/agent-knowledge-base.svelte (51%) diff --git a/src/lib/helpers/types/agentTypes.js b/src/lib/helpers/types/agentTypes.js index 9d3260fc..483606bc 100644 --- a/src/lib/helpers/types/agentTypes.js +++ b/src/lib/helpers/types/agentTypes.js @@ -223,6 +223,7 @@ * @property {string?} [displayName] * @property {boolean} disabled * @property {number?} [confidence] + * @property {boolean} [expanded] */ /** diff --git a/src/routes/page/agent/[agentId]/agent-components/knowledge-bases/agent-knowledge-base-item.svelte b/src/routes/page/agent/[agentId]/agent-components/knowledge-bases/agent-knowledge-base-item.svelte new file mode 100644 index 00000000..ecafac02 --- /dev/null +++ b/src/routes/page/agent/[agentId]/agent-components/knowledge-bases/agent-knowledge-base-item.svelte @@ -0,0 +1,161 @@ + + +
+
+
+
+ {}} + on:click={() => toggleCollapse()} + /> +
+
+ {`Collection #${knwoledgeIdx + 1}`} +
+
+
+ toggleKnowledgeBase(e)} + /> +
+ +
+
+
+
+ changeKnowledgeBase(e)} + > + {#each [...knowledgeBaseOptions] as option} + + {/each} + +
+
+ {}} + on:click={() => deleteKnowledgeBase()} + /> +
+
+
+ + {#if !collapsed} +
+
+
+
+ {'Confidence'} +
+
+
+ validateConfidenceInput(e)} + on:blur={e => changeConfidence(e)} + /> +
+
+
+
+
+
+ {/if} +
\ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-components/agent-knowledge-base.svelte b/src/routes/page/agent/[agentId]/agent-components/knowledge-bases/agent-knowledge-base.svelte similarity index 51% rename from src/routes/page/agent/[agentId]/agent-components/agent-knowledge-base.svelte rename to src/routes/page/agent/[agentId]/agent-components/knowledge-bases/agent-knowledge-base.svelte index 7ca2cc7d..951c8d8b 100644 --- a/src/routes/page/agent/[agentId]/agent-components/agent-knowledge-base.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/knowledge-bases/agent-knowledge-base.svelte @@ -1,10 +1,11 @@
-
-
Chat
+
collapsed = !collapsed} + on:keydown={(e) => e.key === 'Enter' && (collapsed = !collapsed)} + > +
+ + Chat +
{#if agent.llm_config?.is_inherit}
- Inherited + Inherited
{/if}
-
- -
- changeProvider(e)}> - {#each providers as option} - - {/each} - + {#if !collapsed} +
+
+ +
+ changeProvider(e)}> + {#each providers as option} + + {/each} + +
-
- -
- -
- changeModel(e)}> - {#each models as option} - - {/each} - + +
+ +
+ changeModel(e)}> + {#each models as option} + + {/each} + +
-
-
- -
- validateIntegerInput(e)} - on:change={e => changeMaxRecursiveDepth(e)} - /> +
+ +
+ validateIntegerInput(e)} + on:change={e => changeMaxRecursiveDepth(e)} + /> +
-
-
- -
- validateIntegerInput(e)} - on:change={e => changeMaxOutputToken(e)} - /> +
+ +
+ validateIntegerInput(e)} + on:change={e => changeMaxOutputToken(e)} + /> +
-
- {#if isReasoningModel} -
- -
- changeReasoningEffortLevel(e)}> - {#each reasoningLevelOptions as option} - - {/each} - + {#if isReasoningModel} +
+ +
+ changeReasoningEffortLevel(e)}> + {#each reasoningLevelOptions as option} + + {/each} + +
+ {/if}
{/if}
\ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-components/llm-configs/llm-basic-config.svelte b/src/routes/page/agent/[agentId]/agent-components/llm-configs/llm-basic-config.svelte index 1597804a..833cab06 100644 --- a/src/routes/page/agent/[agentId]/agent-components/llm-configs/llm-basic-config.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/llm-configs/llm-basic-config.svelte @@ -1,6 +1,7 @@
-
-
{title}
+
collapsed = !collapsed} + on:keydown={(e) => e.key === 'Enter' && (collapsed = !collapsed)} + > +
+ + {title} +
-
- -
- changeProvider(e)}> - {#each providers as option} - - {/each} - + {#if !collapsed} +
+
+ +
+ changeProvider(e)}> + {#each providers as option} + + {/each} + +
-
- -
- -
- changeModel(e)}> - {#each models as option} - - {/each} - + +
+ +
+ changeModel(e)}> + {#each models as option} + + {/each} + +
+ {/if}
\ No newline at end of file From 2544add910d48e4c95be13d1808d9ad460a53544 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Tue, 17 Feb 2026 13:27:37 -0600 Subject: [PATCH 14/21] extend to rule actions --- src/lib/helpers/types/agentTypes.js | 2 +- .../mcp-tools/agent-mcp-tool-item.svelte | 3 + .../rules/agent-rule-item.svelte | 116 +++++++++++++++--- .../agent-components/rules/agent-rule.svelte | 91 +++++++++----- .../page/agent/[agentId]/agent-tabs.svelte | 2 +- 5 files changed, 166 insertions(+), 48 deletions(-) diff --git a/src/lib/helpers/types/agentTypes.js b/src/lib/helpers/types/agentTypes.js index 483606bc..7f8569e9 100644 --- a/src/lib/helpers/types/agentTypes.js +++ b/src/lib/helpers/types/agentTypes.js @@ -232,7 +232,7 @@ * @property {string?} [displayName] * @property {boolean} disabled * @property {AgentRuleCriteria?} [rule_criteria] - * @property {AgentRuleAction?} [rule_action] + * @property {AgentRuleAction[]} rule_actions * @property {any?} [output_args] * @property {string?} [json_args] * @property {string?} [statement] diff --git a/src/routes/page/agent/[agentId]/agent-components/mcp-tools/agent-mcp-tool-item.svelte b/src/routes/page/agent/[agentId]/agent-components/mcp-tools/agent-mcp-tool-item.svelte index 04a3f168..fb66e1e9 100644 --- a/src/routes/page/agent/[agentId]/agent-components/mcp-tools/agent-mcp-tool-item.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/mcp-tools/agent-mcp-tool-item.svelte @@ -212,6 +212,9 @@
{}} diff --git a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte index f97ce060..08a91c33 100644 --- a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte @@ -11,6 +11,7 @@ const duration = 200; const textLimit = 1024; + const actionLimit = 10; /** @type {import('$agentTypes').AgentRule} */ export let rule; @@ -62,12 +63,65 @@ }); } - function deleteRule() { + /** + * @param {any} e + * @param {string} field + * @param {number} idx + */ + function toggleRuleAction(e, field, idx) { + svelteDispatch('toggle', { + ruleIdx: ruleIndex, + field: field, + itemIdx: idx, + checked: e.target.checked + }); + } + + /** + * @param {any} e + * @param {string} field + * @param {number} idx + */ + function changeRuleAction(e, field, idx) { + svelteDispatch('change', { + ruleIdx: ruleIndex, + field: field, + itemIdx: idx, + value: e?.target?.value || e?.detail?.text || '' + }); + } + + /** + * @param {string} field + */ + function addRuleItem(field) { + svelteDispatch('add', { + ruleIdx: ruleIndex, + field: field + }); + } + + /** + * @param {string} field + */ + function deleteRule(field) { svelteDispatch('delete', { - ruleIdx: ruleIndex + ruleIdx: ruleIndex, + field: field }); } + /** + * @param {string} field + * @param {number} idx + */ + function deleteRuleItem(field, idx) { + svelteDispatch('delete', { + ruleIdx: ruleIndex, + field: field, + itemIdx: idx + }); + } function toggleCollapse() { svelteDispatch('collapse', { @@ -156,7 +210,7 @@ role="link" tabindex="0" on:keydown={() => {}} - on:click={() => deleteRule()} + on:click={() => deleteRule('rule')} />
@@ -292,18 +346,19 @@
-
+ {#each rule.rule_actions || [] as action, aid (aid)} +
0 ? 'border-top-style: none' : ''}`}>
- {'Action'} + {`Action #${aid + 1}`}
toggleRule(e, 'action')} + checked={!action?.disabled} + on:change={e => toggleRuleAction(e, 'action', aid)} />
@@ -312,20 +367,28 @@
changeRule(e, 'action')} + disabled={!!action?.disabled} + on:change={e => changeRuleAction(e, 'action', aid)} > {#each [...actionOptions] as option} - {/each}
-
+
+ {}} + on:click={() => deleteRuleItem('action', aid)} + /> +
- {#if rule.rule_action?.name} + {#if action?.name}
@@ -340,9 +403,9 @@ language="json" containerClasses="agent-rule-config" hideLineNumber={true} - editable={!rule.rule_action?.disabled} - scriptText={JSON.stringify(rule.rule_action?.config || {}, null, 2)} - on:change={(e) => changeRule(e, 'action-config')} + editable={!action?.disabled} + scriptText={JSON.stringify(action?.config || {}, null, 2)} + on:change={(e) => changeRuleAction(e, 'action-config', aid)} />
@@ -350,6 +413,29 @@
{/if}
+ {/each} + + {#if rule.rule_actions?.length < actionLimit} +
+
+
+ {rule.rule_actions.length === 0 ? 'Actions' : ''} +
+
+ {}} + on:click={() => addRuleItem('action')} + /> +
+
+
+ {/if}
{/if}
\ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte index e2580674..daa47124 100644 --- a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte @@ -41,7 +41,7 @@ trigger_name: x.trigger_name, disabled: x.disabled, rule_criteria: x.rule_criteria, - rule_action: x.rule_action, + rule_actions: x.rule_actions.filter(x => !!x.name), expanded: x.expanded }; }); @@ -160,13 +160,6 @@ disabled: found.rule_criteria?.disabled || false }; innerRefresh(innerRules); - } else if (field === 'action') { - found.rule_action = { - ...found.rule_action || {}, - name: value, - disabled: found.rule_action?.disabled || false - }; - innerRefresh(innerRules); } else if (field === 'criteria-text') { if (found.rule_criteria == null) { found.rule_criteria = { @@ -190,19 +183,21 @@ } catch { // ignore invalid JSON while typing } - } else if (field === 'action-config') { - if (found.rule_action == null) { - found.rule_action = { - name: '', - disabled: false, - config: {} - }; - } - try { - found.rule_action.config = JSON.parse(value || '{}'); - } catch { - // ignore invalid JSON while typing + } else if (field === 'action') { + const foundAction = found.rule_actions?.find((_, index) => index === e.detail.itemIdx); + if (foundAction) { + foundAction.name = value; } + innerRefresh(innerRules); + } else if (field === 'action-config') { + const foundAction = found.rule_actions?.find((_, index) => index === e.detail.itemIdx); + if (foundAction) { + try { + foundAction.config = JSON.parse(value || '{}'); + } catch { + // ignore invalid JSON while typing + } + } } handleAgentChange(); @@ -215,16 +210,29 @@ trigger_name: '', displayName: '', disabled: false, - expanded: true + expanded: true, + rule_actions: [] } ]; scrollToBottom(scrollContainer); handleAgentChange(); } - /** @param {number} idx */ - function deleteRule(idx) { - innerRules = innerRules.filter((_, index) => index !== idx); + /** + * @param {any} e + * @param {number} idx + */ + function deleteRule(e, idx) { + if (e.detail.field === 'rule') { + innerRules = innerRules.filter((_, index) => index !== idx); + } else if (e.detail.field === 'action') { + const found = innerRules.find((_, index) => index === idx); + if (!found) return; + + found.rule_actions = found.rule_actions.filter((_, index) => index !== e.detail.itemIdx); + innerRefresh(innerRules); + } + handleAgentChange(); } @@ -248,13 +256,10 @@ } found.rule_criteria.disabled = !e.detail.checked; } else if (field === 'action') { - if (!found.rule_action) { - found.rule_action = { - name: '', - disabled: false - }; + const foundAction = found.rule_actions?.find((_, index) => index === e.detail.itemIdx); + if (foundAction) { + foundAction.disabled = !e.detail.checked; } - found.rule_action.disabled = !e.detail.checked; } innerRefresh(innerRules); @@ -274,6 +279,29 @@ handleAgentChange(); } + /** + * @param {any} e + * @param {number} uid + */ + function addRuleItem(e, uid) { + const found = innerRules.find((_, index) => index === uid); + if (!found) return; + + if (e.detail.field === 'action') { + found.rule_actions = [ + ...found.rule_actions, + { + name: '', + disabled: false, + config: {} + } + ]; + } + + innerRefresh(innerRules); + handleAgentChange(); + } + /** * @param {import("$agentTypes").AgentRule} rule */ @@ -408,8 +436,9 @@ actionOptions={actionOptions} windowWidth={windowWidth} on:toggle={e => toggleRule(e, uid)} - on:delete={() => deleteRule(uid)} + on:delete={e => deleteRule(e, uid)} on:change={e => changeRule(e, uid)} + on:add={e => addRuleItem(e, uid)} on:compile={e => compileCodeScript(e.detail.rule)} on:collapse={e => toggleCollapse(e, uid)} /> diff --git a/src/routes/page/agent/[agentId]/agent-tabs.svelte b/src/routes/page/agent/[agentId]/agent-tabs.svelte index eb3c9c9c..43370a7c 100644 --- a/src/routes/page/agent/[agentId]/agent-tabs.svelte +++ b/src/routes/page/agent/[agentId]/agent-tabs.svelte @@ -60,7 +60,7 @@ ]; onMount(() => { - selectedTab = tabs[0]?.name; + selectedTab = tabs[4]?.name; }); /** @param {string} selected */ From 1c7e074636e25805afcee9d41ec3854cfeddfa8e Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Thu, 19 Feb 2026 14:50:26 -0600 Subject: [PATCH 15/21] add skipping expression --- src/lib/helpers/types/agentTypes.js | 1 + src/lib/services/agent-service.js | 4 +-- .../rules/agent-rule-item.svelte | 26 +++++++++++++++-- .../agent-components/rules/agent-rule.svelte | 28 ++++++++++++++----- .../page/agent/[agentId]/agent-tabs.svelte | 2 +- 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/lib/helpers/types/agentTypes.js b/src/lib/helpers/types/agentTypes.js index 7f8569e9..702451ee 100644 --- a/src/lib/helpers/types/agentTypes.js +++ b/src/lib/helpers/types/agentTypes.js @@ -252,6 +252,7 @@ * @property {string?} [name] * @property {boolean} disabled * @property {any} [config] + * @property {string?} [skippingExpression] */ diff --git a/src/lib/services/agent-service.js b/src/lib/services/agent-service.js index a21c7c1d..fcdb08c9 100644 --- a/src/lib/services/agent-service.js +++ b/src/lib/services/agent-service.js @@ -117,7 +117,7 @@ export async function getAgentRuleOptions() { /** * Get agent rule criteria providers - * @returns {Promise} + * @returns {Promise} */ export async function getAgentRuleCriteriaProviders() { const url = endpoints.agentRuleCriteriaProvidersUrl; @@ -127,7 +127,7 @@ export async function getAgentRuleCriteriaProviders() { /** * Get agent rule actions - * @returns {Promise} + * @returns {Promise} */ export async function getAgentRuleActions() { const url = endpoints.agentRuleActionsUrl; diff --git a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte index 08a91c33..665b306e 100644 --- a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte @@ -38,7 +38,6 @@ export let windowWidth; - /** * @param {any} e * @param {string} field @@ -242,7 +241,7 @@ on:change={e => changeRule(e, 'criteria')} > {#each [...criteriaOptions] as option} - {/each} @@ -371,7 +370,7 @@ on:change={e => changeRuleAction(e, 'action', aid)} > {#each [...actionOptions] as option} - {/each} @@ -389,6 +388,27 @@
{#if action?.name} +
+
+
+
+ {'Skipping'} +
+
+
+
+
+ changeRuleAction(e, 'action-skipping-expression', aid)} + /> +
+
+
+
diff --git a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte index daa47124..612556c6 100644 --- a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte @@ -119,9 +119,10 @@ function loadAgentRuleActions() { return new Promise((resolve, reject) => { getAgentRuleActions().then(data => { - const list = data?.map(x => ({ name: x })) || []; + const list = data?.map(x => ({ name: x.key, defaultConfig: x.value })) || []; actionOptions = [{ - name: "" + name: "", + defaultConfig: "" }, ...list]; resolve('done'); }); @@ -131,9 +132,10 @@ function loadAgentRuleCriteriaProviders() { return new Promise((resolve, reject) => { getAgentRuleCriteriaProviders().then(data => { - const list = data?.map(x => ({ name: x })) || []; + const list = data?.map(x => ({ name: x.key, defaultConfig: x.value })) || []; criteriaOptions = [{ - name: "" + name: "", + defaultConfig: "" }, ...list]; resolve('done'); }); @@ -154,10 +156,13 @@ found.trigger_name = value; innerRefresh(innerRules); } else if (field === 'criteria') { + const name = value.split('#')[0]; + const defaultConfig = value.split('#')[1]; found.rule_criteria = { ...found.rule_criteria || {}, - name: value, - disabled: found.rule_criteria?.disabled || false + name: name, + disabled: found.rule_criteria?.disabled || false, + config: JSON.parse(defaultConfig || '{}') }; innerRefresh(innerRules); } else if (field === 'criteria-text') { @@ -186,7 +191,10 @@ } else if (field === 'action') { const foundAction = found.rule_actions?.find((_, index) => index === e.detail.itemIdx); if (foundAction) { - foundAction.name = value; + const name = value.split('#')[0]; + const defaultConfig = value.split('#')[1]; + foundAction.name = name; + foundAction.config = JSON.parse(defaultConfig || '{}'); } innerRefresh(innerRules); } else if (field === 'action-config') { @@ -198,6 +206,12 @@ // ignore invalid JSON while typing } } + } else if (field === 'action-skipping-expression') { + const foundAction = found.rule_actions?.find((_, index) => index === e.detail.itemIdx); + if (foundAction) { + foundAction.skippingExpression = value; + } + innerRefresh(innerRules); } handleAgentChange(); diff --git a/src/routes/page/agent/[agentId]/agent-tabs.svelte b/src/routes/page/agent/[agentId]/agent-tabs.svelte index 43370a7c..eb3c9c9c 100644 --- a/src/routes/page/agent/[agentId]/agent-tabs.svelte +++ b/src/routes/page/agent/[agentId]/agent-tabs.svelte @@ -60,7 +60,7 @@ ]; onMount(() => { - selectedTab = tabs[4]?.name; + selectedTab = tabs[0]?.name; }); /** @param {string} selected */ From 28698530e2fd3a271a117c8fed2355834e08d3f7 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Thu, 26 Feb 2026 12:03:40 -0600 Subject: [PATCH 16/21] reverse icon --- .../agent-components/llm-configs/llm-basic-config.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/page/agent/[agentId]/agent-components/llm-configs/llm-basic-config.svelte b/src/routes/page/agent/[agentId]/agent-components/llm-configs/llm-basic-config.svelte index 833cab06..a1cda369 100644 --- a/src/routes/page/agent/[agentId]/agent-components/llm-configs/llm-basic-config.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/llm-configs/llm-basic-config.svelte @@ -101,7 +101,7 @@ on:keydown={(e) => e.key === 'Enter' && (collapsed = !collapsed)} >
- + {title}
From 6bf25ee0fc989988760e03aed68d23b724b4edf9 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 2 Mar 2026 14:32:04 -0600 Subject: [PATCH 17/21] remove agent rule actions and configs --- src/lib/helpers/http.js | 1 - src/lib/helpers/types/agentTypes.js | 9 - src/lib/services/agent-service.js | 10 -- src/lib/services/api-endpoints.js | 1 - .../rules/agent-rule-item.svelte | 168 ------------------ .../agent-components/rules/agent-rule.svelte | 72 +------- 6 files changed, 3 insertions(+), 258 deletions(-) diff --git a/src/lib/helpers/http.js b/src/lib/helpers/http.js index f5f52bdd..3b3138db 100644 --- a/src/lib/helpers/http.js +++ b/src/lib/helpers/http.js @@ -235,7 +235,6 @@ function skipLoader(config) { new RegExp('http(s*)://(.*?)/agent/(.*?)/code-scripts', 'g'), new RegExp('http(s*)://(.*?)/rule/triggers', 'g'), new RegExp('http(s*)://(.*?)/rule/criteria-providers', 'g'), - new RegExp('http(s*)://(.*?)/rule/actions', 'g'), new RegExp('http(s*)://(.*?)/conversation/state/keys', 'g'), new RegExp('http(s*)://(.*?)/conversation/(.*?)/files/(.*?)', 'g'), new RegExp('http(s*)://(.*?)/llm-configs', 'g'), diff --git a/src/lib/helpers/types/agentTypes.js b/src/lib/helpers/types/agentTypes.js index 702451ee..476a920c 100644 --- a/src/lib/helpers/types/agentTypes.js +++ b/src/lib/helpers/types/agentTypes.js @@ -232,7 +232,6 @@ * @property {string?} [displayName] * @property {boolean} disabled * @property {AgentRuleCriteria?} [rule_criteria] - * @property {AgentRuleAction[]} rule_actions * @property {any?} [output_args] * @property {string?} [json_args] * @property {string?} [statement] @@ -247,14 +246,6 @@ * @property {any} [config] */ -/** - * @typedef {Object} AgentRuleAction - * @property {string?} [name] - * @property {boolean} disabled - * @property {any} [config] - * @property {string?} [skippingExpression] - */ - /** * @typedef {Object} AgentTaskSearchOption diff --git a/src/lib/services/agent-service.js b/src/lib/services/agent-service.js index fcdb08c9..1f3a760b 100644 --- a/src/lib/services/agent-service.js +++ b/src/lib/services/agent-service.js @@ -125,16 +125,6 @@ export async function getAgentRuleCriteriaProviders() { return response.data; } -/** - * Get agent rule actions - * @returns {Promise} - */ -export async function getAgentRuleActions() { - const url = endpoints.agentRuleActionsUrl; - const response = await axios.get(url); - return response.data; -} - /** * Get agent labels * @param {number?} [size] diff --git a/src/lib/services/api-endpoints.js b/src/lib/services/api-endpoints.js index 88aee7f2..4387da10 100644 --- a/src/lib/services/api-endpoints.js +++ b/src/lib/services/api-endpoints.js @@ -41,7 +41,6 @@ export const endpoints = { agentUtilityOptionsUrl: `${host}/agent/utility/options`, agentRuleOptionsUrl: `${host}/rule/triggers`, agentRuleCriteriaProvidersUrl: `${host}/rule/criteria-providers`, - agentRuleActionsUrl: `${host}/rule/actions`, agentLabelsUrl: `${host}/agent/labels`, // agent code script: diff --git a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte index 665b306e..9733ec7f 100644 --- a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte @@ -11,7 +11,6 @@ const duration = 200; const textLimit = 1024; - const actionLimit = 10; /** @type {import('$agentTypes').AgentRule} */ export let rule; @@ -31,9 +30,6 @@ /** @type {any[]} */ export let criteriaOptions = []; - /** @type {any[]} */ - export let actionOptions = []; - /** @type {number} */ export let windowWidth; @@ -62,44 +58,6 @@ }); } - /** - * @param {any} e - * @param {string} field - * @param {number} idx - */ - function toggleRuleAction(e, field, idx) { - svelteDispatch('toggle', { - ruleIdx: ruleIndex, - field: field, - itemIdx: idx, - checked: e.target.checked - }); - } - - /** - * @param {any} e - * @param {string} field - * @param {number} idx - */ - function changeRuleAction(e, field, idx) { - svelteDispatch('change', { - ruleIdx: ruleIndex, - field: field, - itemIdx: idx, - value: e?.target?.value || e?.detail?.text || '' - }); - } - - /** - * @param {string} field - */ - function addRuleItem(field) { - svelteDispatch('add', { - ruleIdx: ruleIndex, - field: field - }); - } - /** * @param {string} field */ @@ -110,18 +68,6 @@ }); } - /** - * @param {string} field - * @param {number} idx - */ - function deleteRuleItem(field, idx) { - svelteDispatch('delete', { - ruleIdx: ruleIndex, - field: field, - itemIdx: idx - }); - } - function toggleCollapse() { svelteDispatch('collapse', { ruleIdx: ruleIndex, @@ -343,119 +289,5 @@ {/if}
- -
- {#each rule.rule_actions || [] as action, aid (aid)} -
0 ? 'border-top-style: none' : ''}`}> -
-
-
-
- {`Action #${aid + 1}`} -
-
- toggleRuleAction(e, 'action', aid)} - /> -
-
-
-
-
- changeRuleAction(e, 'action', aid)} - > - {#each [...actionOptions] as option} - - {/each} - -
-
- {}} - on:click={() => deleteRuleItem('action', aid)} - /> -
-
-
- {#if action?.name} -
-
-
-
- {'Skipping'} -
-
-
-
-
- changeRuleAction(e, 'action-skipping-expression', aid)} - /> -
-
-
-
-
-
-
-
- {'Config'} -
-
-
-
-
- changeRuleAction(e, 'action-config', aid)} - /> -
-
-
-
- {/if} -
- {/each} - - {#if rule.rule_actions?.length < actionLimit} -
-
-
- {rule.rule_actions.length === 0 ? 'Actions' : ''} -
-
- {}} - on:click={() => addRuleItem('action')} - /> -
-
-
- {/if} -
{/if}
\ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte index 612556c6..a33abadd 100644 --- a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte @@ -3,7 +3,7 @@ import Swal from 'sweetalert2'; import { Card, CardBody, Button } from '@sveltestrap/sveltestrap'; import { AI_PROGRAMMER_AGENT_ID, RULE_TRIGGER_CODE_GENERATE_TEMPLATE } from '$lib/helpers/constants'; - import { getAgentRuleOptions, generateAgentCodeScript, getAgentRuleActions, getAgentRuleCriteriaProviders } from '$lib/services/agent-service'; + import { getAgentRuleOptions, generateAgentCodeScript, getAgentRuleCriteriaProviders } from '$lib/services/agent-service'; import LoadingToComplete from '$lib/common/spinners/LoadingToComplete.svelte'; import { AgentCodeScriptType } from '$lib/helpers/enums'; import { scrollToBottom } from '$lib/helpers/utils/common'; @@ -41,7 +41,6 @@ trigger_name: x.trigger_name, disabled: x.disabled, rule_criteria: x.rule_criteria, - rule_actions: x.rule_actions.filter(x => !!x.name), expanded: x.expanded }; }); @@ -66,9 +65,6 @@ /** @type {any[]} */ let criteriaOptions = []; - /** @type {any[]} */ - let actionOptions = []; - /** @type {import('$agentTypes').AgentRule[]} */ let innerRules = []; @@ -79,8 +75,7 @@ resizeWindow(); Promise.all([ loadAgentRuleOptions(), - loadAgentRuleCriteriaProviders(), - loadAgentRuleActions() + loadAgentRuleCriteriaProviders() ]); }); @@ -116,19 +111,6 @@ innerRefresh(list); } - function loadAgentRuleActions() { - return new Promise((resolve, reject) => { - getAgentRuleActions().then(data => { - const list = data?.map(x => ({ name: x.key, defaultConfig: x.value })) || []; - actionOptions = [{ - name: "", - defaultConfig: "" - }, ...list]; - resolve('done'); - }); - }); - } - function loadAgentRuleCriteriaProviders() { return new Promise((resolve, reject) => { getAgentRuleCriteriaProviders().then(data => { @@ -188,30 +170,6 @@ } catch { // ignore invalid JSON while typing } - } else if (field === 'action') { - const foundAction = found.rule_actions?.find((_, index) => index === e.detail.itemIdx); - if (foundAction) { - const name = value.split('#')[0]; - const defaultConfig = value.split('#')[1]; - foundAction.name = name; - foundAction.config = JSON.parse(defaultConfig || '{}'); - } - innerRefresh(innerRules); - } else if (field === 'action-config') { - const foundAction = found.rule_actions?.find((_, index) => index === e.detail.itemIdx); - if (foundAction) { - try { - foundAction.config = JSON.parse(value || '{}'); - } catch { - // ignore invalid JSON while typing - } - } - } else if (field === 'action-skipping-expression') { - const foundAction = found.rule_actions?.find((_, index) => index === e.detail.itemIdx); - if (foundAction) { - foundAction.skippingExpression = value; - } - innerRefresh(innerRules); } handleAgentChange(); @@ -224,8 +182,7 @@ trigger_name: '', displayName: '', disabled: false, - expanded: true, - rule_actions: [] + expanded: true } ]; scrollToBottom(scrollContainer); @@ -239,12 +196,6 @@ function deleteRule(e, idx) { if (e.detail.field === 'rule') { innerRules = innerRules.filter((_, index) => index !== idx); - } else if (e.detail.field === 'action') { - const found = innerRules.find((_, index) => index === idx); - if (!found) return; - - found.rule_actions = found.rule_actions.filter((_, index) => index !== e.detail.itemIdx); - innerRefresh(innerRules); } handleAgentChange(); @@ -269,11 +220,6 @@ }; } found.rule_criteria.disabled = !e.detail.checked; - } else if (field === 'action') { - const foundAction = found.rule_actions?.find((_, index) => index === e.detail.itemIdx); - if (foundAction) { - foundAction.disabled = !e.detail.checked; - } } innerRefresh(innerRules); @@ -300,17 +246,6 @@ function addRuleItem(e, uid) { const found = innerRules.find((_, index) => index === uid); if (!found) return; - - if (e.detail.field === 'action') { - found.rule_actions = [ - ...found.rule_actions, - { - name: '', - disabled: false, - config: {} - } - ]; - } innerRefresh(innerRules); handleAgentChange(); @@ -447,7 +382,6 @@ user={user} ruleOptions={ruleOptions} criteriaOptions={criteriaOptions} - actionOptions={actionOptions} windowWidth={windowWidth} on:toggle={e => toggleRule(e, uid)} on:delete={e => deleteRule(e, uid)} From 6a13012564836f4a0c8783d1404a409a512bc694 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Thu, 5 Mar 2026 17:41:40 -0600 Subject: [PATCH 18/21] add rule config --- src/lib/common/modals/PlainModal.svelte | 7 +- src/lib/helpers/types/agentTypes.js | 10 - src/lib/scss/custom/pages/_agent.scss | 14 + src/lib/services/agent-service.js | 6 +- src/lib/services/api-endpoints.js | 2 +- .../rules/agent-rule-item.svelte | 30 +- .../agent-components/rules/agent-rule.svelte | 325 ++++++++++-------- .../page/agent/[agentId]/agent-tabs.svelte | 2 +- 8 files changed, 235 insertions(+), 161 deletions(-) diff --git a/src/lib/common/modals/PlainModal.svelte b/src/lib/common/modals/PlainModal.svelte index 9ffd6d97..27851df9 100644 --- a/src/lib/common/modals/PlainModal.svelte +++ b/src/lib/common/modals/PlainModal.svelte @@ -1,5 +1,5 @@ @@ -30,7 +33,7 @@ toggle={() => toggleModal()} unmountOnClose > - + \ No newline at end of file diff --git a/src/lib/helpers/types/agentTypes.js b/src/lib/helpers/types/agentTypes.js index 476a920c..55360495 100644 --- a/src/lib/helpers/types/agentTypes.js +++ b/src/lib/helpers/types/agentTypes.js @@ -231,22 +231,12 @@ * @property {string} trigger_name * @property {string?} [displayName] * @property {boolean} disabled - * @property {AgentRuleCriteria?} [rule_criteria] * @property {any?} [output_args] * @property {string?} [json_args] * @property {string?} [statement] * @property {boolean} [expanded] */ -/** - * @typedef {Object} AgentRuleCriteria - * @property {string?} [name] - * @property {string?} [criteria_text] - * @property {boolean} disabled - * @property {any} [config] - */ - - /** * @typedef {Object} AgentTaskSearchOption * @property {string?} [agentId] diff --git a/src/lib/scss/custom/pages/_agent.scss b/src/lib/scss/custom/pages/_agent.scss index 61c1815e..e6d35154 100644 --- a/src/lib/scss/custom/pages/_agent.scss +++ b/src/lib/scss/custom/pages/_agent.scss @@ -338,6 +338,20 @@ max-height: 200px; } +.rule-config-modal { + .modal-content { + width: 1400px; + max-width: calc(100vw - 2rem); + height: 80vh; + margin: 0 auto; + } + + .modal-body { + height: 100%; + box-sizing: border-box; + } +} + .code-editor { max-height: 500px; overflow-y: auto; diff --git a/src/lib/services/agent-service.js b/src/lib/services/agent-service.js index 1f3a760b..86b48b85 100644 --- a/src/lib/services/agent-service.js +++ b/src/lib/services/agent-service.js @@ -117,10 +117,10 @@ export async function getAgentRuleOptions() { /** * Get agent rule criteria providers - * @returns {Promise} + * @returns {Promise} */ -export async function getAgentRuleCriteriaProviders() { - const url = endpoints.agentRuleCriteriaProvidersUrl; +export async function getAgentRuleConfigOptions() { + const url = endpoints.agentRuleConfigOptionsUrl; const response = await axios.get(url); return response.data; } diff --git a/src/lib/services/api-endpoints.js b/src/lib/services/api-endpoints.js index 4387da10..84ad5179 100644 --- a/src/lib/services/api-endpoints.js +++ b/src/lib/services/api-endpoints.js @@ -40,7 +40,7 @@ export const endpoints = { agentCreateUrl: `${host}/agent`, agentUtilityOptionsUrl: `${host}/agent/utility/options`, agentRuleOptionsUrl: `${host}/rule/triggers`, - agentRuleCriteriaProvidersUrl: `${host}/rule/criteria-providers`, + agentRuleConfigOptionsUrl: `${host}/rule/config/options`, agentLabelsUrl: `${host}/agent/labels`, // agent code script: diff --git a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte index 9733ec7f..b090156f 100644 --- a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule-item.svelte @@ -27,8 +27,8 @@ /** @type {any[]} */ export let ruleOptions = []; - /** @type {any[]} */ - export let criteriaOptions = []; + /** @type {any} */ + export let configOptions = {}; /** @type {number} */ export let windowWidth; @@ -80,6 +80,12 @@ rule: rule }); } + + function toggleConfig() { + svelteDispatch('config', { + ruleIdx: ruleIndex + }); + }
@@ -133,6 +139,22 @@
{/if} + + {#if ADMIN_ROLES.includes(user?.role || '') && !!rule.trigger_name && Object.keys(configOptions || {}).length > 0} + +
+ + toggleConfig()} + /> +
+ {/if}
@@ -164,7 +186,7 @@ {#if !collapsed}
-
+
{/if} diff --git a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte index a33abadd..02b56180 100644 --- a/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte +++ b/src/routes/page/agent/[agentId]/agent-components/rules/agent-rule.svelte @@ -3,11 +3,12 @@ import Swal from 'sweetalert2'; import { Card, CardBody, Button } from '@sveltestrap/sveltestrap'; import { AI_PROGRAMMER_AGENT_ID, RULE_TRIGGER_CODE_GENERATE_TEMPLATE } from '$lib/helpers/constants'; - import { getAgentRuleOptions, generateAgentCodeScript, getAgentRuleCriteriaProviders } from '$lib/services/agent-service'; + import { getAgentRuleOptions, generateAgentCodeScript, getAgentRuleConfigOptions } from '$lib/services/agent-service'; import LoadingToComplete from '$lib/common/spinners/LoadingToComplete.svelte'; import { AgentCodeScriptType } from '$lib/helpers/enums'; import { scrollToBottom } from '$lib/helpers/utils/common'; import AgentRuleItem from './agent-rule-item.svelte'; + import PlainModal from '$lib/common/modals/PlainModal.svelte'; const limit = 100; @@ -17,6 +18,9 @@ let isComplete = false; /** @type {boolean} */ let isError = false; + /** @type {boolean} */ + let isOpenConfigModal = false; + /** @type {number} */ let duration = 2000; let windowWidth = 0; @@ -26,6 +30,9 @@ let successText = ''; let errorText = ''; + /** @type {any} */ + let ruleConfig = {}; + /** @type {import('$agentTypes').AgentModel} */ export let agent; @@ -40,7 +47,6 @@ return { trigger_name: x.trigger_name, disabled: x.disabled, - rule_criteria: x.rule_criteria, expanded: x.expanded }; }); @@ -62,8 +68,8 @@ /** @type {any[]} */ let ruleOptions = []; - /** @type {any[]} */ - let criteriaOptions = []; + /** @type {any} */ + let configOptions = {}; /** @type {import('$agentTypes').AgentRule[]} */ let innerRules = []; @@ -75,12 +81,12 @@ resizeWindow(); Promise.all([ loadAgentRuleOptions(), - loadAgentRuleCriteriaProviders() + loadAgentRuleConfigOptions() ]); }); function loadAgentRuleOptions() { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { getAgentRuleOptions().then(data => { const list = data?.map(x => { return { @@ -111,14 +117,10 @@ innerRefresh(list); } - function loadAgentRuleCriteriaProviders() { - return new Promise((resolve, reject) => { - getAgentRuleCriteriaProviders().then(data => { - const list = data?.map(x => ({ name: x.key, defaultConfig: x.value })) || []; - criteriaOptions = [{ - name: "", - defaultConfig: "" - }, ...list]; + function loadAgentRuleConfigOptions() { + return new Promise((resolve) => { + getAgentRuleConfigOptions().then(data => { + configOptions = data || {}; resolve('done'); }); }); @@ -137,40 +139,42 @@ if (field === 'rule') { found.trigger_name = value; innerRefresh(innerRules); - } else if (field === 'criteria') { - const name = value.split('#')[0]; - const defaultConfig = value.split('#')[1]; - found.rule_criteria = { - ...found.rule_criteria || {}, - name: name, - disabled: found.rule_criteria?.disabled || false, - config: JSON.parse(defaultConfig || '{}') - }; - innerRefresh(innerRules); - } else if (field === 'criteria-text') { - if (found.rule_criteria == null) { - found.rule_criteria = { - name: '', - disabled: false, - config: {} - }; - } - found.rule_criteria.criteria_text = value; - innerRefresh(innerRules); - } else if (field === 'criteria-config') { - if (found.rule_criteria == null) { - found.rule_criteria = { - name: '', - disabled: false, - config: {} - }; - } - try { - found.rule_criteria.config = JSON.parse(value || '{}'); - } catch { - // ignore invalid JSON while typing - } - } + } + + // else if (field === 'criteria') { + // const name = value.split('#')[0]; + // const defaultConfig = value.split('#')[1]; + // found.rule_criteria = { + // ...found.rule_criteria || {}, + // name: name, + // disabled: found.rule_criteria?.disabled || false, + // config: JSON.parse(defaultConfig || '{}') + // }; + // innerRefresh(innerRules); + // } else if (field === 'criteria-text') { + // if (found.rule_criteria == null) { + // found.rule_criteria = { + // name: '', + // disabled: false, + // config: {} + // }; + // } + // found.rule_criteria.criteria_text = value; + // innerRefresh(innerRules); + // } else if (field === 'criteria-config') { + // if (found.rule_criteria == null) { + // found.rule_criteria = { + // name: '', + // disabled: false, + // config: {} + // }; + // } + // try { + // found.rule_criteria.config = JSON.parse(value || '{}'); + // } catch { + // // ignore invalid JSON while typing + // } + // } handleAgentChange(); } @@ -212,16 +216,18 @@ const field = e.detail.field; if (field === 'rule') { found.disabled = !e.detail.checked; - } else if (field === 'criteria') { - if (!found.rule_criteria) { - found.rule_criteria = { - name: '', - disabled: false - }; - } - found.rule_criteria.disabled = !e.detail.checked; } + // else if (field === 'criteria') { + // if (!found.rule_criteria) { + // found.rule_criteria = { + // name: '', + // disabled: false + // }; + // } + // found.rule_criteria.disabled = !e.detail.checked; + // } + innerRefresh(innerRules); handleAgentChange(); } @@ -251,78 +257,78 @@ handleAgentChange(); } - /** - * @param {import("$agentTypes").AgentRule} rule - */ - function compileCodeScript(rule) { - if (!!rule.rule_criteria?.disabled) { - return; - } - - Swal.fire({ - title: 'Are you sure?', - html: ` -
-

Are you sure you want to generate code script "${buildScriptName(rule.trigger_name)}"?

-

This action will overwrite existing code script if any.

-
- `, - icon: 'warning', - showCancelButton: true, - cancelButtonText: 'No', - confirmButtonText: 'Yes' - }).then(async (result) => { - if (result.value) { - generateCodeScript(rule); - } - }); - } - - /** - * @param {import("$agentTypes").AgentRule} rule - */ - function generateCodeScript(rule) { - return new Promise((resolve, reject) => { - isLoading = true; - generateAgentCodeScript(agent.id, { - text: '', - options: { - agent_id: AI_PROGRAMMER_AGENT_ID, - template_name: RULE_TRIGGER_CODE_GENERATE_TEMPLATE, - save_to_db: true, - script_name: buildScriptName(rule.trigger_name), - script_type: AgentCodeScriptType.Src, - data: { - 'args_example': { ...rule.output_args }, - 'user_request': rule.rule_criteria?.criteria_text - } - } - }).then(res => { - if (res?.success) { - isLoading = false; - isComplete = true; - successText = "Code script has been generated!"; - setTimeout(() => { - isComplete = false; - successText = ""; - }, duration); - resolve(res); - } else { - throw "error when generating code script."; - } - }).catch(() => { - isLoading = false; - isComplete = false; - isError = true; - errorText = "Failed to generate code script."; - setTimeout(() => { - isError = false; - errorText = ""; - }, duration); - reject(); - }); - }); - } + // /** + // * @param {import("$agentTypes").AgentRule} rule + // */ + // function compileCodeScript(rule) { + // if (!!rule.rule_criteria?.disabled) { + // return; + // } + + // Swal.fire({ + // title: 'Are you sure?', + // html: ` + //
+ //

Are you sure you want to generate code script "${buildScriptName(rule.trigger_name)}"?

+ //

This action will overwrite existing code script if any.

+ //
+ // `, + // icon: 'warning', + // showCancelButton: true, + // cancelButtonText: 'No', + // confirmButtonText: 'Yes' + // }).then(async (result) => { + // if (result.value) { + // generateCodeScript(rule); + // } + // }); + // } + + // /** + // * @param {import("$agentTypes").AgentRule} rule + // */ + // function generateCodeScript(rule) { + // return new Promise((resolve, reject) => { + // isLoading = true; + // generateAgentCodeScript(agent.id, { + // text: '', + // options: { + // agent_id: AI_PROGRAMMER_AGENT_ID, + // template_name: RULE_TRIGGER_CODE_GENERATE_TEMPLATE, + // save_to_db: true, + // script_name: buildScriptName(rule.trigger_name), + // script_type: AgentCodeScriptType.Src, + // data: { + // 'args_example': { ...rule.output_args }, + // 'user_request': rule.rule_criteria?.criteria_text + // } + // } + // }).then(res => { + // if (res?.success) { + // isLoading = false; + // isComplete = true; + // successText = "Code script has been generated!"; + // setTimeout(() => { + // isComplete = false; + // successText = ""; + // }, duration); + // resolve(res); + // } else { + // throw "error when generating code script."; + // } + // }).catch(() => { + // isLoading = false; + // isComplete = false; + // isError = true; + // errorText = "Failed to generate code script."; + // setTimeout(() => { + // isError = false; + // errorText = ""; + // }, duration); + // reject(); + // }); + // }); + // } /** @param {import('$agentTypes').AgentRule[]} list */ @@ -338,16 +344,43 @@ }) || []; } - /** @param {string} name */ - function buildScriptName(name) { - let scriptName = name?.trim(); - if (!name) { - scriptName = 'unknown_rule.py'; - } else { - scriptName = `${scriptName.replace(/\s+/g, "_")}_rule.py`; - } + // /** @param {string} name */ + // function buildScriptName(name) { + // let scriptName = name?.trim(); + // if (!name) { + // scriptName = 'unknown_rule.py'; + // } else { + // scriptName = `${scriptName.replace(/\s+/g, "_")}_rule.py`; + // } - return scriptName; + // return scriptName; + // } + + /** + * @param {any} e + * @param {number} uid + */ + function openRuleConfigModal(e, uid) { + const found = innerRules.find((_, index) => index === uid); + if (!found) return; + + const graph = configOptions['membase']; + const params = JSON.stringify({ + agent: agent.name, + agent_id: agent.id, + trigger: found.trigger_name || "" + }); + const url = new URL(graph.url, window.location.origin); + url.searchParams.set('parameters', params); + console.log(url.toString()); + + ruleConfig = { + url: url.toString(), + rule: found, + title: `${found.trigger_name} config` + }; + + isOpenConfigModal = true; } function resizeWindow() { @@ -366,6 +399,18 @@ {errorText} /> +{#if isOpenConfigModal} + isOpenConfigModal = !isOpenConfigModal} + > +