Skip to content

feat: add RAG management view#974

Open
jeffmaury wants to merge 2 commits intokortex-hub:mainfrom
jeffmaury:GH-512
Open

feat: add RAG management view#974
jeffmaury wants to merge 2 commits intokortex-hub:mainfrom
jeffmaury:GH-512

Conversation

@jeffmaury
Copy link
Contributor

@jeffmaury jeffmaury commented Feb 3, 2026

To test:

  • create a Milvus resource (called m1 in this example)
  • make sure docling container is started
  • create a rag1.json in $HOME/.local/share/kortex/rag folder with the following content
{
  "name": "rag1",
  "ragConnection": {
    "name": "m1",
    "providerId": "milvus"
  },
  "chunkerId": "kortex.docling.docling",
  "files": [
  ]
}

rag

Part of #512

@jeffmaury jeffmaury marked this pull request as ready for review February 4, 2026 08:42
@jeffmaury jeffmaury requested a review from a team as a code owner February 4, 2026 08:42
@jeffmaury jeffmaury requested review from axel7083, benoitf and bmahabirbu and removed request for a team February 4, 2026 08:42
@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

Adds RAG (Retrieval-Augmented Generation) environment management end-to-end: new navigation token and routes, IPC handlers and preload APIs to list/delete environments, DI binding and registry init in main, renderer stores and UI (list, details, columns, utilities), and tests updated for new signatures and error behavior.

Changes

