Skip to content

feat: basic model listing / search page #439

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Aug 2, 2025
Merged

Conversation

leonardmq
Copy link
Collaborator

@leonardmq leonardmq commented Jul 16, 2025

What does this PR do?

Add a new (very much open to changes) page to list and search through available models:

  • Uses the remote model list (may want to have it go through the backend API to have cleaner typing?)
  • Search by model slug or name (non-fuzzy for now)
  • Filter by provider, model family, and other criteria
  • Summary view per model showing:
    • Which providers support it
    • What features each provider supports

Why

Model discovery currently happens on external providers like OpenRouter. Users then need to manually map those models back to Kiln, where the names differ (OpenRouter gives a slug; and it is hard to know for sure which model it is in Kiln in some cases where the model is a narrow variant).

We can build on top of this later to let users click a model to go directly into the Run UI with the right model and provider selected or other such things.

Kapture.2025-07-16.at.19.04.07.mp4

Summary by CodeRabbit

  • New Features

    • Introduced a "Models" section in the app navigation, accessible from the sidebar.
    • Added a comprehensive Model Library page with search, filtering, and sorting capabilities for models.
    • Visual indicators for provider connection status and detailed model information, including capability badges and tooltips.
  • Bug Fixes

    • Loading and error states are now handled gracefully with informative messages and retry options.
  • Chores

    • Expanded the list of recognized model names to include new models.
    • Disabled server-side rendering for the Models page to enhance client-side performance.

Copy link
Contributor

coderabbitai bot commented Jul 16, 2025

Walkthrough

A new "Models" section has been added to the web UI's navigation and sidebar, along with a dedicated /models page. This page provides a searchable, filterable, and sortable model library interface, fetching model data from a remote source and displaying provider connection statuses. The API schema's ModelName enum is updated with new model identifiers, and server-side rendering is disabled for the models page.

Changes

Cohort / File(s) Change Summary
Navigation & Sidebar Update
app/web_ui/src/routes/(app)/+layout.svelte
Added a "Models" section to the navigation and sidebar by updating the Section enum, extending the reactive statement to recognize /models paths, and introducing a new sidebar menu item with icon and active state binding for the models section.
Models Page Implementation
app/web_ui/src/routes/(app)/models/+page.svelte
Introduced a comprehensive Svelte page for the model library, including interfaces for models and providers, state management for search/filter/sort, remote model data fetching, filter/sort logic, UI for filters and results, provider connection status, error/loading handling, and accessibility/UX enhancements.
SSR Disabled for Models Page
app/web_ui/src/routes/(app)/models/+page.ts
Disabled server-side rendering for the /models page by exporting ssr = false.
API Schema ModelName Update
app/web_ui/src/lib/api_schema.d.ts
Extended the ModelName enum to include "llama_4_maverick", "llama_4_scout", "deepseek_r1_0528", "grok_4", and "kimi_k2".

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ModelsPage
    participant RemoteConfig
    participant ProviderStore

    User->>ModelsPage: Navigates to /models
    ModelsPage->>RemoteConfig: Fetch model library JSON
    RemoteConfig-->>ModelsPage: Returns model data
    ModelsPage->>ProviderStore: Load connected providers
    ProviderStore-->>ModelsPage: Returns provider connection status
    ModelsPage->>User: Displays searchable/filterable/sortable model library
    User->>ModelsPage: Applies search/filter/sort
    ModelsPage->>User: Updates displayed models accordingly
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • tawnymanticore

Poem

A hop to the sidebar, a leap to explore,
The Models page opens—there’s so much in store!
With filters and badges, and sorting so neat,
Each model and provider, a new friend to meet.
The schema expands with names fresh and bright,
This bunny approves—what a wonderful sight!
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd51128 and 9a43f0b.

📒 Files selected for processing (1)
  • app/web_ui/src/routes/(app)/models/+page.svelte (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
app/web_ui/src/**/*.{js,jsx,ts,tsx,svelte}

📄 CodeRabbit Inference Engine (.cursor/rules/project.mdc)

Our web UI component framework is DaisyUI v4 (based on Tailwind). Be sure to use v4 docs and features, not v5

Files:

  • app/web_ui/src/routes/(app)/models/+page.svelte
🧠 Learnings (5)
📓 Common learnings
Learnt from: leonardmq
PR: Kiln-AI/Kiln#390
File: libs/core/kiln_ai/adapters/provider_tools.py:494-499
Timestamp: 2025-07-23T08:58:45.769Z
Learning: leonardmq prefers to keep tightly coupled implementation details (like API versions) hardcoded when they are not user-facing and could break other modules if changed. The shared Config class is reserved for user-facing customizable values, not internal implementation details.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#341
File: libs/server/kiln_server/document_api.py:44-51
Timestamp: 2025-06-18T08:22:58.510Z
Learning: leonardmq prefers to defer fixing blocking I/O in async handlers when: the operation is very fast (milliseconds), user-triggered rather than automated, has no concurrency concerns, and would require additional testing to fix properly. He acknowledges such issues as valid but makes pragmatic decisions about timing the fixes.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#402
File: libs/core/kiln_ai/adapters/embedding/litellm_embedding_adapter.py:0-0
Timestamp: 2025-07-14T03:43:07.283Z
Learning: leonardmq prefers to keep defensive validation checks even when they're technically redundant, viewing them as useful "quick sanity checks" that provide additional safety nets. He values defensive programming over strict DRY (Don't Repeat Yourself) principles when the redundant code serves as a safeguard.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#388
File: libs/core/kiln_ai/datamodel/test_extraction_chunk.py:49-74
Timestamp: 2025-07-03T05:13:02.873Z
Learning: leonardmq prefers automatic cleanup of temporary files in tests using `delete=True` in `tempfile.NamedTemporaryFile()` context managers, rather than manual cleanup with `delete=False` and explicit file removal. This is because automatic cleanup is simpler, safer, and avoids leaving temporary files if tests fail before cleanup.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#0
File: :0-0
Timestamp: 2025-06-27T06:45:06.591Z
Learning: leonardmq prefers unused imports to be flagged as actionable review comments rather than nitpick comments. Unused imports should be treated as concrete issues that need to be addressed, not just suggestions.
📚 Learning: in the kiln web ui's project import functionality (edit_project.svelte), when the file selector api ...
Learnt from: scosman
PR: Kiln-AI/Kiln#464
File: app/web_ui/src/routes/(fullscreen)/setup/(setup)/create_project/edit_project.svelte:116-138
Timestamp: 2025-07-30T02:50:29.383Z
Learning: In the Kiln web UI's project import functionality (edit_project.svelte), when the file selector API fails, the preferred approach is to use alert() as a brief notification and set select_file_unavailable = true to gracefully fall back to manual path entry, rather than using the form's error handling system. This maintains a smooth user experience with automatic fallback rather than showing an error state.

Applied to files:

  • app/web_ui/src/routes/(app)/models/+page.svelte
📚 Learning: in the kiln ai codebase, the friendly_name field always exists on model objects and is never undefin...
Learnt from: leonardmq
PR: Kiln-AI/Kiln#439
File: app/web_ui/src/routes/(app)/models/+page.svelte:211-230
Timestamp: 2025-08-01T13:07:27.911Z
Learning: In the Kiln AI codebase, the friendly_name field always exists on model objects and is never undefined or null, so null checks are not needed when accessing this field.

Applied to files:

  • app/web_ui/src/routes/(app)/models/+page.svelte
📚 Learning: leonardmq prefers unused imports to be flagged as actionable review comments rather than nitpick com...
Learnt from: leonardmq
PR: Kiln-AI/Kiln#0
File: :0-0
Timestamp: 2025-06-27T06:45:06.591Z
Learning: leonardmq prefers unused imports to be flagged as actionable review comments rather than nitpick comments. Unused imports should be treated as concrete issues that need to be addressed, not just suggestions.

Applied to files:

  • app/web_ui/src/routes/(app)/models/+page.svelte
📚 Learning: leonardmq prefers to keep defensive validation checks even when they're technically redundant, viewi...
Learnt from: leonardmq
PR: Kiln-AI/Kiln#402
File: libs/core/kiln_ai/adapters/embedding/litellm_embedding_adapter.py:0-0
Timestamp: 2025-07-14T03:43:07.283Z
Learning: leonardmq prefers to keep defensive validation checks even when they're technically redundant, viewing them as useful "quick sanity checks" that provide additional safety nets. He values defensive programming over strict DRY (Don't Repeat Yourself) principles when the redundant code serves as a safeguard.

Applied to files:

  • app/web_ui/src/routes/(app)/models/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04-arm)
  • GitHub Check: Build Desktop Apps (windows-latest)
  • GitHub Check: Build Desktop Apps (macos-latest)
  • GitHub Check: Build Desktop Apps (macos-13)
🔇 Additional comments (11)
app/web_ui/src/routes/(app)/models/+page.svelte (11)

1-12: LGTM! Clean imports and proper module organization.

The imports are well-organized and all appear to be used in the component. Good use of TypeScript imports and proper Svelte lifecycle functions.


14-59: LGTM! Well-structured interfaces and helpful tooltip messages.

