Skip to content

Conversation

@iceljc
Copy link
Collaborator

@iceljc iceljc commented Oct 22, 2025

PR Type

Enhancement


Description

  • Refactored LLM configuration into modular components supporting multiple capabilities (chat, image generation, image editing, audio transcription, realtime)

  • Added code scripts page with Python editor supporting source and test scripts management

  • Enhanced knowledge base search with exact search option and elapsed time tracking

  • Updated LLM model filtering to use capability-based approach instead of type-based


Diagram Walkthrough

flowchart LR
  A["Agent LLM Config"] -->|split into| B["Chat Config"]
  A -->|split into| C["Image Generation"]
  A -->|split into| D["Image Edit"]
  A -->|split into| E["Audio Transcription"]
  A -->|split into| F["Realtime Config"]
  G["Code Scripts Page"] -->|uses| H["CodeMirror Editor"]
  H -->|supports| I["Python Scripts"]
  J["Knowledge Search"] -->|enhanced with| K["Exact Search"]
  J -->|enhanced with| L["Elapsed Time Tracking"]
Loading

File Walkthrough

Relevant files
Enhancement
20 files
agent-llm-config.svelte
Refactored LLM config into modular components                       
+37/-172
chat-config.svelte
New chat configuration component with reasoning support   
+217/-0 
image-generation-config.svelte
New image generation configuration component                         
+116/-0 
image-edit-config.svelte
New image editing configuration component                               
+116/-0 
audio-transcription-config.svelte
New audio transcription configuration component                   
+116/-0 
realtime-config.svelte
New realtime configuration component                                         
+116/-0 
+page.svelte
New code scripts page with Python editor                                 
+491/-0 
agent-tabs.svelte
Updated tab label from Config to Configs                                 
+1/-1     
+page.svelte
Added exact search and elapsed time tracking                         
+39/-6   
+page.svelte
Added exact search and elapsed time tracking                         
+39/-6   
+page.svelte
Updated LLM config filter parameter structure                       
+2/-2     
enums.js
Added agent code script types and LLM model capabilities 
+31/-5   
agentTypes.js
Added agent code script types and LLM config properties   
+32/-0   
commonTypes.js
Updated LLM config filter and model setting types               
+8/-3     
knowledgeTypes.js
Added vector search parameter type for exact search           
+6/-0     
agent-service.js
Added agent code scripts API functions                                     
+38/-2   
llm-provider-service.js
Updated LLM config filter parameter handling                         
+6/-9     
api-endpoints.js
Added agent code script endpoints                                               
+4/-0     
_agent.scss
Added styles for config and code editor containers             
+20/-0   
http.js
Added code scripts endpoint to skip loader regex                 
+2/-1     
Formatting
1 files
+page.svelte
Minor code cleanup and formatting                                               
+0/-2     
Configuration changes
2 files
svelte.config.js
Added code scripts route to prerender list                             
+1/-0     
vite.config.js
Added CodeMirror dependencies to optimization config         
+10/-0   
Dependencies
1 files
package.json
Added CodeMirror and svelte-codemirror-editor dependencies
+7/-0     
Additional files
1 files
+page.svelte +1/-1     

@qodo-merge-pro
Copy link

qodo-merge-pro bot commented Oct 22, 2025

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
- [ ] Create ticket/issue <!-- /create_ticket --create_ticket=true -->

</details></td></tr>
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
No custom compliance provided

Follow the guide to enable custom compliance check.

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-merge-pro
Copy link

qodo-merge-pro bot commented Oct 22, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Consolidate duplicated config components into one

Refactor the five new, nearly identical Svelte components for LLM configurations
into a single, reusable component. This generic component should accept props
for customization (like capability and title) and use slots for unique fields,
such as those in the ChatConfig.

Examples:

src/routes/page/agent/[agentId]/agent-components/llm-configs/image-generation-config.svelte [1-119]
<script>
    import { Input } from '@sveltestrap/sveltestrap';
	import { LlmModelCapability } from '$lib/helpers/enums';
    
    /** @type {import('$agentTypes').AgentModel} */
    export let agent;

    /** @type {import('$commonTypes').LlmConfig[]} */
    export let llmConfigs = [];


 ... (clipped 109 lines)
src/routes/page/agent/[agentId]/agent-components/llm-configs/image-edit-config.svelte [1-119]
<script>
    import { Input } from '@sveltestrap/sveltestrap';
	import { LlmModelCapability } from '$lib/helpers/enums';
    
    /** @type {import('$agentTypes').AgentModel} */
    export let agent;

    /** @type {import('$commonTypes').LlmConfig[]} */
    export let llmConfigs = [];


 ... (clipped 109 lines)

Solution Walkthrough:

Before:

// agent-llm-config.svelte
<ChatConfig ... />
<ImageGenerationConfig ... />
<ImageEditConfig ... />
<AudioTranscriptionConfig ... />
<RealtimeConfig ... />

// image-generation-config.svelte (and 3 others are very similar)
<script>
  // ... props: agent, llmConfigs, handleAgentChange
  let config = agent.llm_config?.image_generation || {};
  // ... logic to filter providers and models based on LlmModelCapability.ImageGeneration
  // ... changeProvider, changeModel handlers
</script>
<h6>Image Generation</h6>
<Input type="select" ...> <!-- Provider -->
<Input type="select" ...> <!-- Model -->

// chat-config.svelte
<script>
  // ... similar logic to above, but with extra fields
</script>
<h6>Chat</h6>
<Input ...> <!-- Provider -->
<Input ...> <!-- Model -->
<Input ...> <!-- Max recursive depth -->
<Input ...> <!-- Max output tokens -->

After:

// agent-llm-config.svelte
<GenericConfig title="Chat" capability={LlmModelCapability.Chat} config={agent.llm_config} ...>
  <!-- Extra fields for chat using a slot -->
  <Input ...> <!-- Max recursive depth -->
  <Input ...> <!-- Max output tokens -->
  {#if isReasoningModel}
    <Input ...> <!-- Reasoning effort -->
  {/if}
</GenericConfig>

<GenericConfig title="Image Generation" capability={LlmModelCapability.ImageGeneration} config={agent.llm_config?.image_generation} ... />
<GenericConfig title="Image Edit" capability={LlmModelCapability.ImageEdit} config={agent.llm_config?.image_edit} ... />
<GenericConfig title="Audio Transcription" capability={LlmModelCapability.AudioTranscription} config={agent.llm_config?.audio_transcription} ... />
<GenericConfig title="Realtime" capability={LlmModelCapability.Realtime} config={agent.llm_config?.realtime} ... />

// GenericConfig.svelte
<script>
  export let title;
  export let capability;
  export let config;
  // ... generic logic to filter providers/models based on `capability` prop
</script>
<h6>{title}</h6>
<Input ...> <!-- Provider -->
<Input ...> <!-- Model -->
<slot></slot> <!-- For extra fields -->
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies significant code duplication across the five new configuration components, proposing a much more maintainable and scalable solution using a single generic component with props and slots.

High
Possible issue
Prevent TypeError from spreading null

Prevent a potential TypeError by ensuring chatConfig is an object before
spreading it. Change ...chatConfig to ...(chatConfig || {}).

src/routes/page/agent/[agentId]/agent-components/agent-llm-config.svelte [17-30]

 export const fetchLlmConfig = () => {
     const chatConfig = chatConfigCmp?.fetchConfig();
     const imageGenerationConfig = imageGenerationConfigCmp?.fetchConfig();
     const imageEditConfig = imageEditConfigCmp?.fetchConfig();
     const audioTranscriptionConfig = audioTranscriptionConfigCmp?.fetchConfig();
     const realtimeConfig = realtimeConfigCmp?.fetchConfig();
     return {
-        ...chatConfig,
+        ...(chatConfig || {}),
         image_generation: imageGenerationConfig ? {...imageGenerationConfig} : null,
         image_edit: imageEditConfig ? {...imageEditConfig} : null,
         audio_transcription: audioTranscriptionConfig ? {...audioTranscriptionConfig} : null,
         realtime: realtimeConfig ? {...realtimeConfig} : null
     };
 }
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a potential TypeError from spreading a null value, which can occur if chatConfigCmp.fetchConfig() returns null. This is a valid bug fix.

Medium
Remove incorrect property reset
Suggestion Impact:The commit removed the line setting config.reasoning_effort_level = null within changeProvider, aligning with the suggestion.

code diff:

         if (!!!provider) {
             models = [];
             config.model = null;
-            config.reasoning_effort_level = null;
             handleAgentChange();
             return;
         }

In changeProvider, remove the line config.reasoning_effort_level = null; as this
property is not part of the audio transcription configuration.

src/routes/page/agent/[agentId]/agent-components/llm-configs/audio-transcription-config.svelte [59-75]

 async function changeProvider(e) {
     const provider = e.target.value;
     config.provider = provider || null;
 
     if (!!!provider) {
         models = [];
         config.model = null;
-        config.reasoning_effort_level = null;
         handleAgentChange();
         return;
     }
 
     config.is_inherit = false;
     models = getLlmModels(provider);
     config.model = models[0]?.name;
     handleAgentChange();
 }

[Suggestion processed]

Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies that config.reasoning_effort_level is an extraneous property for the audio transcription config, likely a copy-paste error. Removing it improves code correctness and removes dead code.

Low
  • Update

@iceljc iceljc marked this pull request as draft October 27, 2025 22:17
@iceljc iceljc marked this pull request as ready for review October 29, 2025 03:48
@qodo-merge-pro
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit logs: New actions for fetching and updating agent code scripts (including create/update and
delete-if-not-included semantics) are added without any visible client-side logging of the
action, user, or outcome, making auditability unclear.

Referred Code
/**
 * Get agent code scripts
 * @param {string} agentId
 * @param {import('$agentTypes').AgentCodeScriptFilter?} filter
 * @returns {Promise<import('$agentTypes').AgentCodeScriptViewModel[]>}
 */
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


 ... (clipped 10 lines)
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Generic catch block: The save flow swallows errors in a catch without surfacing actionable context (e.g., which
agent or script failed), which may hinder debugging of edge cases.

Referred Code
        refreshScriptObj([...scripts]);
    } else {
        throw "error when saving code scripts.";
    }
}).catch(() => {
    isLoading = false;
    isComplete = false;
    isError = true;
    setTimeout(() => {
        isError = false;
    }, duration);
});     
Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Param serialization risk: The qs serializer with encode:false for arrays in getAgentCodeScripts may pass unencoded
user-influenced parameters to the backend, relying entirely on server-side validation.