Cohort / File(s) Summary
API Navigation
packages/api/src/navigation-page.ts, packages/api/src/navigation-request.ts
Added NavigationPage.RAG_ENVIRONMENT_DETAILS and corresponding NavigationParameters entry { name: string }.
Main plugin — DI & Init
packages/main/src/plugin/index.ts, packages/main/src/plugin/rag-environment-registry.ts
Bound RagEnvironmentRegistry as singleton, added dual-phase init calls, registered IPC handlers rag-environment-registry:getRagEnvironments and rag-environment-registry:deleteRagEnvironment, and changed deleteRagEnvironment signature to Promise<void> (throws on not-found).
Main plugin tests
packages/main/src/plugin/rag-environment-registry.spec.ts
Updated constructor to accept IPCHandle, wired IPC dependency in tests, and adjusted assertions to expect deleteRagEnvironment to throw on errors and return void on success.
Preload API
packages/preload/src/index.ts
Exposed getRagEnvironments(): Promise<RagEnvironment[]> and deleteRagEnvironment(name: string): Promise<void> via IPC channels.
Renderer routing & navigation
packages/renderer/src/App.svelte, packages/renderer/src/navigation.ts, packages/renderer/src/stores/navigation/navigation-registry.ts, packages/renderer/src/stores/navigation/navigation-registry-rag.svelte.ts
Added routes for /rag-environments and /rag-environments/:name/*, registered RAG navigation entry and added route mapping for RAG_ENVIRONMENT_DETAILS.
Renderer stores
packages/renderer/src/stores/rag-environments.ts, packages/renderer/src/stores/chunk-providers.ts
Added ragEnvironments and chunkProviders writable stores, fetch* functions using window APIs, event store wiring, and checkForUpdate() stubs.
Renderer UI — pages & components
packages/renderer/src/lib/rag/RAGEnvironmentList.svelte, packages/renderer/src/lib/rag/RAGEnvironmentDetails.svelte, packages/renderer/src/lib/rag/components/EmptyRAGEnvironmentScreen.svelte
Added RAG list and detail pages with tabbed details, empty state, and integration with stores.
Renderer UI — column components
packages/renderer/src/lib/rag/columns/RAGEnvironmentStatus.svelte, .../RAGEnvironmentName.svelte, .../RAGEnvironmentDatabase.svelte, .../RAGEnvironmentChunker.svelte, .../RAGEnvironmentSources.svelte, .../RAGEnvironmentActions.svelte
Added reusable table column components (status, name/navigation, database, chunker, sources count, delete action with confirmation).
Renderer utils
packages/renderer/src/lib/rag/rag-environment-utils.svelte.ts
Added getDatabaseName() and getChunkProviderName() helpers to derive display names from provider registries.

Sequence Diagram

sequenceDiagram
    participant UI as Frontend UI
    participant Store as Svelte Store
    participant Preload as Preload Layer
    participant IPC as IPC Channel
    participant Backend as RagEnvironmentRegistry

    UI->>Store: fetchRagEnvironments()
    Store->>Preload: window.getRagEnvironments()
    Preload->>IPC: send rag-environment-registry:getRagEnvironments
    IPC->>Backend: invoke getAllRagEnvironments handler
    Backend-->>IPC: return RagEnvironment[]
    IPC-->>Preload: respond with RagEnvironment[]
    Preload-->>Store: return data
    Store-->>UI: update ragEnvironments

    UI->>UI: user confirms delete
    UI->>Preload: window.deleteRagEnvironment(name)
    Preload->>IPC: send rag-environment-registry:deleteRagEnvironment
    IPC->>Backend: invoke deleteRagEnvironment handler
    Backend-->>IPC: return void / throw error
    IPC-->>Preload: respond / propagate error
    Preload-->>UI: promise resolves / rejects
    UI->>Store: fetchRagEnvironments() (refresh)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat: add RAG management view' accurately summarizes the main change: adding a new RAG management view/interface to the application. The title is concise, clear, and directly reflects the primary objective of the changeset.
Description check ✅ Passed The PR description is related to the changeset. It provides testing instructions, example configuration, and references issue #512, all of which align with the RAG management view implementation shown in the file changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@packages/renderer/src/lib/rag/columns/RAGEnvironmentDatabase.svelte`:
- Line 12: databaseName is computed once at initialization using
getDatabaseName($providerInfos, object) and will become stale when providerInfos
updates; replace the one-time computation with a reactive derived store (use
Svelte 5 runes/$derived) that derives databaseName from providerInfos and object
so it updates automatically when $providerInfos changes, referencing the
existing getDatabaseName function to compute the derived value in
RAGEnvironmentDatabase.svelte.

In `@packages/renderer/src/lib/rag/columns/RAGEnvironmentSources.svelte`:
- Line 10: The count is computed once with "const sourcesCount =
object.files.length" so it doesn't update when the parent changes the "object"
prop; replace that static declaration with a Svelte reactive statement (use "$:
sourcesCount = object?.files?.length ?? 0") so "sourcesCount" updates whenever
"object" or its "files" change (follow the pattern used in
RAGEnvironmentStatus.svelte), keeping the variable name "sourcesCount" so
bindings in the template remain valid.

In `@packages/renderer/src/lib/rag/RAGEnvironmentDetails.svelte`:
- Around line 55-58: The Status text in RAGEnvironmentDetails.svelte is
hardcoded to "Running"; replace it with the actual environment status prop/state
(e.g., use the passed-in environment.status or a local reactive variable
`status`) so the view reflects real state; also provide a safe fallback like
"Unknown" when status is undefined and map known statuses (initializing,
running, error, stopped) to readable labels and optional CSS classes for proper
styling and accessibility.
- Around line 95-97: Replace the typo'd CSS class "file-iconF" with the intended
"file-icon" in the affected element in RAGEnvironmentDetails.svelte so the
markup matches your style conventions; also search for any CSS/JS references
using "file-iconF" (selectors, styles, or queries) and rename them to
"file-icon" to keep markup and styles consistent.

In `@packages/renderer/src/lib/rag/RAGEnvironmentList.svelte`:
- Around line 64-71: The default sort column prop passed to the Table in
RAGEnvironmentList.svelte is "Name" but the columns definition uses the title
"Environment Name", so update the Table invocation to use the exact column
identifier the Table expects (either change defaultSortColumn from "Name" to
"Environment Name" or to the column's id/key from the columns array) so the
default sort matches the columns variable and the Table component's matching
logic.
🧹 Nitpick comments (7)
packages/renderer/src/lib/rag/columns/RAGFilePath.svelte (1)

14-18: Ensure single-line truncation is enforced for long paths.

overflow-hidden alone can still wrap. If the intent is a single-line, ellipsized path, add truncate (or whitespace-nowrap text-ellipsis) to guarantee that behavior.

♻️ Suggested tweak for reliable truncation
-    <div class="text-sm text-[var(--pd-table-body-text)]" title={object.path}>
+    <div class="truncate text-sm text-[var(--pd-table-body-text)]" title={object.path}>
       {object.path}
     </div>
packages/renderer/src/App.svelte (1)

201-210: Inconsistent indentation in nested Route.

The inner <Route path="/:name/*"> on Line 206 should be indented to align with the sibling <Route path="/"> on Line 203 for consistency with other route blocks in this file.

🔧 Suggested formatting fix
         <!-- RAG Environments -->
         <Route path="/rag-environments/*" breadcrumb="RAG Environments" navigationHint="root" firstmatch>
           <Route path="/" breadcrumb="RAG Environments" navigationHint="root">
             <RAGEnvironmentList />
           </Route>
-        <Route path="/:name/*" let:meta breadcrumb="RAG Environment Details" navigationHint="details">
-          <RAGEnvironmentDetails name={meta.params.name} />
-        </Route>
+          <Route path="/:name/*" let:meta breadcrumb="RAG Environment Details" navigationHint="details">
+            <RAGEnvironmentDetails name={meta.params.name} />
+          </Route>
         </Route>
packages/renderer/src/lib/rag/columns/RAGEnvironmentActions.svelte (1)

11-16: Consider providing user feedback on deletion failure.

The current implementation silently logs errors to the console. Users won't be aware if the deletion fails. Consider displaying a toast notification or error message to inform the user of the failure.

🔧 Example improvement with toast notification
+import { toast } from '/@/lib/toast/toast';
+
 function handleDelete(): void {
   withConfirmation(
-    () => window.deleteRagEnvironment(object.name).catch(console.error),
+    () => window.deleteRagEnvironment(object.name).catch((err: unknown) => {
+      console.error(err);
+      toast.error(`Failed to delete environment ${object.name}`);
+    }),
     `delete environment ${object.name}`,
   );
 }
packages/renderer/src/lib/rag/columns/RAGEnvironmentName.svelte (1)

22-22: Simplify onclick handler.

The .bind(undefined, object) pattern is unnecessary since object is already in scope. A simpler arrow function or direct call would be cleaner and more readable.

🔧 Suggested simplification
-<button class="flex flex-col whitespace-nowrap max-w-full" onclick={openRAGEnvironmentDetails.bind(undefined, object)}>
+<button class="flex flex-col whitespace-nowrap max-w-full" onclick={() => openRAGEnvironmentDetails(object)}>

Alternatively, since object is the only parameter and is in scope, the function could be simplified to not take a parameter:

-function openRAGEnvironmentDetails(object: RagEnvironment): void {
+function openRAGEnvironmentDetails(): void {
   handleNavigation({
     page: NavigationPage.RAG_ENVIRONMENT_DETAILS,
     parameters: {
       name: object.name,
     },
   });
 }
</script>

-<button class="flex flex-col whitespace-nowrap max-w-full" onclick={openRAGEnvironmentDetails.bind(undefined, object)}>
+<button class="flex flex-col whitespace-nowrap max-w-full" onclick={openRAGEnvironmentDetails}>
packages/renderer/src/stores/rag-environments.ts (2)

33-35: checkForUpdate always returns true, triggering unnecessary fetches.

The checkForUpdate function unconditionally returns true, meaning every event (including potentially unrelated ones like extensions-started) will trigger a full refetch. Consider implementing actual change detection or at minimum documenting that this is intentional.


49-54: Remove debug console.log statement.

The console.log('fetched rag environments', result) on Line 51 appears to be debug output that should be removed before merging to avoid cluttering the console in production.

🧹 Suggested fix
 export async function fetchRagEnvironments(): Promise<RagEnvironment[]> {
   const result = await window.getRagEnvironments();
-  console.log('fetched rag environments', result);
   ragEnvironments.set(result);
   return result;
 }
packages/renderer/src/lib/rag/rag-environment-utils.svelte.ts (1)

11-11: Replace template literal with plain string for N/A fallback.

The fallback value doesn't require interpolation, so use a regular string literal.

♻️ Proposed fix
-  return ragConnection?.name ? `${ragConnection.name} (${ragProvider?.name})` : `N/A`;
+  return ragConnection?.name ? `${ragConnection.name} (${ragProvider?.name})` : 'N/A';

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@packages/main/src/plugin/rag-environment-registry.ts`:
- Around line 190-194: deleteRagEnvironment currently uses the untrusted name to
build a filesystem path via getRagEnvironmentFilePath, allowing path traversal;
validate the name first (e.g., allow only a strict whitelist like
/^[A-Za-z0-9._-]+$/ or explicitly disallow path separators like '/' and '\\')
and throw if it fails, then call getRagEnvironmentFilePath; additionally after
resolving the path, ensure the resolved path is inside the registry base
directory (compare path.resolve(filePath).startsWith(path.resolve(this.ragDir))
or similar) and throw if it does not, so only files under the RAG directory can
be deleted.

In `@packages/renderer/src/App.svelte`:
- Around line 201-208: The route is passing the raw URL-encoded param to
RAGEnvironmentDetails which can break names with spaces/special chars; update
the Route handler to decode the param before use (e.g., use decodeURIComponent
on meta.params.name) so RAGEnvironmentDetails receives a decoded name value;
locate the Route that renders <RAGEnvironmentDetails name={meta.params.name}/>
and replace the prop with the decoded param.

In `@packages/renderer/src/stores/rag-environments.ts`:
- Around line 49-52: The console.log in fetchRagEnvironments currently prints
the full RAG payload (in fetchRagEnvironments, calling window.getRagEnvironments
and updating ragEnvironments), which can leak sensitive paths/metadata; remove
the console.log or wrap it behind a dev-only guard (e.g., check
process.env.NODE_ENV === 'development' or an isDev flag) so production builds do
not log the result. Keep the call to window.getRagEnvironments() and
ragEnvironments.set(result) unchanged.
🧹 Nitpick comments (1)
packages/renderer/src/lib/rag/rag-environment-utils.svelte.ts (1)

5-12: Replace unnecessary template literal with string literal.

The static analysis correctly identifies that `N/A` doesn't use interpolation and should be a plain string literal.

♻️ Proposed fix
-  return ragConnection?.name ? `${ragConnection.name} (${ragProvider?.name})` : `N/A`;
+  return ragConnection?.name ? `${ragConnection.name} (${ragProvider?.name})` : 'N/A';

Comment on lines +190 to 194
public async deleteRagEnvironment(name: string): Promise<void> {
const filePath = this.getRagEnvironmentFilePath(name);
if (!existsSync(filePath)) {
return false;
throw new Error(`RAG environment ${name} not found`);
}
Copy link

@coderabbitai coderabbitai bot Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Validate environment names before constructing file paths.

name comes from IPC and is used to build a filesystem path; without validation, ../ segments can escape the RAG directory and delete arbitrary files. Add a strict name check before resolving paths.

🛡️ Suggested fix
   public async deleteRagEnvironment(name: string): Promise<void> {
+    if (name !== basename(name)) {
+      throw new Error(`Invalid RAG environment name: ${name}`);
+    }
     const filePath = this.getRagEnvironmentFilePath(name);
🤖 Prompt for AI Agents
In `@packages/main/src/plugin/rag-environment-registry.ts` around lines 190 - 194,
deleteRagEnvironment currently uses the untrusted name to build a filesystem
path via getRagEnvironmentFilePath, allowing path traversal; validate the name
first (e.g., allow only a strict whitelist like /^[A-Za-z0-9._-]+$/ or
explicitly disallow path separators like '/' and '\\') and throw if it fails,
then call getRagEnvironmentFilePath; additionally after resolving the path,
ensure the resolved path is inside the registry base directory (compare
path.resolve(filePath).startsWith(path.resolve(this.ragDir)) or similar) and
throw if it does not, so only files under the RAG directory can be deleted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has sense to me.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description image shows the Kortex application with the RAG section active in the left sidebar navigation, displaying the chat interface with example prompts.

@MarsKubeX, glad it makes sense! Here's the complete fix — centralizing the validation in a private helper so every method that constructs a path is protected, not just deleteRagEnvironment:

  • Add a private validateName helper that rejects names containing path separators (using basename check) and verifies the resolved path stays inside #ragDirectory.
  • Call validateName at the top of getRagEnvironmentFilePath so all callers — deleteRagEnvironment, loadEnvironment, hasRagEnvironment, saveOrUpdate — are covered automatically.

🧠 Learnings used
Learnt from: CR
Repo: kortex-hub/kortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:41:44.065Z
Learning: Applies to packages/main/src/plugin/index.ts : IPC communication handlers should follow the naming convention <registry-name>:<action> (e.g., container-provider-registry:listContainers) in packages/main/src/plugin/index.ts

Learnt from: CR
Repo: kortex-hub/kortex PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T14:41:20.640Z
Learning: Applies to packages/main/src/**/*.ts : IPC communication handlers should follow the naming convention `<registry-name>:<action>` (e.g., `container-provider-registry:listContainers`) when exposed via `ipcHandle()` in the main process