The TypeScript interfaces provide comprehensive type safety, and the tooltip messages are user-friendly and descriptive. Good separation of concerns with dedicated interfaces for different data structures.


61-88: LGTM! Well-organized state management.

State variables are properly typed and initialized with sensible defaults. Good separation between different types of state (data, UI state, filter options).


90-112: LGTM! Proper reactive statements for select options.

Good use of Svelte reactivity to transform data into the format needed for the FancySelect components. The mapping logic is clean and efficient.


114-148: LGTM! Clean filter management logic.

The active filters reactive statement and removeFilter function are well-implemented. Good use of conditional arrays and proper state management for filter removal.


179-226: LGTM! Comprehensive and efficient filtering logic.

The filtering function properly handles text search across multiple fields, provider filtering, and capability-based filtering. The switch statement for capabilities is clean and covers all cases appropriately.


228-284: LGTM! Solid sorting implementation with proper state management.

Good use of toSorted() for immutability, and the sorting logic properly handles the friendly_name field. The toggleSort function correctly cycles through sort states, and clearFilters properly resets all filter and sort state.


286-357: LGTM! Well-organized capability badge logic.

Good separation between leading (suggested/starred) and trailing badges. The conditional logic properly prioritizes suggested capabilities and the color coding is consistent and meaningful.


359-368: LGTM! Proper reactive patterns and lifecycle management.

Good use of Svelte reactivity to automatically apply filters and sorting when state changes. The onMount logic correctly loads both local available models and remote configuration.


370-416: LGTM! Efficient connection detection with good UX helpers.

The refactored model_provider_is_connected function uses efficient find() and some() methods. Good special handling for finetune-only models and Ollama. The helper functions provide clear user guidance for connecting providers.


419-814: LGTM! Comprehensive and well-structured template with excellent UX.

The template demonstrates excellent use of DaisyUI v4 components and Tailwind CSS. Good implementation of:

  • Proper loading and error states
  • Responsive grid layout
  • Clear visual hierarchy
  • Accessibility features (tooltips, proper semantics)
  • Intuitive interaction patterns for filters and sorting
  • Proper handling of connected vs disconnected providers
  • Clean model card design with capability indicators

The component provides a polished user experience with comprehensive functionality.


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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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: 0

🧹 Nitpick comments (5)
app/web_ui/src/routes/(app)/models/+page.svelte (5)

145-147: Consider making the remote config URL configurable.

The URL is currently hard-coded. Consider moving it to an environment variable or configuration file for better flexibility across environments.

+import { PUBLIC_REMOTE_CONFIG_URL } from '$env/static/public'
+
 const response = await fetch(
-  "https://remote-config.getkiln.ai/kiln_config.json",
+  PUBLIC_REMOTE_CONFIG_URL || "https://remote-config.getkiln.ai/kiln_config.json",
 )

429-434: Consider debouncing the search input for better performance.

Currently, filtering runs on every keystroke. For large model lists, this could impact performance.

Add a debounced search handler:

import { debounce } from '$lib/utils/debounce'

let searchQuery = ""
let debouncedSearchQuery = ""

const handleSearch = debounce((value: string) => {
  debouncedSearchQuery = value
}, 300)

$: handleSearch(searchQuery)
$: debouncedSearchQuery, selectedFamily, selectedProvider, selectedCapability, models, applyFilters()

Then update the filter to use debouncedSearchQuery instead of searchQuery in the applyFilters function.


653-657: Improve image error handling with a fallback.

Currently, failed images are just hidden, leaving empty space. Consider showing a fallback icon or text.

+let imageErrors: Set<string> = new Set()
+
 on:error={(e) => {
   if (e.target instanceof HTMLImageElement) {
-    e.target.style.display = "none"
+    imageErrors.add(provider.name)
+    imageErrors = imageErrors // Trigger reactivity
   }
 }}

Then conditionally render a fallback:

{#if !imageErrors.has(provider.name)}
  <img ... />
{:else}
  <div class="w-6 h-6 rounded bg-gray-200 flex items-center justify-center text-xs">
    {provider.name.substring(0, 2).toUpperCase()}
  </div>
{/if}

1-700: Consider breaking this component into smaller, reusable parts.

At 700 lines, this component handles many responsibilities. Consider extracting:

  • ModelCard component for individual model display
  • FilterBar component for search and filters
  • CapabilityBadges component

This would improve maintainability and reusability.


79-89: Consider filtering providers based on selected family.

Currently, the provider dropdown shows all providers even when a family is selected. Consider showing only providers that offer models from the selected family.

$: availableProviders = selectedFamily
  ? [...new Set(
      models
        .filter(m => m.family === selectedFamily)
        .flatMap(m => m.providers.map(p => p.name))
    )].sort()
  : providers

$: providerOptions = [
  {
    options: [
      { label: "All Providers", value: "" },
      ...availableProviders.map((provider) => ({
        label: provider,
        value: provider,
      })),
    ],
  },
]
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e93fc35 and 2d6827b.

📒 Files selected for processing (3)
  • app/web_ui/src/routes/(app)/+layout.svelte (3 hunks)
  • app/web_ui/src/routes/(app)/models/+page.svelte (1 hunks)
  • app/web_ui/src/routes/(app)/models/+page.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: leonardmq
PR: Kiln-AI/Kiln#341
File: libs/server/kiln_server/document_api.py:44-51
Timestamp: 2025-06-18T08:22:58.510Z
Learning: leonardmq prefers to defer fixing blocking I/O in async handlers when: the operation is very fast (milliseconds), user-triggered rather than automated, has no concurrency concerns, and would require additional testing to fix properly. He acknowledges such issues as valid but makes pragmatic decisions about timing the fixes.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#402
File: libs/core/kiln_ai/adapters/embedding/litellm_embedding_adapter.py:0-0
Timestamp: 2025-07-14T03:43:07.265Z
Learning: leonardmq prefers to keep defensive validation checks even when they're technically redundant, viewing them as useful "quick sanity checks" that provide additional safety nets. He values defensive programming over strict DRY (Don't Repeat Yourself) principles when the redundant code serves as a safeguard.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#388
File: libs/core/kiln_ai/datamodel/test_extraction_chunk.py:49-74
Timestamp: 2025-07-03T05:13:02.873Z
Learning: leonardmq prefers automatic cleanup of temporary files in tests using `delete=True` in `tempfile.NamedTemporaryFile()` context managers, rather than manual cleanup with `delete=False` and explicit file removal. This is because automatic cleanup is simpler, safer, and avoids leaving temporary files if tests fail before cleanup.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#0
File: :0-0
Timestamp: 2025-06-27T06:45:06.591Z
Learning: leonardmq prefers unused imports to be flagged as actionable review comments rather than nitpick comments. Unused imports should be treated as concrete issues that need to be addressed, not just suggestions.
🔇 Additional comments (5)
app/web_ui/src/routes/(app)/models/+page.ts (1)

1-1: LGTM!

Disabling SSR is appropriate for this client-side interactive page with dynamic filtering and searching.

app/web_ui/src/routes/(app)/+layout.svelte (3)

28-28: LGTM!

The Models enum addition follows the existing pattern correctly.


76-77: LGTM!

The path detection for /models is implemented consistently with other routes.


403-432: LGTM!

The Models menu item is well-structured with proper SVG attribution and consistent styling.

app/web_ui/src/routes/(app)/models/+page.svelte (1)

228-228: Review Browser Compatibility for toSorted()

The Array.prototype.toSorted() method was introduced in ES2023 (June 2023) and is supported in:

  • Chrome 110+
  • Edge 110+
  • Firefox 115+
  • Safari 16.4+
  • Opera 96+

It returns a new sorted array without mutating the original. If your application must run on any browsers older than these versions, you’ll need to either:

• Add a polyfill (e.g., via core-js)
• Or fall back to a non-mutating sort():

- filteredModels = filteredModels.toSorted((a, b) => {
+ filteredModels = [...filteredModels].sort((a, b) => {

Location to verify:

  • app/web_ui/src/routes/(app)/models/+page.svelte, line 228

Please confirm your supported browser matrix and adjust accordingly.

@scosman
Copy link
Collaborator

scosman commented Jul 16, 2025

whaaaat

@scosman
Copy link
Collaborator

scosman commented Jul 16, 2025

Screenshot 2025-07-16 at 1 11 47 PM Some minor wrapping issues

@scosman
Copy link
Collaborator

scosman commented Jul 16, 2025

This is great. Some small nits:

Can we make "suggested" models pop a little at the top level?

  • "Data Gen" Badge could be "Data Gen ★" or "Data Gen +" for suggested, with the tool tip being more verbose on what's special "Recommended for Data Gen - one of the best models.". Same for anywhere we have suggestions (uncensored, etc)

Tooltips need a little work:

  • "Supports Data Gen" -> "Supports synthetic data gen: tested with Kiln's data gen tool."
  • "Supports structured output" -> "Supported structured output (JSON) preferring the tool-calling method".
  • "Support Logprobs" -> "Supports logprobs, a feature needed for the advanced eval method G-Eval".
  • "Uncensored model which will produce any outputs (biased, malicious). Useful for adversarial evals."

title "Models" "Model Library"
Subtitle: "Browse available models"

@scosman
Copy link
Collaborator

scosman commented Jul 16, 2025

We should probably make friendly family names (or we can just skip showing them)

@scosman
Copy link
Collaborator

scosman commented Jul 16, 2025

Provider names should be pretty. We have a utility for this.

@scosman
Copy link
Collaborator

scosman commented Jul 16, 2025

We should have a UI indicator if I don't have a provider connected. Something subtle. just color ideally, great out logo/title a bit?

Clicking should take you to connect_providers

@scosman
Copy link
Collaborator

scosman commented Jul 16, 2025

"No models found" SVG needs some work. Sonnet can't draw.

Sidebar icon should be: https://www.svgrepo.com/svg/524675/library

@leonardmq leonardmq force-pushed the leonard/model-library branch from 2d6827b to b6a81b8 Compare July 22, 2025 04:56
Copy link
Contributor

@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: 0

🧹 Nitpick comments (2)
app/web_ui/src/routes/(app)/models/+page.svelte (2)

156-183: Consider adding request timeout and better error specificity.

The function correctly fetches from the remote config, but could benefit from:

  • Request timeout to prevent hanging requests
  • More specific error messages for different failure scenarios
 async function fetchModelsFromRemoteConfig() {
   try {
     loading = true
     error = null

-    const response = await fetch(
-      "https://remote-config.getkiln.ai/kiln_config.json",
-    )
+    const controller = new AbortController()
+    const timeoutId = setTimeout(() => controller.abort(), 10000) // 10 second timeout
+    
+    const response = await fetch(
+      "https://remote-config.getkiln.ai/kiln_config.json",
+      { signal: controller.signal }
+    )
+    clearTimeout(timeoutId)
     if (!response.ok) {
-      throw new Error(`Failed to fetch models: ${response.status}`)
+      throw new Error(`Failed to fetch models: ${response.status} ${response.statusText}`)
     }

252-280: Consider performance optimization for large datasets.

The sorting implementation is correct but uses toSorted() which creates a new array. For large datasets, consider performance implications.

-  filteredModels = filteredModels.toSorted((a, b) => {
+  filteredModels.sort((a, b) => {

Note: This would modify the array in place rather than creating a new one, which is more memory efficient for large datasets.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d6827b and 492f090.

📒 Files selected for processing (5)
  • app/web_ui/src/lib/utils/provider_utils.ts (1 hunks)
  • app/web_ui/src/routes/(app)/+layout.svelte (3 hunks)
  • app/web_ui/src/routes/(app)/models/+page.svelte (1 hunks)
  • app/web_ui/src/routes/(app)/settings/providers/add_models/+page.svelte (2 hunks)
  • app/web_ui/src/routes/(fullscreen)/setup/(setup)/connect_providers/connect_providers.svelte (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/web_ui/src/routes/(app)/+layout.svelte
🧰 Additional context used
📓 Path-based instructions (1)
app/web_ui/src/**/*.{js,jsx,ts,tsx,svelte}

📄 CodeRabbit Inference Engine (.cursor/rules/project.mdc)

Our web UI component framework is DaisyUI v4 (based on Tailwind). Be sure to use v4 docs and features, not v5

Files:

  • app/web_ui/src/lib/utils/provider_utils.ts
  • app/web_ui/src/routes/(app)/settings/providers/add_models/+page.svelte
  • app/web_ui/src/routes/(fullscreen)/setup/(setup)/connect_providers/connect_providers.svelte
  • app/web_ui/src/routes/(app)/models/+page.svelte
🧠 Learnings (1)
📓 Common learnings
Learnt from: leonardmq
PR: Kiln-AI/Kiln#390
File: libs/core/kiln_ai/adapters/provider_tools.py:494-499
Timestamp: 2025-07-23T08:58:45.769Z
Learning: leonardmq prefers to keep tightly coupled implementation details (like API versions) hardcoded when they are not user-facing and could break other modules if changed. The shared Config class is reserved for user-facing customizable values, not internal implementation details.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#341
File: libs/server/kiln_server/document_api.py:44-51
Timestamp: 2025-06-18T08:22:58.510Z
Learning: leonardmq prefers to defer fixing blocking I/O in async handlers when: the operation is very fast (milliseconds), user-triggered rather than automated, has no concurrency concerns, and would require additional testing to fix properly. He acknowledges such issues as valid but makes pragmatic decisions about timing the fixes.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#402
File: libs/core/kiln_ai/adapters/embedding/litellm_embedding_adapter.py:0-0
Timestamp: 2025-07-14T03:43:07.283Z
Learning: leonardmq prefers to keep defensive validation checks even when they're technically redundant, viewing them as useful "quick sanity checks" that provide additional safety nets. He values defensive programming over strict DRY (Don't Repeat Yourself) principles when the redundant code serves as a safeguard.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#388
File: libs/core/kiln_ai/datamodel/test_extraction_chunk.py:49-74
Timestamp: 2025-07-03T05:13:02.873Z
Learning: leonardmq prefers automatic cleanup of temporary files in tests using `delete=True` in `tempfile.NamedTemporaryFile()` context managers, rather than manual cleanup with `delete=False` and explicit file removal. This is because automatic cleanup is simpler, safer, and avoids leaving temporary files if tests fail before cleanup.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#0
File: :0-0
Timestamp: 2025-06-27T06:45:06.591Z
Learning: leonardmq prefers unused imports to be flagged as actionable review comments rather than nitpick comments. Unused imports should be treated as concrete issues that need to be addressed, not just suggestions.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Desktop Apps (windows-latest)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04-arm)
  • GitHub Check: Build Desktop Apps (macos-latest)
  • GitHub Check: Build Desktop Apps (macos-13)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04)
🔇 Additional comments (19)
app/web_ui/src/lib/utils/provider_utils.ts (2)

1-1: LGTM! Good type definition for provider settings.

The ProviderSettings type alias provides appropriate flexibility for the settings structure while maintaining type safety.


6-53: Well-structured provider connection utility function.

The centralized approach using a switch statement is clean and maintainable. The function correctly handles different provider authentication patterns:

  • Single API key providers (OpenAI, Anthropic, etc.)
  • Multi-credential providers (Amazon Bedrock, Fireworks AI, etc.)
  • Array-based providers (OpenAI compatible)
  • Special cases like Ollama

The double negation (!!) ensures boolean return values, and the default case appropriately returns false for unknown provider IDs.

app/web_ui/src/routes/(app)/settings/providers/add_models/+page.svelte (2)

9-9: LGTM! Proper import of the utility function.

Good use of the centralized provider connection utility.


33-35: Excellent refactoring using the centralized utility.

The refactored logic is much cleaner and more maintainable:

  • Eliminates repetitive manual checks
  • Uses the centralized checkProviderConnection function
  • Maintains the same functionality with less code

This approach ensures consistency across the application for provider connection checks.

app/web_ui/src/routes/(fullscreen)/setup/(setup)/connect_providers/connect_providers.svelte (3)

13-13: LGTM! Proper import of the utility function.

Consistent use of the centralized provider connection utility across components.


530-559: Excellent refactoring with improved error handling.

The refactored logic provides several improvements:

  • Uses the centralized checkProviderConnection utility for consistency
  • Cleaner iteration through provider IDs
  • Better error handling with specific error throwing
  • Maintains the same functionality with more maintainable code

The approach ensures all provider connection checks use the same logic across the application.


582-582: Nice typo fix in the comment.

The correction from "epmemerial" to "ephemeral" improves code readability.

app/web_ui/src/routes/(app)/models/+page.svelte (12)

18-42: Well-designed TypeScript interfaces.

The interfaces provide good type safety and clearly define the data structure:

  • Provider interface captures all the necessary model provider attributes
  • Model interface with providers array supports multiple provider scenarios
  • ConfigData wrapper provides proper typing for the API response

The interface design supports the filtering and capability features effectively.


44-69: Good state management organization.

The state variables are well-organized and cover all the necessary functionality:

  • Separate state for models, filtered results, and UI states
  • Clear separation of search, filter, and sort state
  • Predefined capability options with user-friendly labels

The organization makes the component logic easy to follow.


78-140: Excellent reactive data transformations.

The reactive statements effectively transform arrays into the required option group format for the FancySelect component. The active filters computation provides a clean way to display current filter state with proper labels.


185-196: LGTM! Proper provider settings loading.

The function correctly loads provider settings with appropriate error handling and logging.


199-249: Robust filtering implementation.

The filtering logic is comprehensive and handles all the required scenarios:

  • Text search across multiple model fields
  • Family, provider, and capability filtering
  • Proper case-insensitive string matching
  • Good use of array methods for provider capability checks

The implementation correctly combines all filter criteria.


318-371: Excellent capability badge implementation with user-friendly tooltips.

The function provides comprehensive capability badges with descriptive tooltips that align with the PR feedback requirements:

  • "Data Gen ★" and "Evals ★" badges for recommended models
  • Descriptive tooltips explaining each capability
  • Proper color coding for different badge types
  • Handles uncensored models with appropriate explanations

The implementation addresses the PR feedback about making tooltips more descriptive and user-friendly.


394-402: Smart provider connection handling.

The function correctly uses the centralized provider connection utility and provides intuitive UX by navigating disconnected users to the provider settings page.


405-415: Proper page metadata and title structure.

The page uses appropriate title and subtitle that align with the PR feedback ("Model Library" and "Browse available models").


417-460: Comprehensive loading and error states.

The loading and error states provide good user experience:

  • Clear loading indicators
  • Detailed error messages
  • Retry functionality
  • Proper error styling using DaisyUI v4 classes

The implementation handles edge cases gracefully.


462-636: Well-structured search and filter UI.

The search and filter interface provides excellent UX:

  • Clear search input with proper placeholder
  • Organized filter dropdowns using FancySelect
  • Active filter badges with removal functionality
  • Results count display
  • Clear filters functionality
  • Sorting controls with visual indicators

The implementation uses appropriate DaisyUI v4 classes and follows good accessibility practices.


640-661: User-friendly empty state.

The "No models found" state provides helpful guidance to users with clear messaging and suggestions for adjusting search criteria.


663-770: Excellent model grid implementation with provider connection indicators.

The model grid provides comprehensive information:

  • Clean card layout with proper hierarchy
  • Capability badges with tooltips
  • Provider information with connection status
  • Visual indicators for disconnected providers (grayscale, opacity)
  • Clickable navigation for disconnected providers
  • Proper error handling for missing provider images
  • Feature indicator dots with tooltips

The implementation addresses the PR feedback about showing provider connection status and follows DaisyUI v4 patterns.

Copy link
Contributor

@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: 2

🧹 Nitpick comments (3)
app/web_ui/src/routes/(app)/models/+page.svelte (3)

157-197: Solid data fetching implementation with proper error handling.

Both functions handle errors appropriately and follow good async/await patterns. The provider settings loading integrates well with the existing API client pattern.

Consider making the remote config URL configurable rather than hardcoded:

- const response = await fetch(
-   "https://remote-config.getkiln.ai/kiln_config.json",
- )
+ const configUrl = import.meta.env.VITE_REMOTE_CONFIG_URL || "https://remote-config.getkiln.ai/kiln_config.json"
+ const response = await fetch(configUrl)

687-687: Consider using word-break instead of break-all.

Using break-all can break words at any character, which may harm readability. Consider break-words instead.

- <h3 class="text-lg font-semibold text-gray-900 break-all">
+ <h3 class="text-lg font-semibold text-gray-900 break-words">

754-754: Consider using break-words for model IDs.

Similar to the model name, break-all might break model IDs at inappropriate points.

- class="text-xs {isConnected
-   ? 'text-gray-500'
-   : 'text-gray-400'} break-all"
+ class="text-xs {isConnected
+   ? 'text-gray-500'
+   : 'text-gray-400'} break-words"
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 492f090 and 2c6bd75.

⛔ Files ignored due to path filters (2)
  • app/web_ui/static/images/delete.svg is excluded by !**/*.svg
  • app/web_ui/static/images/library.svg is excluded by !**/*.svg
📒 Files selected for processing (2)
  • app/web_ui/src/routes/(app)/+layout.svelte (3 hunks)
  • app/web_ui/src/routes/(app)/models/+page.svelte (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/web_ui/src/routes/(app)/+layout.svelte
🧰 Additional context used
📓 Path-based instructions (1)
app/web_ui/src/**/*.{js,jsx,ts,tsx,svelte}

📄 CodeRabbit Inference Engine (.cursor/rules/project.mdc)

Our web UI component framework is DaisyUI v4 (based on Tailwind). Be sure to use v4 docs and features, not v5

Files:

  • app/web_ui/src/routes/(app)/models/+page.svelte
🧠 Learnings (1)
📓 Common learnings
Learnt from: leonardmq
PR: Kiln-AI/Kiln#390
File: libs/core/kiln_ai/adapters/provider_tools.py:494-499
Timestamp: 2025-07-23T08:58:45.769Z
Learning: leonardmq prefers to keep tightly coupled implementation details (like API versions) hardcoded when they are not user-facing and could break other modules if changed. The shared Config class is reserved for user-facing customizable values, not internal implementation details.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#341
File: libs/server/kiln_server/document_api.py:44-51
Timestamp: 2025-06-18T08:22:58.510Z
Learning: leonardmq prefers to defer fixing blocking I/O in async handlers when: the operation is very fast (milliseconds), user-triggered rather than automated, has no concurrency concerns, and would require additional testing to fix properly. He acknowledges such issues as valid but makes pragmatic decisions about timing the fixes.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#402
File: libs/core/kiln_ai/adapters/embedding/litellm_embedding_adapter.py:0-0
Timestamp: 2025-07-14T03:43:07.283Z
Learning: leonardmq prefers to keep defensive validation checks even when they're technically redundant, viewing them as useful "quick sanity checks" that provide additional safety nets. He values defensive programming over strict DRY (Don't Repeat Yourself) principles when the redundant code serves as a safeguard.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#388
File: libs/core/kiln_ai/datamodel/test_extraction_chunk.py:49-74
Timestamp: 2025-07-03T05:13:02.873Z
Learning: leonardmq prefers automatic cleanup of temporary files in tests using `delete=True` in `tempfile.NamedTemporaryFile()` context managers, rather than manual cleanup with `delete=False` and explicit file removal. This is because automatic cleanup is simpler, safer, and avoids leaving temporary files if tests fail before cleanup.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#0
File: :0-0
Timestamp: 2025-06-27T06:45:06.591Z
Learning: leonardmq prefers unused imports to be flagged as actionable review comments rather than nitpick comments. Unused imports should be treated as concrete issues that need to be addressed, not just suggestions.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04-arm)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04)
  • GitHub Check: Build Desktop Apps (macos-13)
  • GitHub Check: Build Desktop Apps (macos-latest)
  • GitHub Check: Build Desktop Apps (windows-latest)
🔇 Additional comments (7)
app/web_ui/src/routes/(app)/models/+page.svelte (7)

19-43: Well-structured TypeScript interfaces.

The interface definitions are comprehensive and clearly define the data structures for providers, models, and configuration data. The boolean flags in the Provider interface align well with the filtering capabilities implemented later in the component.


45-76: Comprehensive state management setup.

The state variables are well-organized and cover all aspects of the model library functionality including search, filtering, sorting, and data management. The capabilities array provides a clean mapping between internal values and user-facing labels.


79-140: Effective use of Svelte reactivity.

The reactive statements properly transform data for UI components and create clean filter badge representations. The use of Svelte's $: syntax is appropriate and the computed properties will update correctly when dependencies change.


143-155: Clean filter removal implementation.

The removeFilter function properly handles all filter types with a clear switch statement. The implementation is straightforward and effective.


199-309: Comprehensive filtering and sorting implementation.

The filtering logic properly handles multiple criteria including text search, family, provider, and capability filters. The use of toSorted() maintains immutability, and the sort toggling logic provides a good user experience by cycling through ascending, descending, and no sorting.


311-403: Well-designed utility functions and reactive coordination.

The getCapabilityBadges function creates comprehensive badge information with appropriate tooltips that align with the PR requirements. The reactive statements properly coordinate filtering and sorting updates, and the onMount function correctly orchestrates the data loading sequence.


406-791: Excellent template implementation with comprehensive functionality.

The template effectively implements all the requirements from the PR objectives including:

  • Model search and filtering capabilities
  • Provider connection status indicators
  • Capability badges with descriptive tooltips
  • Responsive grid layout
  • Proper loading and error states
  • Clean, polished UI using DaisyUI v4

The implementation aligns well with the feedback suggestions and provides a solid foundation for the model library feature.

@leonardmq
Copy link
Collaborator Author

Made changes based on all the comments above, except for greying out providers the user hasn’t connected yet for which ollama handling is missing still.

ollama connection status is not handled yet because the logic for checking provider connection is very tied to the connect_providers pages so needs a refactor to extract things out.

Ideally, we would keep the provider connection info in a Svelte store, but that will add complexity (and I am not totally solid on the patterns around stores in Svelte). Our current store setup already has some issues (refreshing the browser sometimes not triggering the correct initialization, invalidation logic not propagating correctly, and scattered triggering logic). Adding a provider store would add more complexity (maybe justified?): we would need to correctly refresh it if the user connects a provider, handle edge cases like multi-tab scenarios, etc.

Regarding provider friendly names: I found the provider_name_from_id method to do this, but it’s tied to the model store. So it only works if all available models have been loaded (so we need to do that onMount wherever it is used; or navigate from a page that already loaded that store). There also is a bug: it only knows about providers the user already has access to (since it derives provider names from existing models the user has access to), so it does not return names for providers the user has not connected.

Open question: should this page pull from remote_config or the local API? Using remote_config risks older clients not being able to handle newly added providers - unless we replicate the backend filtering logic to skip unsupported models / providers (maybe fine to do that as fairly trivial?).

Copy link
Contributor

@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: 1

♻️ Duplicate comments (2)
app/web_ui/src/routes/(app)/models/+page.svelte (2)

672-673: Improve text contrast for accessibility.

The text color class should provide better contrast for accessibility compliance.

The existing past review comment correctly identified this issue. Consider using a darker text color:

- <h3 class="mt-2 text-sm font-medium text-gray-900">
+ <h3 class="mt-2 text-sm font-medium text-gray-900">

Note: The past comment suggested changing from text-neutral-content to text-gray-900, but the current code already uses text-gray-900 which is correct.


720-728: Address accessibility concerns properly.

The svelte-ignore comments disable important accessibility checks for click events on a div element.

As noted in the past review, this creates accessibility issues. The existing suggestion to add proper keyboard navigation and ARIA attributes should be implemented:

- <!-- svelte-ignore a11y-click-events-have-key-events -->
- <!-- svelte-ignore a11y-no-static-element-interactions -->
  <div
    class="flex items-center justify-between p-3 bg-gray-50 rounded-md {!isConnected
      ? 'opacity-50 cursor-pointer hover:opacity-60 transition-all'
      : ''}"
+   role={!isConnected ? "button" : undefined}
+   tabindex={!isConnected ? "0" : undefined}
    on:click={!isConnected
      ? () => handle_provider_click(provider.name)
      : undefined}
+   on:keydown={!isConnected
+     ? (e) => {
+         if (e.key === 'Enter' || e.key === ' ') {
+           e.preventDefault();
+           handle_provider_click(provider.name);
+         }
+       }
+     : undefined}
  >
🧹 Nitpick comments (7)
app/web_ui/src/routes/(app)/models/+page.svelte (7)

7-10: Consider using direct imports instead of barrel exports.

The import from ../../../lib/stores suggests using a barrel export pattern. Consider importing load_available_models and provider_name_from_id directly from their specific modules for better tree-shaking and clearer dependencies.

- import {
-   load_available_models,
-   provider_name_from_id,
- } from "../../../lib/stores"
+ import { load_available_models } from "../../../lib/stores/models"
+ import { provider_name_from_id } from "../../../lib/stores/providers"

200-250: Optimize search performance with debouncing.

The search function runs on every keystroke which could impact performance with large model lists. Consider debouncing the search input.

You can implement debouncing by adding a debounced search function:

import { debounce } from 'lodash-es'

// Add after other reactive statements
const debouncedApplyFilters = debounce(applyFilters, 300)

// Replace the reactive statement at line 375-380
$: searchQuery, debouncedApplyFilters()

374-383: Optimize reactive statements to prevent unnecessary updates.

The current reactive statements may cause excessive re-runs. Consider combining related reactive logic and using more specific dependencies.

- // Watch for filter changes
- $: searchQuery,
-   selectedFamily,
-   selectedProvider,
-   selectedCapability,
-   models,
-   applyFilters()
-
- // Watch for sort changes
- $: sortBy, sortDirection, applySorting()
+ // Combined reactive statement for all changes
+ $: {
+   if (models.length > 0) {
+     applyFilters()
+   }
+ }

385-393: Consider parallel loading for better performance.

The sequential loading of models and provider settings could be optimized by running them in parallel since they're independent operations.

  onMount(async () => {
    // we need to seed the available models in the Svelte store, because we get
    // the provider friendly name formatter from there, but we load the actual
    // model list from the remote config, because that is the most up to date
-   await load_available_models()
-   await fetchModelsFromRemoteConfig()
-   // Load provider connection status for displaying connection indicators
-   await load_provider_settings()
+   await Promise.all([
+     load_available_models(),
+     fetchModelsFromRemoteConfig(),
+     load_provider_settings()
+   ])
  })

737-741: Improve image error handling.

The current error handler hides the image but leaves an empty space. Consider showing a fallback icon or placeholder.

  on:error={(e) => {
    if (e.target instanceof HTMLImageElement) {
-     e.target.style.display = "none"
+     e.target.src = "/fallback-provider-icon.svg"
+     e.target.alt = `${provider.name} (fallback icon)`
    }
  }}

614-615: Improve CSS class readability with consistent formatting.

The long conditional class string is hard to read and maintain. Consider extracting the logic or using a more readable format.

- class="inline-flex items-center px-3 py-1.5 text-sm font-medium rounded-md transition-colors {sortBy ===
- option.value
-   ? 'text-gray-700 bg-gray-100 hover:bg-gray-200'
-   : 'text-gray-600 hover:text-gray-900 hover:bg-gray-100 border border-transparent'}"
+ class="inline-flex items-center px-3 py-1.5 text-sm font-medium rounded-md transition-colors {sortBy === option.value 
+   ? 'text-gray-700 bg-gray-100 hover:bg-gray-200' 
+   : 'text-gray-600 hover:text-gray-900 hover:bg-gray-100 border border-transparent'}"

162-164: Consider making the remote config URL configurable.

The hardcoded URL could be made configurable through environment variables for different deployment environments.

+ import { env } from '$env/dynamic/public'

- const response = await fetch(
-   "https://remote-config.getkiln.ai/kiln_config.json",
- )
+ const configUrl = env.PUBLIC_REMOTE_CONFIG_URL || "https://remote-config.getkiln.ai/kiln_config.json"
+ const response = await fetch(configUrl)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c6bd75 and d9e9a17.

📒 Files selected for processing (1)
  • app/web_ui/src/routes/(app)/models/+page.svelte (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
app/web_ui/src/**/*.{js,jsx,ts,tsx,svelte}

📄 CodeRabbit Inference Engine (.cursor/rules/project.mdc)

Our web UI component framework is DaisyUI v4 (based on Tailwind). Be sure to use v4 docs and features, not v5

Files:

  • app/web_ui/src/routes/(app)/models/+page.svelte
🧠 Learnings (1)
📓 Common learnings
Learnt from: leonardmq
PR: Kiln-AI/Kiln#390
File: libs/core/kiln_ai/adapters/provider_tools.py:494-499
Timestamp: 2025-07-23T08:58:45.769Z
Learning: leonardmq prefers to keep tightly coupled implementation details (like API versions) hardcoded when they are not user-facing and could break other modules if changed. The shared Config class is reserved for user-facing customizable values, not internal implementation details.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#341
File: libs/server/kiln_server/document_api.py:44-51
Timestamp: 2025-06-18T08:22:58.510Z
Learning: leonardmq prefers to defer fixing blocking I/O in async handlers when: the operation is very fast (milliseconds), user-triggered rather than automated, has no concurrency concerns, and would require additional testing to fix properly. He acknowledges such issues as valid but makes pragmatic decisions about timing the fixes.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#402
File: libs/core/kiln_ai/adapters/embedding/litellm_embedding_adapter.py:0-0
Timestamp: 2025-07-14T03:43:07.283Z
Learning: leonardmq prefers to keep defensive validation checks even when they're technically redundant, viewing them as useful "quick sanity checks" that provide additional safety nets. He values defensive programming over strict DRY (Don't Repeat Yourself) principles when the redundant code serves as a safeguard.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#388
File: libs/core/kiln_ai/datamodel/test_extraction_chunk.py:49-74
Timestamp: 2025-07-03T05:13:02.873Z
Learning: leonardmq prefers automatic cleanup of temporary files in tests using `delete=True` in `tempfile.NamedTemporaryFile()` context managers, rather than manual cleanup with `delete=False` and explicit file removal. This is because automatic cleanup is simpler, safer, and avoids leaving temporary files if tests fail before cleanup.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#0
File: :0-0
Timestamp: 2025-06-27T06:45:06.591Z
Learning: leonardmq prefers unused imports to be flagged as actionable review comments rather than nitpick comments. Unused imports should be treated as concrete issues that need to be addressed, not just suggestions.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04)
  • GitHub Check: Build Desktop Apps (macos-13)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04-arm)
  • GitHub Check: Build Desktop Apps (windows-latest)
  • GitHub Check: Build Desktop Apps (macos-latest)
🔇 Additional comments (3)
app/web_ui/src/routes/(app)/models/+page.svelte (3)

19-32: Well-structured TypeScript interfaces.

The Provider interface comprehensively captures all the model capabilities and metadata. The boolean flags are clear and the naming follows good conventions.


258-281: Good use of toSorted for immutable sorting.

Using toSorted() instead of sort() maintains immutability which is excellent for Svelte's reactivity system.


96-98: provider_name_from_id behavior is correct and covered by tests

The provider_name_from_id function in app/web_ui/src/lib/stores.ts returns:

  • "Unknown" when passed an empty string
  • the matched provider_name from the available_models store for known providers
  • the raw provider_id for any unmatched ID

Unit tests in app/web_ui/src/lib/stores.test.ts already verify these scenarios. No further changes are required here.

Comment on lines 157 to 184
async function fetchModelsFromRemoteConfig() {
try {
loading = true
error = null

const response = await fetch(
"https://remote-config.getkiln.ai/kiln_config.json",
)
if (!response.ok) {
throw new Error(`Failed to fetch models: ${response.status}`)
}

const data: ConfigData = await response.json()
models = data.model_list

// Extract unique families and providers for filters
families = [...new Set(models.map((m) => m.family))].sort()
providers = [
...new Set(models.flatMap((m) => m.providers.map((p) => p.name))),
].sort()

applyFilters()
} catch (err) {
error = createKilnError(err)
} finally {
loading = false
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add request timeout and improve error handling.

The fetch request lacks a timeout and could benefit from more specific error handling for different HTTP status codes.

  async function fetchModelsFromRemoteConfig() {
    try {
      loading = true
      error = null

-     const response = await fetch(
-       "https://remote-config.getkiln.ai/kiln_config.json",
-     )
+     const controller = new AbortController()
+     const timeoutId = setTimeout(() => controller.abort(), 10000) // 10 second timeout
+     
+     const response = await fetch(
+       "https://remote-config.getkiln.ai/kiln_config.json",
+       { signal: controller.signal }
+     )
+     clearTimeout(timeoutId)
+     
      if (!response.ok) {
-       throw new Error(`Failed to fetch models: ${response.status}`)
+       throw new Error(`Failed to fetch models: ${response.status} ${response.statusText}`)
      }
📝 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
async function fetchModelsFromRemoteConfig() {
try {
loading = true
error = null
const response = await fetch(
"https://remote-config.getkiln.ai/kiln_config.json",
)
if (!response.ok) {
throw new Error(`Failed to fetch models: ${response.status}`)
}
const data: ConfigData = await response.json()
models = data.model_list
// Extract unique families and providers for filters
families = [...new Set(models.map((m) => m.family))].sort()
providers = [
...new Set(models.flatMap((m) => m.providers.map((p) => p.name))),
].sort()
applyFilters()
} catch (err) {
error = createKilnError(err)
} finally {
loading = false
}
}
async function fetchModelsFromRemoteConfig() {
try {
loading = true
error = null
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 10000) // 10 second timeout
const response = await fetch(
"https://remote-config.getkiln.ai/kiln_config.json",
{ signal: controller.signal }
)
clearTimeout(timeoutId)
if (!response.ok) {
throw new Error(`Failed to fetch models: ${response.status} ${response.statusText}`)
}
const data: ConfigData = await response.json()
models = data.model_list
// Extract unique families and providers for filters
families = [...new Set(models.map((m) => m.family))].sort()
providers = [
...new Set(models.flatMap((m) => m.providers.map((p) => p.name))),
].sort()
applyFilters()
} catch (err) {
error = createKilnError(err)
} finally {
loading = false
}
}
🤖 Prompt for AI Agents
In app/web_ui/src/routes/(app)/models/+page.svelte between lines 157 and 184,
the fetchModelsFromRemoteConfig function lacks a request timeout and has generic
error handling. To fix this, implement a timeout mechanism for the fetch request
using AbortController to abort the request if it exceeds a set duration.
Additionally, enhance error handling by checking for specific HTTP status codes
(e.g., 404, 500) and provide more descriptive error messages accordingly before
throwing errors. This will improve reliability and clarity of error reporting.

Copy link
Contributor

@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: 0

♻️ Duplicate comments (1)
app/web_ui/src/routes/(app)/models/+page.svelte (1)

157-184: Previously flagged timeout issue remains unaddressed.

The fetch request still lacks the timeout mechanism that was suggested in previous reviews. This could lead to hanging requests if the remote config endpoint is slow or unresponsive.

🧹 Nitpick comments (1)
app/web_ui/src/routes/(app)/models/+page.svelte (1)

721-721: Consider addressing the accessibility ignore rather than suppressing it.

The svelte-ignore a11y-no-noninteractive-tabindex suggests there's still an accessibility concern that's being suppressed rather than properly resolved. Consider if the tabindex logic can be restructured to avoid this warning.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d9e9a17 and 103109c.

📒 Files selected for processing (1)
  • app/web_ui/src/routes/(app)/models/+page.svelte (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
app/web_ui/src/**/*.{js,jsx,ts,tsx,svelte}

📄 CodeRabbit Inference Engine (.cursor/rules/project.mdc)

Our web UI component framework is DaisyUI v4 (based on Tailwind). Be sure to use v4 docs and features, not v5

Files:

  • app/web_ui/src/routes/(app)/models/+page.svelte
🧠 Learnings (1)
📓 Common learnings
Learnt from: leonardmq
PR: Kiln-AI/Kiln#390
File: libs/core/kiln_ai/adapters/provider_tools.py:494-499
Timestamp: 2025-07-23T08:58:45.769Z
Learning: leonardmq prefers to keep tightly coupled implementation details (like API versions) hardcoded when they are not user-facing and could break other modules if changed. The shared Config class is reserved for user-facing customizable values, not internal implementation details.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#341
File: libs/server/kiln_server/document_api.py:44-51
Timestamp: 2025-06-18T08:22:58.510Z
Learning: leonardmq prefers to defer fixing blocking I/O in async handlers when: the operation is very fast (milliseconds), user-triggered rather than automated, has no concurrency concerns, and would require additional testing to fix properly. He acknowledges such issues as valid but makes pragmatic decisions about timing the fixes.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#402
File: libs/core/kiln_ai/adapters/embedding/litellm_embedding_adapter.py:0-0
Timestamp: 2025-07-14T03:43:07.283Z
Learning: leonardmq prefers to keep defensive validation checks even when they're technically redundant, viewing them as useful "quick sanity checks" that provide additional safety nets. He values defensive programming over strict DRY (Don't Repeat Yourself) principles when the redundant code serves as a safeguard.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#388
File: libs/core/kiln_ai/datamodel/test_extraction_chunk.py:49-74
Timestamp: 2025-07-03T05:13:02.873Z
Learning: leonardmq prefers automatic cleanup of temporary files in tests using `delete=True` in `tempfile.NamedTemporaryFile()` context managers, rather than manual cleanup with `delete=False` and explicit file removal. This is because automatic cleanup is simpler, safer, and avoids leaving temporary files if tests fail before cleanup.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#0
File: :0-0
Timestamp: 2025-06-27T06:45:06.591Z
Learning: leonardmq prefers unused imports to be flagged as actionable review comments rather than nitpick comments. Unused imports should be treated as concrete issues that need to be addressed, not just suggestions.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04)
  • GitHub Check: Build Desktop Apps (macos-latest)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04-arm)
  • GitHub Check: Build Desktop Apps (macos-13)
  • GitHub Check: Build Desktop Apps (windows-latest)
🔇 Additional comments (7)
app/web_ui/src/routes/(app)/models/+page.svelte (7)

1-44: Well-structured imports and TypeScript interfaces.

The imports are appropriate and the TypeScript interfaces provide comprehensive typing for model and provider data. The Provider interface captures all necessary capability flags and metadata.


45-141: Comprehensive state management with proper reactive declarations.

The state variables are well-organized and the reactive declarations properly transform data for UI components. The activeFilters computation provides a clean way to display filter badges.


142-318: Robust filtering and sorting implementation.

The filtering logic comprehensively covers text search, family, provider, and capability filtering. The use of toSorted() prevents array mutation, and the three-stage sorting behavior (ascending → descending → clear) provides excellent UX.


319-394: Excellent capability badge implementation and reactive updates.

The getCapabilityBadges function provides descriptive tooltips as requested in PR feedback. The reactive watchers properly trigger filtering when dependencies change, and the onMount sequence loads data in the correct order.


395-403: Clean provider connection handling.

The provider click handler properly checks connection status and navigates to settings for disconnected providers, implementing the UX flow described in the PR comments.


406-567: Well-structured search and filter interface.

The template provides excellent UX with loading/error states, properly labeled search input with icon, consistent filter dropdowns, and clear active filter badges with removal functionality.


568-802: Comprehensive model grid with good UX enhancements.

The model grid implementation provides excellent visual feedback for provider connection status, proper responsive layout, and comprehensive tooltips. The accessibility improvements from previous reviews have been largely addressed.

@scosman
Copy link
Collaborator

scosman commented Jul 29, 2025

Open question: should this page pull from remote_config or the local API? Using remote_config risks older clients not being able to handle newly added providers - unless we replicate the backend filtering logic to skip unsupported models / providers (maybe fine to do that as fairly trivial?).

Can we test if the same issue occurs? I was assuming we were working with untyped JSON data, and it would just fall through to ID if it can't find name. We're not working with enums/typing here if we're calling remote, so I bet it mostly just works (and might need a small tweak).

Otherwise, sounds good.

@scosman
Copy link
Collaborator

scosman commented Jul 29, 2025

Let's also add an AppPage button: "Manage Providers" to /settings/providers? Just grey, not primary.

@leonardmq
Copy link
Collaborator Author

leonardmq commented Jul 30, 2025

@scosman

Right now, we are (probably) dealing with untyped strings on the frontend, but we cannot rely on that - we expose ModelProviderName as a type and already use it:

export type ModelProviderName = components["schemas"]["ModelProviderName"]

That becomes a problem if data from this page integrates with the broader frontend (e.g. check if the provider is connected or not, etc.).

Typescript types are not enforced at runtime so this would not be immediately obvious that things are breaking (unlike with Python enums), but any code assuming ModelProviderName is exhaustive could break. For example, provider logos defined here would require a fallback / default state to handle unknown providers, and this would not be caught in typing at compile time:

const provider_image_map: Record<ModelProviderName | "wandb", string> = {

Probably safer to just serve the config via an endpoint on our API to filter out the ones that backend also does not support. Later we could also add a flag to indicate to the client that the config it is getting excludes some models that are not compatible and that they should try to update Kiln.


EDIT:

  • defaults / fallbacks are not necessary if we use the available_models API and check in there whether a model is connected or not - since we get the models the user already has, we would never be getting a totally foreign provider the client does not know about (I was trying to determine if the model was connected based on which providers were connected, like in the connect_providers screen, but that was more complicated and unnecessary)

Copy link

github-actions bot commented Aug 1, 2025

📊 Coverage Report

Overall Coverage: 92%

Diff: origin/main...HEAD

No lines with coverage information in this diff.


@leonardmq leonardmq force-pushed the leonard/model-library branch from a3d74b6 to 773b996 Compare August 1, 2025 12:37
Copy link
Contributor

@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: 0

🧹 Nitpick comments (1)
app/web_ui/src/routes/(app)/models/+page.svelte (1)

177-288: Comprehensive filtering and sorting implementation.

The filtering logic effectively handles text search across multiple fields and capability-based filtering. The sorting implementation using toSorted maintains immutability, and the three-state sort toggle (asc/desc/none) provides good UX.

Consider adding consistent optional chaining for all fields in the text search to prevent potential errors if the data structure changes:

        model.family?.toLowerCase().includes(searchLower) ||
        model.friendly_name?.toLowerCase().includes(searchLower) ||
        model.name?.toLowerCase().includes(searchLower) ||
        model.providers.some((p) =>
          p.model_id?.toLowerCase().includes(searchLower),
        )
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3d74b6 and 773b996.

📒 Files selected for processing (3)
  • app/desktop/studio_server/test_provider_api.py (4 hunks)
  • app/web_ui/src/lib/api_schema.d.ts (1 hunks)
  • app/web_ui/src/routes/(app)/models/+page.svelte (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • app/desktop/studio_server/test_provider_api.py
  • app/web_ui/src/lib/api_schema.d.ts
🧰 Additional context used
📓 Path-based instructions (1)
app/web_ui/src/**/*.{js,jsx,ts,tsx,svelte}

📄 CodeRabbit Inference Engine (.cursor/rules/project.mdc)

Our web UI component framework is DaisyUI v4 (based on Tailwind). Be sure to use v4 docs and features, not v5

Files:

  • app/web_ui/src/routes/(app)/models/+page.svelte
🧠 Learnings (2)
📓 Common learnings
Learnt from: leonardmq
PR: Kiln-AI/Kiln#390
File: libs/core/kiln_ai/adapters/provider_tools.py:494-499
Timestamp: 2025-07-23T08:58:45.769Z
Learning: leonardmq prefers to keep tightly coupled implementation details (like API versions) hardcoded when they are not user-facing and could break other modules if changed. The shared Config class is reserved for user-facing customizable values, not internal implementation details.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#341
File: libs/server/kiln_server/document_api.py:44-51
Timestamp: 2025-06-18T08:22:58.510Z
Learning: leonardmq prefers to defer fixing blocking I/O in async handlers when: the operation is very fast (milliseconds), user-triggered rather than automated, has no concurrency concerns, and would require additional testing to fix properly. He acknowledges such issues as valid but makes pragmatic decisions about timing the fixes.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#402
File: libs/core/kiln_ai/adapters/embedding/litellm_embedding_adapter.py:0-0
Timestamp: 2025-07-14T03:43:07.283Z
Learning: leonardmq prefers to keep defensive validation checks even when they're technically redundant, viewing them as useful "quick sanity checks" that provide additional safety nets. He values defensive programming over strict DRY (Don't Repeat Yourself) principles when the redundant code serves as a safeguard.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#388
File: libs/core/kiln_ai/datamodel/test_extraction_chunk.py:49-74
Timestamp: 2025-07-03T05:13:02.873Z
Learning: leonardmq prefers automatic cleanup of temporary files in tests using `delete=True` in `tempfile.NamedTemporaryFile()` context managers, rather than manual cleanup with `delete=False` and explicit file removal. This is because automatic cleanup is simpler, safer, and avoids leaving temporary files if tests fail before cleanup.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#0
File: :0-0
Timestamp: 2025-06-27T06:45:06.591Z
Learning: leonardmq prefers unused imports to be flagged as actionable review comments rather than nitpick comments. Unused imports should be treated as concrete issues that need to be addressed, not just suggestions.
📚 Learning: in the kiln web ui's project import functionality (edit_project.svelte), when the file selector api ...
Learnt from: scosman
PR: Kiln-AI/Kiln#464
File: app/web_ui/src/routes/(fullscreen)/setup/(setup)/create_project/edit_project.svelte:116-138
Timestamp: 2025-07-30T02:50:29.383Z
Learning: In the Kiln web UI's project import functionality (edit_project.svelte), when the file selector API fails, the preferred approach is to use alert() as a brief notification and set select_file_unavailable = true to gracefully fall back to manual path entry, rather than using the form's error handling system. This maintains a smooth user experience with automatic fallback rather than showing an error state.

Applied to files:

  • app/web_ui/src/routes/(app)/models/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04)
  • GitHub Check: Build Desktop Apps (windows-latest)
  • GitHub Check: Build Desktop Apps (macos-latest)
  • GitHub Check: Build Desktop Apps (macos-13)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04-arm)
🔇 Additional comments (7)
app/web_ui/src/routes/(app)/models/+page.svelte (7)

14-39: Well-structured TypeScript interfaces.

The interfaces are comprehensive and properly typed, using imported types like ModelProviderName for type safety. The Provider interface effectively captures all model capabilities and metadata needed for the UI.


41-131: Excellent reactive state management.

The state variables are properly typed and the reactive statements effectively transform data for the UI components. The activeFilters reactive statement elegantly builds filter badges from the current filter state.


133-145: Simple and effective filter removal logic.

The switch statement cleanly handles resetting individual filters based on their type.


147-174: Data fetching logic is functional.

The function properly manages loading and error states, extracts filter options from the fetched data, and handles JSON parsing. The basic error handling and state management are appropriate for this use case.


353-401: Robust provider connection detection.

The logic properly handles different provider types and connection states, including the special case of finetune-only models. The ollama-specific handling and helper functions for URLs and tooltips provide a good user experience for different connection states.


404-806: Comprehensive and user-friendly UI implementation.

The template effectively handles all states (loading, error, empty, populated) with appropriate feedback. The responsive grid layout, search interface, filter badges, and provider connection indicators create an intuitive user experience. The accessibility considerations and error handling demonstrate good UX practices.


338-351: Proper reactive state management and initialization.

The reactive statements correctly trigger filtering when state changes, and the onMount sequence logically loads local models before fetching remote configuration to ensure accurate provider connection status detection.

Copy link
Contributor

@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: 2

♻️ Duplicate comments (1)
app/web_ui/src/routes/(app)/models/+page.svelte (1)

134-136: Add request timeout and improve error handling.

The fetch request lacks a timeout and could benefit from more specific error handling for different HTTP status codes.

This matches a previous review comment that suggested implementing a timeout mechanism using AbortController and enhancing error handling with more descriptive messages.

🧹 Nitpick comments (5)
app/web_ui/src/routes/(app)/models/+page.svelte (5)

158-203: Optimize filter performance with memoization.

The filtering logic runs on every reactive update, which could impact performance with large model lists. The search operation using includes() on every model/provider combination could be expensive.

Consider memoizing the filtered results or using debounced search:

+ import { debounce } from 'lodash-es'
+
+ // Debounced search to avoid excessive filtering
+ const debouncedApplyFilters = debounce(applyFilters, 150)
+
- $: searchQuery, selectedProvider, selectedCapability, models, applyFilters()
+ $: searchQuery, selectedProvider, selectedCapability, models, debouncedApplyFilters()

342-354: Simplify URL generation logic.

The model_not_connected_href function has inconsistent return types and could be simplified for better maintainability.

  function model_not_connected_href(
    provider_id: string,
    model_id: string | null,
  ) {
-   if (provider_id === "ollama" && ollama_is_connected && model_id) {
-     return get_ollama_model_href(model_id)
-   }
-   return "/settings/providers"
+   return provider_id === "ollama" && ollama_is_connected && model_id
+     ? `https://ollama.com/library/${model_id}`
+     : "/settings/providers"
  }

445-452: Improve search input accessibility.

The search input should have better keyboard navigation and screen reader support.

          <input
            id="search"
            type="text"
            bind:value={searchQuery}
            placeholder="Search by name, model ID..."
+           autocomplete="off"
+           role="searchbox"
+           aria-label="Search models by name or model ID"
            class="block w-full pl-12 pr-4 py-3 border border-gray-300 rounded-lg leading-5 bg-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all"
          />

627-628: Consider performance impact of large model grids.

With potentially hundreds of models, rendering all model cards at once could impact performance. Consider implementing virtual scrolling or pagination for better UX.

For large datasets, consider adding pagination or virtual scrolling:

  • Use intersection observer for lazy loading
  • Implement pagination with page size limits
  • Add "Load more" functionality for progressive loading

669-673: Consolidate image error handling.

The image error handling logic is duplicated. Consider extracting it to a reusable function or directive.

+ function handleImageError(event: Event) {
+   const target = event.target as HTMLImageElement
+   if (target) {
+     target.style.display = "none"
+   }
+ }

-              on:error={(e) => {
-                if (e.target instanceof HTMLImageElement) {
-                  e.target.style.display = "none"
-                }
-              }}
+              on:error={handleImageError}

Also applies to: 700-704

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 773b996 and 9d5c53c.

📒 Files selected for processing (1)
  • app/web_ui/src/routes/(app)/models/+page.svelte (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
app/web_ui/src/**/*.{js,jsx,ts,tsx,svelte}

📄 CodeRabbit Inference Engine (.cursor/rules/project.mdc)

Our web UI component framework is DaisyUI v4 (based on Tailwind). Be sure to use v4 docs and features, not v5

Files:

  • app/web_ui/src/routes/(app)/models/+page.svelte
🧠 Learnings (2)
📓 Common learnings
Learnt from: leonardmq
PR: Kiln-AI/Kiln#390
File: libs/core/kiln_ai/adapters/provider_tools.py:494-499
Timestamp: 2025-07-23T08:58:45.769Z
Learning: leonardmq prefers to keep tightly coupled implementation details (like API versions) hardcoded when they are not user-facing and could break other modules if changed. The shared Config class is reserved for user-facing customizable values, not internal implementation details.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#341
File: libs/server/kiln_server/document_api.py:44-51
Timestamp: 2025-06-18T08:22:58.510Z
Learning: leonardmq prefers to defer fixing blocking I/O in async handlers when: the operation is very fast (milliseconds), user-triggered rather than automated, has no concurrency concerns, and would require additional testing to fix properly. He acknowledges such issues as valid but makes pragmatic decisions about timing the fixes.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#402
File: libs/core/kiln_ai/adapters/embedding/litellm_embedding_adapter.py:0-0
Timestamp: 2025-07-14T03:43:07.283Z
Learning: leonardmq prefers to keep defensive validation checks even when they're technically redundant, viewing them as useful "quick sanity checks" that provide additional safety nets. He values defensive programming over strict DRY (Don't Repeat Yourself) principles when the redundant code serves as a safeguard.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#388
File: libs/core/kiln_ai/datamodel/test_extraction_chunk.py:49-74
Timestamp: 2025-07-03T05:13:02.873Z
Learning: leonardmq prefers automatic cleanup of temporary files in tests using `delete=True` in `tempfile.NamedTemporaryFile()` context managers, rather than manual cleanup with `delete=False` and explicit file removal. This is because automatic cleanup is simpler, safer, and avoids leaving temporary files if tests fail before cleanup.
Learnt from: leonardmq
PR: Kiln-AI/Kiln#0
File: :0-0
Timestamp: 2025-06-27T06:45:06.591Z
Learning: leonardmq prefers unused imports to be flagged as actionable review comments rather than nitpick comments. Unused imports should be treated as concrete issues that need to be addressed, not just suggestions.
📚 Learning: in the kiln web ui's project import functionality (edit_project.svelte), when the file selector api ...
Learnt from: scosman
PR: Kiln-AI/Kiln#464
File: app/web_ui/src/routes/(fullscreen)/setup/(setup)/create_project/edit_project.svelte:116-138
Timestamp: 2025-07-30T02:50:29.383Z
Learning: In the Kiln web UI's project import functionality (edit_project.svelte), when the file selector API fails, the preferred approach is to use alert() as a brief notification and set select_file_unavailable = true to gracefully fall back to manual path entry, rather than using the form's error handling system. This maintains a smooth user experience with automatic fallback rather than showing an error state.

Applied to files:

  • app/web_ui/src/routes/(app)/models/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Desktop Apps (windows-latest)
  • GitHub Check: Build Desktop Apps (macos-latest)
  • GitHub Check: Build Desktop Apps (macos-13)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04-arm)
  • GitHub Check: Build Desktop Apps (ubuntu-22.04)
🔇 Additional comments (4)
app/web_ui/src/routes/(app)/models/+page.svelte (4)

1-11: LGTM: Well-structured imports and lifecycle management.

The imports are well-organized and the onMount lifecycle properly loads both available models and remote config data in the correct sequence.

Also applies to: 308-311


14-39: LGTM: Comprehensive TypeScript interfaces.

The interface definitions are well-structured and provide good type safety for the model data structure. The Provider interface covers all necessary attributes for the UI features.


264-300: LGTM: Well-implemented capability badge system.

The capability badge generation logic is clean and provides useful tooltips that align with the PR objectives for improved user guidance.


69-79: Ignore the runtime‐error concern for provider_name_from_id

The provider_name_from_id implementation in app/web_ui/src/lib/stores.ts already guards unknown or empty IDs:

• Returns "Unknown" when provider_id is falsy
• Looks up available_models and falls back to returning provider_id if not found

This behavior is covered by stores.test.ts and prevents any runtime exception.

Likely an incorrect or invalid review comment.

@leonardmq
Copy link
Collaborator Author

leonardmq commented Aug 1, 2025

@scosman

Reverted the previous commit that tried to check providers connected the same way as connect_providers does it.

Changes:

  • intersect with available_models API to find connected providers / models
    • small special case for Ollama where you can have Ollama connected but not the specific model; now it links out to the Ollama docs for the model
    • small tweak for finetune-only models (it tells you it is finetune only)
  • added Finetune in capabilities
  • the badges shown at the top are for editorial traits (suggested for xyz, recommended for xyz); the small circle icons that are provider-specific are for more granular capabilities (structured output, etc.); the capability filtering dropdown allows filtering for both
  • friendly provider name
    • there is a bug though, the util to get the provider name gets the names from available_models, but so it does not know the friendly provider name of providers that are not connected (since there is no such model in the endpoint it uses)
  • removed family badges and filters, because we do not have a friendly family name set up yet
  • fix: wrapping issues
  • chore: rewrite tooltip content
  • changed SVG for empty state (also changed loader to align with the other pages)
  • fix: wrapping issue on long model slugs
  • chore: renamed Models in sidebar, and Model Library as page title; not sure if that was what you meant you wanted
  • added Manage Providers in the top right as a secondary action button

@leonardmq leonardmq force-pushed the leonard/model-library branch from a3e909b to eb99c4f Compare August 1, 2025 13:01
@leonardmq leonardmq requested a review from scosman August 1, 2025 13:05
@scosman
Copy link
Collaborator

scosman commented Aug 1, 2025

1

Everything seems to be getting the special star. We're treating "supports_data_gen" as if it's "suggested_for_data_gen". Maybe the comment wasn't clear:

  • it should still have "Data Gen" badge if supports_data_gen
  • it should be "Data Gen [star]" if suggested_for_data_gen

2

Same goes for other badges like uncensored.

3

Log probs is missing a badge

4

Can we make the "Evaluations" item in dropdown "Suggested For Evals". Technically all models support evals, we want to make it clear this is a "suggestion" filter. We can keep "Evals [star]" in badge because the other string is too long 😀

5

I'll maybe to this separately, but we're not listing most of our Fine-tune models. They come direct from the Fireworks API, and don't have nice names so I don't just want to drop them in. I might add a modal or something.

@leonardmq
Copy link
Collaborator Author

leonardmq commented Aug 2, 2025

@scosman

That was partially intentional; I kept the badges only for the starred traits (there was a bug where supports_data_gen was one of them, instead of supports_data_gen); and the idea was to keep the more granular details at the provider level.

Changes:

  • fix: the star badge is suggested_for_data_gen (mistakenly set to be supports_data_gen)
  • added back all the traits (as opposed to only star ones) as badges; including uncensored and logprobs
    • if a model is both Suggested for XYZ and XYZ, then we only show Suggested for XYZ
    • star badges are listed first
  • rename capability option into Suggested For Evals
  • changed some colors; one was yellow and when displayed as a colored circle next to the providers, it looked too much like a status indicator suggesting a warning
  • feat: added filter for reasoning models; think that is quite a useful filter to have

Regarding 5., confirming we will do that separately.

Also filed this Issue: #475 - will address separately as separate issue

Feel free to make changes for the colors / strings if you want to.

@leonardmq leonardmq force-pushed the leonard/model-library branch from 76c4a10 to dd51128 Compare August 2, 2025 06:48
supports_finetuning:
"Supports finetuning, to train the model on your own use cases.",
supports_data_gen: "Supports Synthetic Data Generation.",
supports_structured_output:
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I find this message confusing - not sure what preferring the tool-calling method means in this context

Copy link
Collaborator

@scosman scosman left a comment

Choose a reason for hiding this comment

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

Looks amazing!

@leonardmq leonardmq merged commit 7fcdbb1 into main Aug 2, 2025
16 checks passed
@scosman scosman deleted the leonard/model-library branch August 2, 2025 14:13
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.

2 participants