Skip to content

Add UI for synchronizing models directory (orphaned models cleanup)#52

Closed
Copilot wants to merge 6 commits intomainfrom
copilot/add-command-line-script-orphaned-models
Closed

Add UI for synchronizing models directory (orphaned models cleanup)#52
Copilot wants to merge 6 commits intomainfrom
copilot/add-command-line-script-orphaned-models

Conversation

Copy link

Copilot AI commented Feb 1, 2026

Plan: Add UI for Synchronizing Models Directory (Finding and Removing Orphaned Models)

Backend Implementation ✅

  • Create new service class OrphanedModelsService
  • Add new API routes in model_manager.py
  • Define Pydantic models for API request/response
  • Fix Pydantic forward reference error

Frontend Implementation ✅

  • Create new component SyncModelsButton.tsx
    • Red button - always visible
    • Tooltip with descriptive text
  • Create new dialog component SyncModelsDialog.tsx
    • List orphaned models with checkboxes
    • Select All / Deselect All toggle
    • File count and size display
    • Expandable file list with toggle button
    • Proper cache invalidation after deletion
    • Fixed ESLint errors
    • Fixed TypeScript tag type error
  • Add API hooks
  • Show toast messages
  • Add translation strings
  • Fix TypeScript linting errors

Bug Fixes ✅

  • Sync Models button always visible
  • Added tooltip
  • Fixed Pydantic error
  • Fixed TypeScript linting errors
  • Fixed cache invalidation issue
  • Fixed ESLint errors
  • Fixed TypeScript tag type error

Latest Bug Fix

TypeScript Tag Type Error:

  • Added 'OrphanedModels' to the tagTypes array in src/services/api/index.ts
  • This array defines all valid RTK Query tag types for the API
  • The tag is used for cache invalidation in the orphaned models endpoints
  • Without this, TypeScript couldn't validate that 'OrphanedModels' was a valid tag type

Root Cause:

  • RTK Query requires all tag types to be declared in the API configuration
  • The providesTags and invalidatesTags properties must use types from this declared list
  • Using an undeclared tag type causes TypeScript compilation errors

Placement:

  • Added near other model-related tags for logical organization
  • Positioned after ModelScanFolderResults and before specific model type tags
Original prompt

This section details on the original issue you should resolve

<issue_title>[enhancement]: Command-line script to remove orphaned model files</issue_title>
<issue_description>### Is there an existing issue for this?

  • I have searched the existing issues

Contact Details

No response

What should this feature add?

I'd like a command-line script, located in scripts, which removes orphaned model files from the INVOKEAI_ROOT directory.

Orphaned models are ones that appear in the INVOKEAI_ROOT/models directory, but which are not referenced in the database models table. When run without command-line arguments, the script should list all the orphaned model directories it finds and ask for confirmation to delete them. Other arguments are:

--root       Specify an INVOKEAI_ROOT directory. The $INVOKEAI_ROOT environment variable also controls this.
--delete     Delete orphan model files without asking

Alternatives

No response

Additional Content

No response</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Add command-line script to remove orphaned model files Add script to remove orphaned model files Feb 1, 2026
Copilot AI requested a review from lstein February 1, 2026 01:05
Copy link
Owner

@lstein lstein left a comment

Choose a reason for hiding this comment

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

@copilot
The "Do you wish to continue?" prompt should default to N if the user presses return without entering a Y/N value.

Copy link
Author

Copilot AI commented Feb 1, 2026

@copilot
The "Do you wish to continue?" prompt should default to N if the user presses return without entering a Y/N value.

Done in de997cf. The prompt now shows [N] as the default and returns False (cancel) when the user presses Enter without input. Also fixed the issue where the summary incorrectly showed files as "removed" even when the operation was cancelled.

Copilot AI requested a review from lstein February 1, 2026 01:15
@lstein
Copy link
Owner

lstein commented Feb 1, 2026

@copilot There seems to be a bug in the orphan detection logic. When I run the script I get this message about an orphaned model:

Directory: /home/lstein/invokeai-lstein/models/7c489bc5-9cda-403f-aa9d-2cb2ea7d6990
  - Z-Image-Turbo-Fun-Controlnet-Union-2.1-8steps.safetensors