Learnt from: benoitf
Repo: kortex-hub/kortex PR: 1077
File: packages/main/src/plugin/skill/skill-manager.ts:80-109
Timestamp: 2026-03-09T08:47:09.657Z
Learning: In the kortex-hub/kortex repository, IPC handlers (via ipcHandle()) may be registered directly inside feature manager/service classes (e.g., SkillManager in packages/main/src/plugin/skill/skill-manager.ts) rather than exclusively in packages/main/src/plugin/index.ts. Treat this as an accepted design pattern for files under the plugin directory. Reviewers should not require centralization in index.ts; allow IPC registration proximity to the feature that owns the handler. When reviewing code, accept direct ipcHandle() registrations inside feature managers and ensure the pattern is consistently applied across similar feature-manager modules.

Failed to handle agent chat message. Please try again.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@packages/renderer/src/lib/rag/rag-environment-utils.svelte.ts`:
- Around line 5-12: The return uses a static template literal for the
unavailable case which triggers noUnusedTemplateLiteral; in getDatabaseName (and
related variables ragProvider, ragConnection, providerInfos, ragEnvironment)
replace the backticked `N/A` with a normal single-quoted string 'N/A' while
keeping the interpolated template `${ragConnection.name} (${ragProvider?.name})`
unchanged.

In `@packages/renderer/src/lib/rag/RAGEnvironmentDetails.svelte`:
- Around line 20-21: The code calls decodeURIComponent(name) inside the derived
selector (const ragEnvironment = $derived($ragEnvironments.find(env => env.name
=== decodeURIComponent(name)));) which can throw on malformed percent-encoding;
wrap decoding in a safe helper or try/catch: implement a small safeDecode
function (or inline try/catch) that returns either decodeURIComponent(name) or a
fallback (e.g., the original name or null) and then use that safe value in the
$ragEnvironments.find call so the component won’t crash on malformed routes.

In `@packages/renderer/src/stores/chunk-providers.ts`:
- Around line 44-45: Create a new TypeScript declaration file named
exposedInMainWorld.d.ts that adds a declare global block augmenting the Window
interface to include getChunkProviders(): Promise<ChunkProviderInfo[]> (and any
other preload-exposed methods you use); ensure ChunkProviderInfo is either
imported/declared or referenced correctly so the renderer's fetchChunkProviders
function and calls to window.getChunkProviders are properly typed and the
preload/renderer tsconfig references include this declaration file.

Comment on lines +5 to +12
export function getDatabaseName(providerInfos: ProviderInfo[], ragEnvironment: RagEnvironment | undefined): string {
// Extract database name from connection ID or show the ID
const ragProvider = providerInfos.find(provider => provider.id === ragEnvironment?.ragConnection.providerId);
const ragConnection = ragProvider?.ragConnections.find(
connection => connection.name === ragEnvironment?.ragConnection.name,
);
return ragConnection?.name ? `${ragConnection.name} (${ragProvider?.name})` : `N/A`;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -name "biome.json" -o -name "biome.jsonc" | head -5

Repository: kortex-hub/kortex

Length of output: 74


🏁 Script executed:

cat packages/renderer/src/lib/rag/rag-environment-utils.svelte.ts 2>/dev/null || echo "File not found or error reading"

Repository: kortex-hub/kortex

Length of output: 1048


🌐 Web query:

Biome noUnusedTemplateLiteral lint rule

💡 Result:

Biome’s noUnusedTemplateLiteral lint rule (diagnostic: lint/style/noUnusedTemplateLiteral) disallows template literals when you aren’t using interpolation (${...}) or template-literal-specific escaping—i.e., it suggests using a normal string literal ("..." / '...') instead. It’s fixable with a safe fix (auto-replace to a string literal), available since v1.0.0, and not enabled by default (not “recommended”). [1]

Enable it in biome.json:

{
  "linter": {
    "rules": {
      "style": {
        "noUnusedTemplateLiteral": "error"
      }
    }
  }
}

[1]

Example it flags:

const foo = `bar`;

→ safe fix: const foo = "bar"; [1]

Example that’s valid (template literal needed):

const foo = `bar
has newline`;

[1]

Sources: [1]


🏁 Script executed:

cat biome.jsonc

Repository: kortex-hub/kortex

Length of output: 1361


Replace template literal with string literal to satisfy noUnusedTemplateLiteral.

The static string `N/A` should use single quotes instead of backticks. This violates Biome's enabled lint rule, which flags template literals without interpolation.

Suggested fix
-  return ragConnection?.name ? `${ragConnection.name} (${ragProvider?.name})` : `N/A`;
+  return ragConnection?.name ? `${ragConnection.name} (${ragProvider?.name})` : 'N/A';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function getDatabaseName(providerInfos: ProviderInfo[], ragEnvironment: RagEnvironment | undefined): string {
// Extract database name from connection ID or show the ID
const ragProvider = providerInfos.find(provider => provider.id === ragEnvironment?.ragConnection.providerId);
const ragConnection = ragProvider?.ragConnections.find(
connection => connection.name === ragEnvironment?.ragConnection.name,
);
return ragConnection?.name ? `${ragConnection.name} (${ragProvider?.name})` : `N/A`;
}
export function getDatabaseName(providerInfos: ProviderInfo[], ragEnvironment: RagEnvironment | undefined): string {
// Extract database name from connection ID or show the ID
const ragProvider = providerInfos.find(provider => provider.id === ragEnvironment?.ragConnection.providerId);
const ragConnection = ragProvider?.ragConnections.find(
connection => connection.name === ragEnvironment?.ragConnection.name,
);
return ragConnection?.name ? `${ragConnection.name} (${ragProvider?.name})` : 'N/A';
}
🧰 Tools
🪛 Biome (2.3.13)

[error] 11-11: Do not use template literals if interpolation and special-character handling are not needed.

Safe fix: Replace with string literal

(lint/style/noUnusedTemplateLiteral)

🤖 Prompt for AI Agents
In `@packages/renderer/src/lib/rag/rag-environment-utils.svelte.ts` around lines 5
- 12, The return uses a static template literal for the unavailable case which
triggers noUnusedTemplateLiteral; in getDatabaseName (and related variables
ragProvider, ragConnection, providerInfos, ragEnvironment) replace the
backticked `N/A` with a normal single-quoted string 'N/A' while keeping the
interpolated template `${ragConnection.name} (${ragProvider?.name})` unchanged.

Comment on lines +20 to +21
const ragEnvironment = $derived($ragEnvironments.find(env => env.name === decodeURIComponent(name)));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard decodeURIComponent to avoid crashes on malformed routes.

decodeURIComponent throws on invalid percent-encoding, which would break rendering if the route is malformed.

🛠️ Suggested guard
-const ragEnvironment = $derived($ragEnvironments.find(env => env.name === decodeURIComponent(name)));
+const decodedName = $derived.by(() => {
+  try {
+    return decodeURIComponent(name);
+  } catch {
+    return name;
+  }
+});
+const ragEnvironment = $derived($ragEnvironments.find(env => env.name === decodedName));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const ragEnvironment = $derived($ragEnvironments.find(env => env.name === decodeURIComponent(name)));
const decodedName = $derived.by(() => {
try {
return decodeURIComponent(name);
} catch {
return name;
}
});
const ragEnvironment = $derived($ragEnvironments.find(env => env.name === decodedName));
🤖 Prompt for AI Agents
In `@packages/renderer/src/lib/rag/RAGEnvironmentDetails.svelte` around lines 20 -
21, The code calls decodeURIComponent(name) inside the derived selector (const
ragEnvironment = $derived($ragEnvironments.find(env => env.name ===
decodeURIComponent(name)));) which can throw on malformed percent-encoding; wrap
decoding in a safe helper or try/catch: implement a small safeDecode function
(or inline try/catch) that returns either decodeURIComponent(name) or a fallback
(e.g., the original name or null) and then use that safe value in the
$ragEnvironments.find call so the component won’t crash on malformed routes.

Comment on lines +44 to +45
export async function fetchChunkProviders(): Promise<ChunkProviderInfo[]> {
const result = await window.getChunkProviders();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

rg -n --type=ts -C3 '\bgetChunkProviders\b'

Repository: kortex-hub/kortex

Length of output: 2459


🏁 Script executed:

rg -n --type=ts 'window\.getChunkProviders|Window.*interface|declare.*window' | head -30

Repository: kortex-hub/kortex

Length of output: 162


🏁 Script executed:

fd -t f '\.d\.ts$|types\.ts' packages/preload | head -10

Repository: kortex-hub/kortex

Length of output: 43


🏁 Script executed:

rg -n 'declare|interface|export.*type|ChunkProviderInfo' packages/preload/src/index.ts | head -20

Repository: kortex-hub/kortex

Length of output: 576


🏁 Script executed:

rg -n 'declare global|interface Window|window.*:' packages/preload/src/index.ts packages/renderer/src --type=ts -A2 -B2 | head -40

Repository: kortex-hub/kortex

Length of output: 3055


🏁 Script executed:

rg -n 'declare global' packages/preload/src/index.ts --context=10

Repository: kortex-hub/kortex

Length of output: 43


🏁 Script executed:

ls -la packages/preload/src/ && echo "---" && wc -l packages/preload/src/index.ts

Repository: kortex-hub/kortex

Length of output: 341


🏁 Script executed:

tail -100 packages/preload/src/index.ts && echo "---SEPARATOR---" && rg -n 'declare global|Window\s*{|interface.*Window' --type=ts packages/

Repository: kortex-hub/kortex

Length of output: 3740


🏁 Script executed:

rg -n 'declare global' packages/ --type=ts && echo "---" && fd -t f 'window\.d\.ts|preload\.d\.ts' packages/

Repository: kortex-hub/kortex

Length of output: 43


🏁 Script executed:

cat packages/preload/tsconfig.json 2>/dev/null | head -30 && echo "---" && find packages/ -name '*.d.ts' | head -20

Repository: kortex-hub/kortex

Length of output: 772


🏁 Script executed:

find packages/ -name 'exposedInMainWorld.d.ts' -exec cat {} \;

Repository: kortex-hub/kortex

Length of output: 43


🏁 Script executed:

ls -la packages/preload/ | grep -E '\.d\.ts|\.ts' && echo "---CHECK IF FILE EXISTS---" && test -f packages/preload/exposedInMainWorld.d.ts && echo "File exists" || echo "File does not exist"

Repository: kortex-hub/kortex

Length of output: 80


🏁 Script executed:

cat packages/renderer/tsconfig.json 2>/dev/null | head -40

Repository: kortex-hub/kortex

Length of output: 991


🏁 Script executed:

find packages/ -path '*/types/*.d.ts' && echo "---" && ls -la types/ 2>/dev/null && echo "---" && ls -la packages/*/types/ 2>/dev/null | head -30

Repository: kortex-hub/kortex

Length of output: 306


🏁 Script executed:

cat types/additional.d.ts && echo "---" && cat types/env.d.ts

Repository: kortex-hub/kortex

Length of output: 2603


🏁 Script executed:

rg -n 'exposedInMainWorld' packages/ --type=ts --type=json --type=yaml

Repository: kortex-hub/kortex

Length of output: 274


Create missing exposedInMainWorld.d.ts file to properly type window.getChunkProviders.

The function is correctly exposed in the preload bridge, but the TypeScript type declaration file referenced in both packages/preload/tsconfig.json and packages/renderer/tsconfig.json is missing. This causes type-checking errors for window.getChunkProviders() in the renderer. Create packages/preload/exposedInMainWorld.d.ts with a declare global block that augments the Window interface to include the exposed methods, including getChunkProviders(): Promise<ChunkProviderInfo[]>.

🤖 Prompt for AI Agents
In `@packages/renderer/src/stores/chunk-providers.ts` around lines 44 - 45, Create
a new TypeScript declaration file named exposedInMainWorld.d.ts that adds a
declare global block augmenting the Window interface to include
getChunkProviders(): Promise<ChunkProviderInfo[]> (and any other preload-exposed
methods you use); ensure ChunkProviderInfo is either imported/declared or
referenced correctly so the renderer's fetchChunkProviders function and calls to
window.getChunkProviders are properly typed and the preload/renderer tsconfig
references include this declaration file.

@benoitf
Copy link
Contributor

benoitf commented Mar 6, 2026

moving to draft as it needs to solve conflicts

@benoitf benoitf marked this pull request as draft March 6, 2026 12:48
Part of kortex-hub#512

Signed-off-by: Jeff MAURY <jmaury@redhat.com>
@jeffmaury jeffmaury marked this pull request as ready for review March 9, 2026 13:50
@jeffmaury jeffmaury requested review from MarsKubeX and gastoner and removed request for axel7083 March 9, 2026 13:51
Signed-off-by: Jeff MAURY <jmaury@redhat.com>
Copy link
Contributor

@gastoner gastoner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments

@@ -0,0 +1,202 @@
<script lang="ts">
export let size = 20;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Svelte5 please 🥺

class="inline-flex items-center justify-center w-7 h-7 rounded bg-transparent text-gray-400 hover:bg-red-900/10 hover:text-red-400 transition-colors"
title="Delete"
aria-label="Delete environment">
<i class="fa fa-trash" aria-hidden="true"></i>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use Icon component here?
Import should be from import { Icon } from '@podman-desktop/ui-svelte/icons';

<circle cx="12" cy="12" r="10" />
<line x1="15" y1="9" x2="9" y2="15" />
<line x1="9" y1="9" x2="15" y2="15" />
</svg>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we create new icons in images folder?

const { object }: Props = $props();

// Extract chunker name from ID or show the ID
const chunkerName = getChunkProviderName($chunkProviders, object);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Should this be a $derived? I think if $chunkProviders updates, this won't re-derive.

<div class="source-item flex items-center justify-between px-5 py-4 border-b border-[var(--pd-content-divider)] last:border-b-0 hover:bg-[var(--pd-content-card-inset-bg)] transition-colors duration-200">
<div class="source-info flex items-center gap-3">
<div class="w-8 h-8 bg-[var(--pd-content-card-inset-bg)] rounded-md flex items-center justify-center text-[var(--pd-content-text-secondary)]">
<i class="fa fa-file fa-2x"></i>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use the icon component here too?

Comment on lines +190 to 194
public async deleteRagEnvironment(name: string): Promise<void> {
const filePath = this.getRagEnvironmentFilePath(name);
if (!existsSync(filePath)) {
return false;
throw new Error(`RAG environment ${name} not found`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has sense to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants