Add lms remove command to delete downloaded models#580
Conversation
`lms` can download models (`lms get`) but has no way to delete them; the only guidance has been to manually `rm` files from the models folder (see lmstudio-ai#199, lmstudio-ai#223). This adds a `remove` (alias `rm`) subcommand. - `lms remove [modelKey]`: removes a downloaded model from disk. - No argument -> interactive fuzzy picker (mirrors `lms unload`). - With a model key -> targets that model directly. - Models with multiple downloaded variants prompt to remove a single variant or the entire model. - Shows the model in the same table format as `lms ls`, plus its on-disk location, then asks for confirmation. `-y/--yes` skips it. - Refuses to remove a model that is currently loaded (asks the user to `lms unload` first). - Prunes now-empty publisher/repo folders after deletion. Refactor: extract `resolveModelsFolderPath`/`locateSettingsJson` out of `importCmd.ts` into a shared `modelsFolder.ts` and reuse it (adds an `ensureExists` option so removal doesn't recreate the folder). Export `printDownloadedModelsTable` from `list.ts` so the output matches `lms ls`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
All contributors have signed the CLA ✍️ ✅ |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1f470fe7d0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
I have read the CLA Document and I hereby sign the CLA |
The loaded-model guard compared only the relative path, so a model loaded on a remote LM Link device with the same path would block deleting the local download even though local files aren't in use. Filter loaded entries to the local device (via getModelInfo().deviceIdentifier + deviceNameResolver.isLocal) before the path-containment check, matching how `unload` distinguishes local vs remote models. Addresses Codex review feedback on lmstudio-ai#580. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e3d00183c6
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
`lms remove` deletes files from the locally-resolved models folder, but it inherits `--host` from addCreateClientOptions. With `--host <server>` it would list models from the remote instance while deleting local paths — either silently doing nothing or removing the wrong local model. Since there is no server-side delete RPC, fail fast when `--host` is set and tell the user to run the command on the machine where the model is stored. Addresses Codex review feedback (P1) on lmstudio-ai#580. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1ef284a882
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
resolveRemovalTarget looked up variants by model key only, which can include variants downloaded on LM Link peers. Since only base models were filtered to local devices, a remote-only variant could be offered and, when selected, either no-op while reporting success or delete a local file with the same relative path. Filter variants with deviceNameResolver.isLocal(variant.deviceIdentifier) before building the removal choices. Addresses Codex review feedback (P2) on lmstudio-ai#580. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Another round soon, please! ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
What
Adds a
remove(aliasrm) subcommand to delete downloaded models from disk — the counterpart tolms get.Resolves #579. Addresses the requests in #199 and #223, where the only available answer was to manually
rmfiles from the models folder.Usage
lms unload).lms ls, plus its on-disk location, then asks for confirmation.-y/--yesskips the prompt.lms unloadfirst).Since the SDK/backend exposes no delete RPC, removal is a filesystem delete of the model's path under the resolved models folder — the same approach as the documented manual workaround, made safe and built-in.
rm(..., { recursive: true, force: true })handles both file-style paths (a single.gguf) and folder-style paths (variant-based models whosepathis a directory).Changes
src/subcommands/remove.ts— the command. Built on the same primitives asunload/import(createClient,@inquirer/promptssearch/select+fuzzy,askQuestionfromconfirm.ts).src/modelsFolder.ts— extractedresolveModelsFolderPath/locateSettingsJsonout ofimportCmd.tsso both commands share one implementation. Added anensureExistsoption soremovedoesn't recreate the models folder.importCmd.tsnow imports from here (behavior unchanged).src/subcommands/list.ts— exportedprintDownloadedModelsTable(and theLoadedModelInfotype) soremoveoutput matcheslms lsexactly.src/index.ts— registeredremovein the "Local models" group.src/subcommands/remove.test.ts— unit tests for the path-containment helper used by the loaded-model guard and the empty-folder pruning.Testing notes
I was unable to run
npm install/tsc/eslintlocally because several@lmstudio/*dependencies (e.g.@lmstudio/lms-common-server) aren't published to the public npm registry — consistent with the note in CONTRIBUTING that binaries are built in thelmstudio.jsmonorepo. The code was written to match existing patterns and types, and formatted with the repo's Prettier config. I validated the path/variant assumptions against reallms ls --jsonoutput on a live install (single-file.ggufpaths, folder paths for variant models, and two quants sharing a folder). I'd appreciate a CI run to confirm the build, and I'm glad to adjust naming/flags/behavior.