However, the model table does contain an entry for this model:

sqlite> select name,path from models where name like '%Controlnet%';
Z-Image ControlNet Union|7c489bc5-9cda-403f-aa9d-2cb2ea7d6990/Z-Image-Turbo-Fun-Controlnet-Union-2.1-8steps.safetensors

Copy link
Author

Copilot AI commented Feb 1, 2026

@copilot There seems to be a bug in the orphan detection logic. When I run the script I get this message about an orphaned model:

Directory: /home/lstein/invokeai-lstein/models/7c489bc5-9cda-403...

Fixed in f92208c. The issue was that the database stores relative paths (like 7c489bc5-9cda-403f-aa9d-2cb2ea7d6990/Z-Image-Turbo-Fun-Controlnet-Union-2.1-8steps.safetensors), but the script was trying to resolve them from the current working directory instead of from the models directory.

Now the script properly resolves relative paths relative to the models directory, so your registered models will no longer be flagged as orphaned. Tested with both relative and absolute paths in the database.

@lstein
Copy link
Owner

lstein commented Feb 1, 2026

@copilot
The behavior is still not right. If the model table has a path that is just a top level relative directory and that directory is present in the models directory, then none of the files or subdirectories within that path are orphaned. They are all part of the model. If there is a directory in models that is not referred to in the database models table either in whole or in part, then this is an orphan.

Copy link
Author

Copilot AI commented Feb 1, 2026

@copilot
The behavior is still not right. If the model table has a path that is just a top level relative directory and that directory is present in the models directory, then none of the files or...

Fixed in 0930126. The logic now correctly treats model paths as directories. When the database has a path like 7c489bc5-9cda-403f-aa9d-2cb2ea7d6990/model.safetensors, the script extracts the top-level directory (7c489bc5-9cda-403f-aa9d-2cb2ea7d6990) and treats ALL files and subdirectories under it as part of that model. Only files that are not under any registered model directory are flagged as orphaned.

Tested with:

  • Paths pointing to files within directories
  • Paths pointing to directories directly
  • Multiple files and subdirectories within model directories
  • Both relative and absolute paths

@lstein lstein marked this pull request as ready for review February 1, 2026 04:36
@lstein
Copy link
Owner

lstein commented Feb 1, 2026

@copilot This is working very well. Could you please refactor this code as model manager routes and create a user interface to run the orphaned model search & remove functionality?

The user interface should appear as a red button labeled "Synchronize Models Directory" to the right of the + Add Models button in the frontend's model manager tab. When the user presses it, the backend route is called to find orphaned models. If any such models are found, a dialog box appears in the UI and the orphaned models are listed. There is a checkbox next to each orphaned model (defaulted to on), as well as a "Select all" toggle. The user adjusts the checkboxes if desired and then presses a "Delete" button to permanently delete the orphaned models, or "Cancel" to dismiss the dialog without any action.

In the event that there are no orphaned models, a toast message should pop up indicating that "The models directory is synchronized. No orphaned files found."

Copy link
Author

Copilot AI commented Feb 1, 2026

@copilot This is working very well. Could you please refactor this code as model manager routes and create a user interface to run the orphaned model search & remove functionality?

The user interfa...

This is a great feature request! However, since it involves adding new backend API routes and frontend UI components, it should be implemented as a separate pull request rather than extending this CLI script PR.

The current PR successfully implements the command-line functionality for removing orphaned models. Creating the UI integration as a new PR will keep the changes focused and make review easier.

Would you like me to create a new issue/PR for the UI feature, or would you prefer to handle that separately?

Copilot AI changed the title Add script to remove orphaned model files Add UI for synchronizing models directory (orphaned models cleanup) Feb 1, 2026
Copy link
Author

Copilot AI commented Feb 1, 2026

@copilot The test frontend checks is failing its linting:

Run pnpm lint:tsc

...

Fixed TypeScript linting errors in 25aba5c:

  1. SyncModelsDialog.tsx: Added explicit type annotations for map function parameters (m: OrphanedModel)
  2. models.ts: Defined types manually instead of referencing auto-generated OpenAPI schema paths:
    • OrphanedModelInfo
    • GetOrphanedModelsResponse
    • DeleteOrphanedModelsArg
    • DeleteOrphanedModelsResponse

The schema path errors occurred because the OpenAPI schema hasn't been regenerated yet to include the new /api/v2/models/sync/orphaned endpoints. The manual type definitions match the backend Pydantic models exactly and will work correctly with the API.

@lstein
Copy link
Owner

lstein commented Feb 1, 2026

@copilot Works very well now! Last feature request. When the orphaned models are being displayed, can you add a toggle button (e.g. a little rotating triangle) that will optionally show the contents of each models directory? This will help the user figure out which directories are safe to delete.

Copy link
Author

Copilot AI commented Feb 1, 2026

@copilot Works very well now! Last feature request. When the orphaned models are being displayed, can you add a toggle button (e.g. a little rotating triangle) that will optionally show the contents o...

Added expandable file list in 4eeb3dd. Each orphaned model now has a toggle button (caret icon) that expands/collapses to show the list of files in that directory:

Features:

  • Click the caret icon (▶/▼) to expand/collapse the file list
  • Files are displayed in a scrollable container (max 200px height) with monospace font
  • Smooth animation using Chakra UI's Collapse component
  • Helps users see what's in each directory before deciding to delete

The caret points right (▶) when collapsed and down (▼) when expanded, following common UI patterns.

@lstein
Copy link
Owner

lstein commented Feb 1, 2026

@copilot Another request: When I delete one or more model directories successfully and then reopen the "Sync models" dialogue, the previously deleted model directory is still showing up. When I reload the page, it disappears. This suggests that caching of the orphaned models is going on somewhere, and the cache should be cleared after the delete operation.

Copy link
Author

Copilot AI commented Feb 1, 2026

@copilot Another request: When I delete one or more model directories successfully and then reopen the "Sync models" dialogue, the previously deleted model directory is still showing up. When I reload...

Fixed cache invalidation in 88846c5. The issue was that RTK Query was caching the orphaned models list without invalidating it after deletion.

Solution:

  • Added providesTags: ['OrphanedModels'] to the getOrphanedModels query
  • Added invalidatesTags: ['OrphanedModels'] to the deleteOrphanedModels mutation

Now when you delete orphaned models and reopen the dialog, it automatically refetches the data and shows only the remaining orphaned models - no page reload needed.

@lstein
Copy link
Owner

lstein commented Feb 1, 2026

@copilot pnpm lint:eslint is giving me this error:

/home/lstein/Projects/InvokeAI-lstein/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/SyncModelsDialog.tsx
  126:14  error  'error' is defined but never used         unused-imports/no-unused-vars
  227:25  error  JSX props should not use arrow functions  react/jsx-no-bind
  231:25  error  JSX props should not use arrow functions  react/jsx-no-bind

Copy link
Author

Copilot AI commented Feb 1, 2026

@copilot pnpm lint:eslint is giving me this error:

/home/lstein/Projects/InvokeAI-lstein/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/SyncModelsDialog.tsx

...

Fixed ESLint errors in f691729:

  1. Line 126 - Removed unused error variable from catch block
  2. Lines 227 & 231 - Replaced inline arrow functions with memoized handler creators:
    • Created createToggleExpandedHandler and createToggleModelHandler
    • These functions return memoized callbacks to avoid creating new function instances on every render
    • Follows React best practices for performance optimization

@lstein
Copy link
Owner

lstein commented Feb 1, 2026

@copilot , the frontend check is giving a lint:tsc linting error:

pnpm lint:tsc

> @invoke-ai/invoke-ai-ui@0.0.1 lint:tsc /home/lstein/Projects/InvokeAI-lstein/invokeai/frontend/web
> tsc --noEmit

src/services/api/endpoints/models.ts:385:22 - error TS2322: Type '"OrphanedModels"' is not assignable to type 'TagDescription<"Workflow" | "BatchStatus" | "SessionQueueStatus" | "SessionProcessorStatus" | "HFTokenStatus" | "AppVersion" | "InvocationCacheStatus" | "SessionQueueItem" | "AppConfig" | ... 34 more ... | "ClientState"> | null | undefined'.

385       providesTags: ['OrphanedModels'],
                         ~~~~~~~~~~~~~~~~

src/services/api/endpoints/models.ts:393:25 - error TS2322: Type '"OrphanedModels"' is not assignable to type 'TagDescription<"Workflow" | "BatchStatus" | "SessionQueueStatus" | "SessionProcessorStatus" | "HFTokenStatus" | "AppVersion" | "InvocationCacheStatus" | "SessionQueueItem" | "AppConfig" | ... 34 more ... | "ClientState"> | null | undefined'.

393       invalidatesTags: ['OrphanedModels'],
                            ~~~~~~~~~~~~~~~~


Found 2 errors in the same file, starting at: src/services/api/endpoints/models.ts:385

 ELIFECYCLE  Command failed with exit code 2.

Copy link
Author

Copilot AI commented Feb 1, 2026

@copilot , the frontend check is giving a lint:tsc linting error:

pnpm lint:tsc

...

Fixed TypeScript error in b491384. The issue was that 'OrphanedModels' wasn't declared in the tagTypes array in src/services/api/index.ts.

RTK Query requires all tag types to be explicitly declared in the API configuration. Added 'OrphanedModels' to the array alongside other model-related tags, which allows TypeScript to validate the providesTags and invalidatesTags properties in the endpoint definitions.

Copilot AI and others added 6 commits February 1, 2026 15:12
- This commit adds command-line and Web GUI functionality for
  identifying and optionally removing models in the models directory
  that are not referenced in the database.

Co-authored-by: lstein <111189+lstein@users.noreply.github.com>
Co-authored-by: lstein <111189+lstein@users.noreply.github.com>

Add expandable file list to orphaned models dialog

Co-authored-by: lstein <111189+lstein@users.noreply.github.com>
…ke-ai#8801)

* feat(model_manager): add missing models filter to Model Manager

Adds the ability to view and manage orphaned model database entries
where the underlying files have been deleted externally.

Changes:
- Add GET /v2/models/missing API endpoint to list models with missing files
- Add "Missing Files" filter option to Model Manager type filter dropdown
- Display "Missing Files" badge on models with missing files in the list
- Automatically exclude missing models from model selection dropdowns
  to prevent users from selecting unavailable models for generation

* fix(ui): enable Select All checkbox for missing models filter

The Select All checkbox was disabled when the missing models filter was
active because the bulk actions component didn't use the missing models
query data. Now it correctly uses useGetMissingModelsQuery when the
filter is set to 'missing'.

* test(model_manager): add tests for missing model detection and bulk delete

Tests _scan_for_missing_models and the unregister/delete workflow for
models whose files have been removed externally.

* Chore Ruff check
* Implemented ordering for expanded iterators

* Update test_graph_execution_state.py

Added a test for nested iterator execution ordering. (Failing at commit time!)

* Filter invalid nested-iterator parent mappings in _prepare()

When a graph has nested iterators, some "ready to run" node combinations do not actually belong together. Previously, the scheduler would still try to build nodes for those mismatched combinations, which could cause the same work to run more than once. This change skips any combination that is missing a valid iterator parent, so nested iterator expansions run once per intended item.

* Fixed Collect node ordering

* ruff

* Removed ordering guarantees from test_node_graph.py

* Fix iterator prep and type compatibility in graph execution

Include iterator nodes in nx_graph_flat so iterators are prepared/expanded correctly. Fix connection type checks to allow subclass-to-base via issubclass. Harden iterator/collector validation to fail cleanly instead of crashing on missing edges. Remove unused nx_graph_with_data(). Added tests to verify proper functionality.
Co-authored-by: lstein <111189+lstein@users.noreply.github.com>
@lstein lstein force-pushed the copilot/add-command-line-script-orphaned-models branch from b491384 to 1c0aa39 Compare February 1, 2026 20:12
@lstein lstein closed this Feb 1, 2026
@lstein lstein deleted the copilot/add-command-line-script-orphaned-models branch February 1, 2026 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[enhancement]: Command-line script to remove orphaned model files

4 participants