Referred Code
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;
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-merge-pro
Copy link

qodo-merge-pro bot commented Oct 29, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Avoid code duplication with reusable components

Refactor the new LLM configuration and code script sections to use generic,
reusable components instead of duplicated code. This can be achieved by creating
a single component for each feature that accepts props for varying elements like
titles and filter criteria.

Examples:

src/routes/page/agent/[agentId]/agent-components/llm-configs/image-edit-config.svelte [1-116]
<script>
    import { Input } from '@sveltestrap/sveltestrap';
	import { LlmModelCapability } from '$lib/helpers/enums';
    
    /** @type {import('$agentTypes').AgentModel} */
    export let agent;

    /** @type {import('$commonTypes').LlmConfig[]} */
    export let llmConfigs = [];


 ... (clipped 106 lines)
src/routes/page/agent/code-scripts/+page.svelte [323-472]
{#if !!selectedAgentId}
<Card>
    <CardBody class="border-bottom">
        <Row class="g-3">
            <Col lg="3">
                <div class="mb-2" style="display: flex; gap: 10px;">
                    <div class="line-align-center fw-bold">
                        Source scripts
                    </div>
                    <div class="line-align-center">

 ... (clipped 140 lines)

Solution Walkthrough:

Before:

// 1. Duplicated LLM Config Components
// audio-transcription-config.svelte
<script>
  let config = agent.llm_config?.audio_transcription || {};
  // ... logic to filter models by LlmModelCapability.AudioTranscription
</script>
<h6>Audio Transcription</h6>
<!-- UI for provider and model selection -->

// image-edit-config.svelte
<script>
  let config = agent.llm_config?.image_edit || {};
  // ... logic to filter models by LlmModelCapability.ImageEdit
</script>
<h6>Image Edit</h6>
<!-- UI for provider and model selection -->

// 2. Duplicated Script Editor UI in code-scripts/+page.svelte
<!-- Source Scripts Section -->
<NavBar>
  {#each srcScriptObj.scripts as item} ... {/each}
</NavBar>
<CodeMirror value={srcScriptObj.selectedScript?.content} ... />

<!-- Test Scripts Section -->
<NavBar>
  {#each testScriptObj.scripts as item} ... {/each}
</NavBar>
<CodeMirror value={testScriptObj.selectedScript?.content} ... />

After:

// 1. Reusable LLM Config Component
// LlmCapabilityConfig.svelte
<script>
  export let title;
  export let capability;
  export let agentConfig;
  // ... generic logic using `capability` prop to filter models
</script>
<h6>{title}</h6>
<!-- UI for provider and model selection -->

// Parent component
<LlmCapabilityConfig title="Audio Transcription" capability={LlmModelCapability.AudioTranscription} ... />
<LlmCapabilityConfig title="Image Edit" capability={LlmModelCapability.ImageEdit} ... />

// 2. Reusable Script Editor Component
// ScriptEditor.svelte
<script>
  export let title;
  export let scriptObj;
  // ... event handlers
</script>
<h6>{title}</h6>
<NavBar>
  {#each scriptObj.scripts as item} ... {/each}
</NavBar>
<CodeMirror value={scriptObj.selectedScript?.content} ... />

// Parent page
<ScriptEditor title="Source Scripts" bind:scriptObj={srcScriptObj} ... />
<ScriptEditor title="Test Scripts" bind:scriptObj={testScriptObj} ... />
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies two significant areas of code duplication in the new LLM config components and the code scripts page, and proposing reusable components is a high-impact architectural improvement.

High
Possible issue
Prevent data loss from duplicate script names

Enforce unique script names across both source and test scripts before saving to
prevent potential data loss from name collisions.

src/routes/page/agent/code-scripts/+page.svelte [247-290]

 function saveCodeScripts() {
     if (!selectedAgentId) {
         return;
     }
 
-    const uniqueSrcScripts = srcScriptObj.scripts.filter(x => x.name?.trim()).filter((script, index, self) =>
+    const allScripts = [...srcScriptObj.scripts, ...testScriptObj.scripts]
+        .filter(x => x.name?.trim() && x.name.endsWith('.py'))
+        .map(x => ({ ...x, name: x.name.trim() }));
+
+    const uniqueScripts = allScripts.filter((script, index, self) =>
         index === self.findIndex(s => s.name === script.name)
     );
-    const uniqueTestScripts = testScriptObj.scripts.filter(x => x.name?.trim()).filter((script, index, self) =>
-        index === self.findIndex(s => s.name === script.name)
-    );
-    const scripts = [...uniqueSrcScripts, ...uniqueTestScripts].map(x => ({...x, name: x.name.trim() }))
-                                                               .filter(x => x.name.endsWith('.py'));
+
+    if (uniqueScripts.length !== allScripts.length) {
+        // Or show a more user-friendly error message
+        console.error("Duplicate script names found across source and test scripts. Please use unique names.");
+        isError = true;
+        setTimeout(() => { isError = false; }, duration);
+        return;
+    }
 
     const update = {
-        code_scripts: scripts,
+        code_scripts: uniqueScripts,
         options: {
             delete_if_not_included: true,
             is_upsert: true
         }
     };
 
     isLoading = true;
     updateAgentCodeScripts(selectedAgentId, update).then(res => {
         if (res) {
             isLoading = false;
             isComplete = true;
             setTimeout(() => {
                 isComplete = false;
             }, duration);
 
-            refreshScriptObj([...scripts]);
+            refreshScriptObj([...uniqueScripts]);
         } else {
             throw "error when saving code scripts.";
         }
     }).catch(() => {
         isLoading = false;
         isComplete = false;
         isError = true;
         setTimeout(() => {
             isError = false;
         }, duration);
     });     
 }
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a potential data loss bug where scripts with the same name but different types could overwrite each other, and the proposed fix effectively prevents this by validating uniqueness across all scripts.

High
Fix incorrect script selection logic
Suggestion Impact:The commit modified the foundTest assignment within refreshScriptObj to search in the tests array. Although it still references srcScriptObj.selectedScript?.name instead of testScriptObj, it indicates attention to the bug area and partially aligns with the suggestion's intent to correct the selection source.

code diff:

         const tests = scripts?.filter(x => x.script_type === AgentCodeScriptType.Test)?.map(x => ({ ...x, uid: uuidv4() })) || [];
-        const foundTest = srcs.find(x => x.name === srcScriptObj?.selectedScript?.name);
+        const foundTest = tests.find(x => x.name === srcScriptObj?.selectedScript?.name);
         testScriptObj = {
             ...testScriptObj,
             scripts: tests,
             selectedScript: foundTest ? foundTest : tests.length > 0 ? tests[0] : null
         };

Fix a bug in refreshScriptObj where it was using srcScriptObj's selected script
name to find the selected test script, causing incorrect script selection.

src/routes/page/agent/code-scripts/+page.svelte [138-154]

 function refreshScriptObj(scripts) {
     const srcs = scripts?.filter(x => x.script_type === AgentCodeScriptType.Src)?.map(x => ({ ...x, uid: uuidv4() })) || [];
     const foundSrc = srcs.find(x => x.name === srcScriptObj?.selectedScript?.name);
     srcScriptObj = {
         ...srcScriptObj,
         scripts: srcs,
         selectedScript: foundSrc ? foundSrc : srcs.length > 0 ? srcs[0] : null
     };
 
     const tests = scripts?.filter(x => x.script_type === AgentCodeScriptType.Test)?.map(x => ({ ...x, uid: uuidv4() })) || [];
-    const foundTest = srcs.find(x => x.name === srcScriptObj?.selectedScript?.name);
+    const foundTest = tests.find(x => x.name === testScriptObj?.selectedScript?.name);
     testScriptObj = {
         ...testScriptObj,
         scripts: tests,
         selectedScript: foundTest ? foundTest : tests.length > 0 ? tests[0] : null
     };
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a copy-paste bug in the logic for re-selecting a test script after a refresh, which would lead to incorrect UI behavior. The fix is accurate and crucial for the component's functionality.

High
  • More

@iceljc iceljc merged commit b7986cf into SciSharp:main Oct 29, 2025
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant