diff --git a/package-lock.json b/package-lock.json index d00fdd51..7a7d36c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,12 @@ "name": "botsharp-ui", "version": "1.0.0", "dependencies": { + "@codemirror/commands": "^6.10.0", + "@codemirror/lang-python": "^6.2.1", + "@codemirror/language": "^6.11.3", + "@codemirror/state": "^6.5.2", + "@codemirror/theme-one-dark": "^6.1.3", + "@codemirror/view": "^6.38.6", "@ernane/svelte-star-rating": "^1.1.4", "@fullcalendar/common": "^5.11.5", "@microsoft/signalr": "^8.0.0", @@ -30,6 +36,7 @@ "overlayscrollbars-svelte": "^0.5.2", "qs": "^6.14.0", "svelte-awesome-color-picker": "^2.4.7", + "svelte-codemirror-editor": "^1.4.1", "svelte-collapse": "^0.1.2", "svelte-file-dropzone": "^2.0.2", "svelte-flatpickr": "^3.3.3", @@ -100,9 +107,9 @@ } }, "node_modules/@codemirror/commands": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.6.0.tgz", - "integrity": "sha512-qnY+b7j1UNcTS31Eenuc/5YJB6gQOzkUoNmJQc0rznwqSRpeaWWpjkWy2C/MPTcePpsKJEM26hXrOXl1+nceXg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.0.tgz", + "integrity": "sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==", "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.4.0", @@ -119,10 +126,22 @@ "@lezer/json": "^1.0.0" } }, + "node_modules/@codemirror/lang-python": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.2.1.tgz", + "integrity": "sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw==", + "dependencies": { + "@codemirror/autocomplete": "^6.3.2", + "@codemirror/language": "^6.8.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/python": "^1.1.4" + } + }, "node_modules/@codemirror/language": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.2.tgz", - "integrity": "sha512-kgbTYTo0Au6dCSc/TFy7fK3fpJmgHDv1sG1KNQKJXVi+xBTEeBPY/M30YXiU6mMXeH+YIDLsbrT4ZwNRdtF+SA==", + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz", + "integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==", "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", @@ -153,16 +172,31 @@ } }, "node_modules/@codemirror/state": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz", - "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==" + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz", + "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz", + "integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } }, "node_modules/@codemirror/view": { - "version": "6.29.1", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.29.1.tgz", - "integrity": "sha512-7r+DlO/QFwPqKp73uq5mmrS4TuLPUVotbNOKYzN3OLP5ScrOVXcm4g13/48b6ZXGhdmzMinzFYqH0vo+qihIkQ==", + "version": "6.38.6", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.6.tgz", + "integrity": "sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw==", "dependencies": { - "@codemirror/state": "^6.4.0", + "@codemirror/state": "^6.5.0", + "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } @@ -845,6 +879,21 @@ "@lezer/common": "^1.0.0" } }, + "node_modules/@lezer/python": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.18.tgz", + "integrity": "sha512-31FiUrU7z9+d/ElGQLJFXl+dKOdx0jALlP3KEOsGTex8mvj+SoE1FgItcHWK/axkxCHGUSpqIHt6JAWfWu9Rhg==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", + "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==" + }, "node_modules/@microsoft/signalr": { "version": "8.0.7", "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-8.0.7.tgz", @@ -1620,6 +1669,21 @@ "periscopic": "^3.1.0" } }, + "node_modules/codemirror": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz", + "integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==", + "peer": true, + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, "node_modules/codemirror-wrapped-line-indent": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/codemirror-wrapped-line-indent/-/codemirror-wrapped-line-indent-1.0.8.tgz", @@ -3941,6 +4005,15 @@ "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0" } }, + "node_modules/svelte-codemirror-editor": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/svelte-codemirror-editor/-/svelte-codemirror-editor-1.4.1.tgz", + "integrity": "sha512-Pv350iro0Y/AZTT/y2OLaonheQqAwl50Hdfipa2Jv1Z04TSP5kPUyxQnRjqxeRW7DXOX9s5Nd11tHdBl9iYSzw==", + "peerDependencies": { + "codemirror": "^6.0.0", + "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, "node_modules/svelte-collapse": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/svelte-collapse/-/svelte-collapse-0.1.2.tgz", diff --git a/package.json b/package.json index bef3fca2..3c8ea925 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,12 @@ }, "type": "module", "dependencies": { + "@codemirror/commands": "^6.10.0", + "@codemirror/lang-python": "^6.2.1", + "@codemirror/language": "^6.11.3", + "@codemirror/state": "^6.5.2", + "@codemirror/theme-one-dark": "^6.1.3", + "@codemirror/view": "^6.38.6", "@ernane/svelte-star-rating": "^1.1.4", "@fullcalendar/common": "^5.11.5", "@microsoft/signalr": "^8.0.0", @@ -59,6 +65,7 @@ "overlayscrollbars-svelte": "^0.5.2", "qs": "^6.14.0", "svelte-awesome-color-picker": "^2.4.7", + "svelte-codemirror-editor": "^1.4.1", "svelte-collapse": "^0.1.2", "svelte-file-dropzone": "^2.0.2", "svelte-flatpickr": "^3.3.3", diff --git a/src/lib/helpers/enums.js b/src/lib/helpers/enums.js index d3b1ef6a..7f70fcc4 100644 --- a/src/lib/helpers/enums.js +++ b/src/lib/helpers/enums.js @@ -77,6 +77,12 @@ const agentType = { }; export const AgentType = Object.freeze(agentType); +const agentCodeScriptType = { + Src: 'src', + Test: 'test' +}; +export const AgentCodeScriptType = Object.freeze(agentCodeScriptType); + const routingMode = { Eager: "eager", Lazy: "lazy" @@ -203,14 +209,34 @@ const globalEvent = { export const GlobalEvent = Object.freeze(globalEvent); const llmModelType = { - Text: 1, - Chat: 2, - Image: 3, - Embedding: 4, - Audio: 5 + All: "All", + Text: "Text", + Chat: "Chat", + Image: "Image", + Embedding: "Embedding", + Audio: "Audio", + Realtime: "Realtime", + Web: "Web" }; export const LlmModelType = Object.freeze(llmModelType); +const llmModelCapability = { + All: "All", + Text: "Text", + Chat: "Chat", + ImageReading: "ImageReading", + ImageGeneration: "ImageGeneration", + ImageEdit: "ImageEdit", + ImageVariation: "ImageVariation", + Embedding: "Embedding", + AudioTranscription: "AudioTranscription", + AudioGeneration: "AudioGeneration", + Realtime: "Realtime", + WebSearch: "WebSearch", + PdfReading: "PdfReading" +}; +export const LlmModelCapability = Object.freeze(llmModelCapability); + const reasoningEffortLevel = { Minimal: "minimal", Low: "low", diff --git a/src/lib/helpers/http.js b/src/lib/helpers/http.js index ac0435ab..8e470866 100644 --- a/src/lib/helpers/http.js +++ b/src/lib/helpers/http.js @@ -74,7 +74,8 @@ function skipLoader(config) { new RegExp('http(s*)://(.*?)/knowledge/vector/(.*?)/create', 'g'), new RegExp('http(s*)://(.*?)/knowledge/document/(.*?)/page', 'g'), new RegExp('http(s*)://(.*?)/users', 'g'), - new RegExp('http(s*)://(.*?)/instruct/chat-completion', 'g') + new RegExp('http(s*)://(.*?)/instruct/chat-completion', 'g'), + new RegExp('http(s*)://(.*?)/agent/(.*?)/code-scripts', 'g') ]; /** @type {RegExp[]} */ diff --git a/src/lib/helpers/types/agentTypes.js b/src/lib/helpers/types/agentTypes.js index 8046926b..28e4a1b3 100644 --- a/src/lib/helpers/types/agentTypes.js +++ b/src/lib/helpers/types/agentTypes.js @@ -18,6 +18,10 @@ * @property {number} max_recursion_depth * @property {number?} [max_output_tokens] * @property {string?} [reasoning_effort_level] + * @property {any} [image_generation] + * @property {any} [image_edit] + * @property {any} [audio_transcription] + * @property {any} [realtime] */ @@ -105,6 +109,34 @@ * @property {string} [direct_agent_id] - Run task directly in this agent. */ +/** + * @typedef {Object} AgentCodeScriptFilter + * @property {string[]?} [scriptNames] + * @property {string[]?} [scriptTypes] + */ + + +/** + * @typedef {Object} AgentCodeScriptViewModel + * @property {string?} [uid] + * @property {string} name + * @property {string} content + * @property {string} script_type + */ + +/** + * @typedef {Object} AgentCodeScriptUpdateOptions + * @property {boolean?} [delete_if_not_included] + * @property {boolean?} [is_upsert] + */ + +/** + * @typedef {Object} AgentCodeScriptUpdateModel + * @property {AgentCodeScriptViewModel[]?} [code_scripts] + * @property {AgentCodeScriptUpdateOptions?} [options] + */ + + /** * @typedef {Object} ChannelInstruction * @property {string} [uid] diff --git a/src/lib/helpers/types/commonTypes.js b/src/lib/helpers/types/commonTypes.js index 038079b5..a97df90b 100644 --- a/src/lib/helpers/types/commonTypes.js +++ b/src/lib/helpers/types/commonTypes.js @@ -39,10 +39,13 @@ */ /** - * @typedef {Object} LlmConfigOption - * @property {number?} [type] + * @typedef {Object} LlmConfigFilter + * @property {string[]?} [providers] + * @property {string[]?} [modelIds] + * @property {string[]?} [modelNames] + * @property {string[]?} [modelTypes] + * @property {string[]?} [modelCapabilities] * @property {boolean?} [multiModal] - * @property {boolean?} [imageGeneration] */ /** @@ -55,6 +58,8 @@ * @typedef {Object} LlmModelSetting * @property {string} name * @property {string} type + * @property {string[]} capabilities + * @property {boolean} multiModal * @property {any} reasoning */ diff --git a/src/lib/helpers/types/knowledgeTypes.js b/src/lib/helpers/types/knowledgeTypes.js index f0ede318..5d105db1 100644 --- a/src/lib/helpers/types/knowledgeTypes.js +++ b/src/lib/helpers/types/knowledgeTypes.js @@ -16,6 +16,7 @@ * @property {number} [confidence] - Confidence. * @property {boolean} [with_vector] - Include vector or not. * @property {VectorFilterGroup[]} [filter_groups] - Search filter groups. + * @property {VectorSearchParam} [search_param] - Search params. */ /** @@ -28,6 +29,11 @@ * @property {VectorSort?} [order_by] - Sort by. */ +/** + * @typedef {Object} VectorSearchParam + * @property {boolean?} [exact_search] - Exact search or not. + */ + /** * @typedef {Object} VectorFilterGroup * @property {string} [logical_operator] - The logical operator. diff --git a/src/lib/scss/custom/pages/_agent.scss b/src/lib/scss/custom/pages/_agent.scss index 15ef802d..c5396a2b 100644 --- a/src/lib/scss/custom/pages/_agent.scss +++ b/src/lib/scss/custom/pages/_agent.scss @@ -143,6 +143,12 @@ } } +.agent-config-container { + padding: 10px; + border: 1px dashed var(--bs-primary); + border-radius: 5px; +} + .agent-utility-container { display: flex; flex-direction: column; @@ -150,6 +156,7 @@ max-height: 500px; overflow-y: auto; scrollbar-width: thin; + padding: 0px 10px; .merge-utility { display: flex; @@ -266,4 +273,17 @@ &.show { opacity: 1 !important; } +} + +.code-editor { + max-height: 500px; + overflow-y: auto; + scrollbar-width: thin; + resize: none; + + .cm-editor { + min-width: 1000px; + overflow-x: auto; + scrollbar-width: thin; + } } \ No newline at end of file diff --git a/src/lib/services/agent-service.js b/src/lib/services/agent-service.js index e0786c91..d4d87e7b 100644 --- a/src/lib/services/agent-service.js +++ b/src/lib/services/agent-service.js @@ -1,5 +1,6 @@ import { endpoints } from '$lib/services/api-endpoints.js'; import axios from 'axios'; +import qs from 'qs'; /** * Get agent settings @@ -114,10 +115,45 @@ export async function getAgentRuleOptions() { /** * Get agent labels + * @param {number?} [size] * @returns {Promise} */ -export async function getAgentLabels() { +export async function getAgentLabels(size = null) { const url = endpoints.agentLabelsUrl; - const response = await axios.get(url); + const response = await axios.get(url, { + params: { size: size } + }); + return response.data; +} + + +/** + * Get agent code scripts + * @param {string} agentId + * @param {import('$agentTypes').AgentCodeScriptFilter?} filter + * @returns {Promise} + */ +export async function getAgentCodeScripts(agentId, filter = null) { + const url = endpoints.agentCodeScriptListUrl.replace("{agentId}", agentId); + const response = await axios.get(url, { + params: { + ...filter + }, + paramsSerializer: (params) => qs.stringify(params, { encode: false, allowDots: true, arrayFormat: "indices" }) + }); return response.data; } + +/** + * Update agent code scripts + * @param {string} agentId + * @param {import('$agentTypes').AgentCodeScriptUpdateModel} update + * @returns {Promise} + */ +export async function updateAgentCodeScripts(agentId, update) { + const url = endpoints.agentCodeScriptUpdateUrl.replace("{agentId}", agentId); + const response = await axios.post(url, { + ...update + }); + return response.data; +} \ No newline at end of file diff --git a/src/lib/services/api-endpoints.js b/src/lib/services/api-endpoints.js index 12ab5ec3..1ee3cc59 100644 --- a/src/lib/services/api-endpoints.js +++ b/src/lib/services/api-endpoints.js @@ -37,6 +37,10 @@ export const endpoints = { agentUtilityOptionsUrl: `${host}/agent/utility/options`, agentRuleOptionsUrl: `${host}/rule/triggers`, agentLabelsUrl: `${host}/agent/labels`, + + // agent code script: + agentCodeScriptListUrl: `${host}/agent/{agentId}/code-scripts`, + agentCodeScriptUpdateUrl: `${host}/agent/{agentId}/code-scripts`, // agent task agentTaskListUrl: `${host}/agent/tasks`, diff --git a/src/lib/services/llm-provider-service.js b/src/lib/services/llm-provider-service.js index 7d15c608..5dbb6749 100644 --- a/src/lib/services/llm-provider-service.js +++ b/src/lib/services/llm-provider-service.js @@ -1,6 +1,7 @@ import { endpoints } from './api-endpoints.js'; import { replaceUrl } from '$lib/helpers/http.js'; import axios from 'axios'; +import qs from 'qs'; /** * Get provider list @@ -26,19 +27,15 @@ export async function getLlmProviderModels(provider) { /** * Get llm configs - * @param {import('$commonTypes').LlmConfigOption?} [options] + * @param {import('$commonTypes').LlmConfigFilter?} [filter] * @returns {Promise} */ -export async function getLlmConfigs(options = null) { +export async function getLlmConfigs(filter = null) { const url = endpoints.llmConfigsUrl; + const params = filter != null ? { filter: filter } : null; const response = await axios.get(url, { - params: { - options: options - }, - paramsSerializer: { - dots: true, - indexes: null, - } + params: params, + paramsSerializer: (params) => qs.stringify(params, { encode: false, allowDots: true, arrayFormat: "indices" }) }); return response.data; } \ No newline at end of file diff --git a/src/routes/page/agent/+page.svelte b/src/routes/page/agent/+page.svelte index 6f658ddd..232607d2 100644 --- a/src/routes/page/agent/+page.svelte +++ b/src/routes/page/agent/+page.svelte @@ -123,7 +123,7 @@ } function getAgentLabelOptions() { - return getAgentLabels().then(res => { + return getAgentLabels(3000).then(res => { agentLabelOptions = res?.map(x => ({ label: x, value: x })) || []; }).catch(() => { agentLabelOptions = []; 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 439a683e..3ba4a5d6 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 @@ -1,9 +1,10 @@
-
LLM Config
+
LLM Configurations
- {#if agent.llm_config?.is_inherit} - Inherited - {/if} -
- -
- -
- changeProvider(e)}> - {#each providers as option} - - {/each} - -
-
- -
- -
- changeModel(e)}> - {#each models as option} - - {/each} - -
-
- -
- -
- validateIntegerInput(e)} - on:change={e => changeMaxRecursiveDepth(e)} - /> -
-
- -
- -
- validateIntegerInput(e)} - on:change={e => changeMaxOutputToken(e)} - /> -
- {#if isReasoningModel} -
- -
- changeReasoningEffortLevel(e)}> - {#each reasonLevelOptions as option} - - {/each} - -
+
+ + + + +
- {/if} \ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-components/llm-configs/chat-config.svelte b/src/routes/page/agent/[agentId]/agent-components/llm-configs/chat-config.svelte new file mode 100644 index 00000000..866d44b8 --- /dev/null +++ b/src/routes/page/agent/[agentId]/agent-components/llm-configs/chat-config.svelte @@ -0,0 +1,217 @@ + + +
+
+
Chat
+ {#if agent.llm_config?.is_inherit} +
+ Inherited +
+ {/if} +
+ +
+ +
+ changeProvider(e)}> + {#each providers as option} + + {/each} + +
+
+ +
+ +
+ changeModel(e)}> + {#each models as option} + + {/each} + +
+
+ +
+ +
+ validateIntegerInput(e)} + on:change={e => changeMaxRecursiveDepth(e)} + /> +
+
+ +
+ +
+ validateIntegerInput(e)} + on:change={e => changeMaxOutputToken(e)} + /> +
+
+ + {#if isReasoningModel} +
+ +
+ changeReasoningEffortLevel(e)}> + {#each reasonLevelOptions as option} + + {/each} + +
+
+ {/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 new file mode 100644 index 00000000..114101e8 --- /dev/null +++ b/src/routes/page/agent/[agentId]/agent-components/llm-configs/llm-basic-config.svelte @@ -0,0 +1,123 @@ + + +
+
+
{title}
+
+ +
+ +
+ changeProvider(e)}> + {#each providers as option} + + {/each} + +
+
+ +
+ +
+ changeModel(e)}> + {#each models as option} + + {/each} + +
+
+
\ No newline at end of file diff --git a/src/routes/page/agent/[agentId]/agent-tabs.svelte b/src/routes/page/agent/[agentId]/agent-tabs.svelte index 25a9fa2c..ac799eb9 100644 --- a/src/routes/page/agent/[agentId]/agent-tabs.svelte +++ b/src/routes/page/agent/[agentId]/agent-tabs.svelte @@ -48,7 +48,7 @@ /** @type {any[]}*/ let tabs = [ - { name: 'agent-llm-config', displayText: 'LLm Config' }, + { name: 'agent-llm-config', displayText: 'LLm Configs' }, { name: 'agent-routing-rule', displayText: 'Routing' }, { name: 'agent-utility', displayText: 'Utilities' }, { name: 'agent-knowledgebase', displayText: 'Knowledge Base' }, diff --git a/src/routes/page/agent/code-scripts/+page.svelte b/src/routes/page/agent/code-scripts/+page.svelte new file mode 100644 index 00000000..a2865f76 --- /dev/null +++ b/src/routes/page/agent/code-scripts/+page.svelte @@ -0,0 +1,221 @@ + + + + + + + + + + +
Agent
+ +
+ + {/if}