mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-10 03:23:29 +03:00
llm: reintroduce withPlugins
This was removed in #340510, as the previous implementation didn't work well. However, it's still the method that's recommended in the patch for the `llm install` command (`001-disable-install-uninstall-commands.patch`) and with the additions to `enable` overrides on the top-level `llm` derivation, there's a need for a place where the LLM plugin "directory" is specified. So, I've reintroduced the method with a completely new implementation. I've also given it some protections against the list of names getting out of date. This might be a little too clever, but I think the user-facing interface for this function is now quite nice.
This commit is contained in:
parent
794f8c04b0
commit
0d50348b51
2 changed files with 143 additions and 85 deletions
|
@ -1,81 +1,46 @@
|
||||||
{
|
# The `...` allows this derivation to be overridden with `enable-<llm-plugin>`.
|
||||||
lib,
|
#
|
||||||
python3Packages,
|
# Example:
|
||||||
enable-llm-anthropic ? false,
|
#
|
||||||
enable-llm-cmd ? false,
|
# ```nix
|
||||||
enable-llm-command-r ? false,
|
# llm.override {
|
||||||
enable-llm-deepseek ? false,
|
# enable-llm-anthropic = true;
|
||||||
enable-llm-fragments-github ? false,
|
# enable-llm-gemini = true;
|
||||||
enable-llm-fragments-pypi ? false,
|
# enable-llm-cmd = true;
|
||||||
enable-llm-gemini ? false,
|
# enable-llm-templates-github = true;
|
||||||
enable-llm-grok ? false,
|
# }
|
||||||
enable-llm-groq ? false,
|
# ```
|
||||||
enable-llm-gguf ? false,
|
#
|
||||||
enable-llm-hacker-news ? false,
|
# Whatever names are accepted by `llm.withPlugins` are accepted with an added `enable-` prefix as
|
||||||
enable-llm-jq ? false,
|
# an override of this derivation. The user can also do `llm.withPlugins { llm-anthropic = true; }`.
|
||||||
enable-llm-mistral ? false,
|
{ lib, python3Packages, ... }@args:
|
||||||
enable-llm-ollama ? false,
|
|
||||||
enable-llm-openai-plugin ? false,
|
|
||||||
enable-llm-openrouter ? false,
|
|
||||||
enable-llm-sentence-transformers ? false,
|
|
||||||
enable-llm-templates-fabric ? false,
|
|
||||||
enable-llm-templates-github ? false,
|
|
||||||
enable-llm-venice ? false,
|
|
||||||
enable-llm-video-frames ? false,
|
|
||||||
}:
|
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (python3Packages)
|
inherit (python3Packages) llm;
|
||||||
toPythonApplication
|
|
||||||
llm
|
hasEnablePrefix = lib.hasPrefix "enable-";
|
||||||
llm-anthropic
|
addEnablePrefix = name: "enable-${name}";
|
||||||
llm-cmd
|
removeEnablePrefix = lib.removePrefix "enable-";
|
||||||
llm-command-r
|
|
||||||
llm-deepseek
|
# Filter to just the attributes which are named "enable-<plugin-name>"
|
||||||
llm-fragments-github
|
enableArgs = lib.filterAttrs (name: value: hasEnablePrefix name) args;
|
||||||
llm-fragments-pypi
|
pluginArgs = lib.mapAttrs' (
|
||||||
llm-gemini
|
name: value: lib.nameValuePair (removeEnablePrefix name) value
|
||||||
llm-gguf
|
) enableArgs;
|
||||||
llm-grok
|
|
||||||
llm-groq
|
# Provide some diagnostics for the plugin names
|
||||||
llm-hacker-news
|
pluginNames = lib.attrNames (lib.functionArgs llm.withPlugins);
|
||||||
llm-jq
|
enableNames = lib.map addEnablePrefix pluginNames;
|
||||||
llm-mistral
|
unknownPluginNames = lib.removeAttrs pluginArgs pluginNames;
|
||||||
llm-ollama
|
unknownNames = lib.map addEnablePrefix (lib.attrNames unknownPluginNames);
|
||||||
llm-openai-plugin
|
unknownNamesDiagnostic = ''
|
||||||
llm-openrouter
|
Unknown plugins specified in override: ${lib.concatStringsSep ", " unknownNames}
|
||||||
llm-sentence-transformers
|
|
||||||
llm-templates-fabric
|
Valid overrides:
|
||||||
llm-templates-github
|
- ${lib.concatStringsSep "\n - " enableNames}
|
||||||
llm-venice
|
'';
|
||||||
llm-video-frames
|
|
||||||
;
|
|
||||||
in
|
in
|
||||||
|
|
||||||
toPythonApplication (
|
assert lib.assertMsg (lib.length unknownNames == 0) unknownNamesDiagnostic;
|
||||||
llm.overrideAttrs (finalAttrs: {
|
|
||||||
propagatedBuildInputs =
|
llm.withPlugins pluginArgs
|
||||||
(finalAttrs.propagatedBuildInputs or [ ])
|
|
||||||
++ lib.optionals enable-llm-anthropic [ llm-anthropic ]
|
|
||||||
++ lib.optionals enable-llm-cmd [ llm-cmd ]
|
|
||||||
++ lib.optionals enable-llm-cmd [ llm-command-r ]
|
|
||||||
++ lib.optionals enable-llm-deepseek [ llm-deepseek ]
|
|
||||||
++ lib.optionals enable-llm-fragments-github [ llm-fragments-github ]
|
|
||||||
++ lib.optionals enable-llm-fragments-pypi [ llm-fragments-pypi ]
|
|
||||||
++ lib.optionals enable-llm-gemini [ llm-gemini ]
|
|
||||||
++ lib.optionals enable-llm-gguf [ llm-gguf ]
|
|
||||||
++ lib.optionals enable-llm-grok [ llm-grok ]
|
|
||||||
++ lib.optionals enable-llm-groq [ llm-groq ]
|
|
||||||
++ lib.optionals enable-llm-hacker-news [ llm-hacker-news ]
|
|
||||||
++ lib.optionals enable-llm-jq [ llm-jq ]
|
|
||||||
++ lib.optionals enable-llm-mistral [ llm-mistral ]
|
|
||||||
++ lib.optionals enable-llm-ollama [ llm-ollama ]
|
|
||||||
++ lib.optionals enable-llm-openai-plugin [ llm-openai-plugin ]
|
|
||||||
++ lib.optionals enable-llm-openrouter [ llm-openrouter ]
|
|
||||||
++ lib.optionals enable-llm-sentence-transformers [ llm-sentence-transformers ]
|
|
||||||
++ lib.optionals enable-llm-templates-fabric [ llm-templates-fabric ]
|
|
||||||
++ lib.optionals enable-llm-templates-github [ llm-templates-github ]
|
|
||||||
++ lib.optionals enable-llm-venice [ llm-venice ]
|
|
||||||
++ lib.optionals enable-llm-video-frames [ llm-video-frames ];
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
|
runCommand,
|
||||||
callPackage,
|
callPackage,
|
||||||
buildPythonPackage,
|
buildPythonPackage,
|
||||||
fetchFromGitHub,
|
fetchFromGitHub,
|
||||||
|
@ -14,6 +15,7 @@
|
||||||
pluggy,
|
pluggy,
|
||||||
puremagic,
|
puremagic,
|
||||||
pydantic,
|
pydantic,
|
||||||
|
python,
|
||||||
python-ulid,
|
python-ulid,
|
||||||
pyyaml,
|
pyyaml,
|
||||||
sqlite-migrate,
|
sqlite-migrate,
|
||||||
|
@ -23,6 +25,103 @@
|
||||||
sqlite-utils,
|
sqlite-utils,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
|
# The function signature of `withPlugins` is the list of all the plugins `llm` knows about.
|
||||||
|
# The plugin directory is at <https://llm.datasette.io/en/stable/plugins/directory.html>
|
||||||
|
withPluginsArgNames = lib.functionArgs withPlugins;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Make a derivation for `llm` that contains `llm` plus the relevant plugins.
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
```
|
||||||
|
withPlugins ::
|
||||||
|
{
|
||||||
|
llm-anthropic :: bool,
|
||||||
|
llm-gemini :: bool,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
-> derivation
|
||||||
|
```
|
||||||
|
|
||||||
|
See `lib.attrNames (lib.functionArgs llm.withPlugins)` for the total list of plugins supported.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
:::{.example}
|
||||||
|
## `llm.withPlugins` usage example
|
||||||
|
|
||||||
|
```nix
|
||||||
|
llm.withPlugins { llm-gemini = true; llm-groq = true; }
|
||||||
|
=> «derivation /nix/store/<hash>-python3-3.12.10-llm-with-llm-gemini-llm-groq.drv»
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
*/
|
||||||
|
withPlugins =
|
||||||
|
# Keep this list up to date with the plugins in python3Packages!
|
||||||
|
{
|
||||||
|
llm-anthropic ? false,
|
||||||
|
llm-cmd ? false,
|
||||||
|
llm-command-r ? false,
|
||||||
|
llm-deepseek ? false,
|
||||||
|
llm-fragments-github ? false,
|
||||||
|
llm-fragments-pypi ? false,
|
||||||
|
llm-gemini ? false,
|
||||||
|
llm-gguf ? false,
|
||||||
|
llm-grok ? false,
|
||||||
|
llm-groq ? false,
|
||||||
|
llm-hacker-news ? false,
|
||||||
|
llm-jq ? false,
|
||||||
|
llm-mistral ? false,
|
||||||
|
llm-ollama ? false,
|
||||||
|
llm-openai-plugin ? false,
|
||||||
|
llm-openrouter ? false,
|
||||||
|
llm-sentence-transformers ? false,
|
||||||
|
llm-templates-fabric ? false,
|
||||||
|
llm-templates-github ? false,
|
||||||
|
llm-venice ? false,
|
||||||
|
llm-video-frames ? false,
|
||||||
|
}@args:
|
||||||
|
let
|
||||||
|
# Filter to just the attributes which are set to a true value.
|
||||||
|
setArgs = lib.filterAttrs (name: lib.id) args;
|
||||||
|
|
||||||
|
# Make a string with those names separated with a dash.
|
||||||
|
setArgsStr = lib.concatStringsSep "-" (lib.attrNames setArgs);
|
||||||
|
|
||||||
|
# Make the derivation name reflect what's inside it.
|
||||||
|
drvName = if lib.stringLength setArgsStr == 0 then "llm" else "llm-with-${setArgsStr}";
|
||||||
|
|
||||||
|
# Make a python environment with just those plugins.
|
||||||
|
python-environment = python.withPackages (
|
||||||
|
ps:
|
||||||
|
let
|
||||||
|
# Throw a diagnostic if this list gets out of sync with the names in python3Packages
|
||||||
|
allPluginsPresent = pluginNames == (lib.attrNames withPluginsArgNames);
|
||||||
|
pluginNames = lib.attrNames (lib.intersectAttrs ps withPluginsArgNames);
|
||||||
|
missingNamesList = lib.attrNames (lib.removeAttrs withPluginsArgNames pluginNames);
|
||||||
|
missingNames = lib.concatStringsSep ", " missingNamesList;
|
||||||
|
|
||||||
|
# The relevant plugins are the ones the user asked for.
|
||||||
|
plugins = lib.intersectAttrs setArgs ps;
|
||||||
|
in
|
||||||
|
assert lib.assertMsg allPluginsPresent "Missing these plugins: ${missingNames}";
|
||||||
|
([ ps.llm ] ++ lib.attrValues plugins)
|
||||||
|
);
|
||||||
|
|
||||||
|
in
|
||||||
|
# That Python environment produced above contains too many irrelevant binaries, due to how
|
||||||
|
# Python needs to use propagatedBuildInputs. Let's make one with just what's needed: `llm`.
|
||||||
|
# Since we include the `passthru` and `meta` information, it's as good as the original
|
||||||
|
# derivation.
|
||||||
|
runCommand "${python.name}-${drvName}" { inherit (llm) passthru meta; } ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
ln -s ${python-environment}/bin/llm $out/bin/llm
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Uses the `withPlugins` names to make a Python environment with everything.
|
||||||
|
withAllPlugins = withPlugins (lib.genAttrs (lib.attrNames withPluginsArgNames) (name: true));
|
||||||
|
|
||||||
llm = buildPythonPackage rec {
|
llm = buildPythonPackage rec {
|
||||||
pname = "llm";
|
pname = "llm";
|
||||||
version = "0.25";
|
version = "0.25";
|
||||||
|
@ -75,7 +174,8 @@ let
|
||||||
pythonImportsCheck = [ "llm" ];
|
pythonImportsCheck = [ "llm" ];
|
||||||
|
|
||||||
passthru = {
|
passthru = {
|
||||||
inherit withPlugins;
|
inherit withPlugins withAllPlugins;
|
||||||
|
|
||||||
mkPluginTest = plugin: {
|
mkPluginTest = plugin: {
|
||||||
${plugin.pname} = callPackage ./mk-plugin-test.nix { inherit llm plugin; };
|
${plugin.pname} = callPackage ./mk-plugin-test.nix { inherit llm plugin; };
|
||||||
};
|
};
|
||||||
|
@ -93,12 +193,5 @@ let
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
withPlugins = throw ''
|
|
||||||
llm.withPlugins was confusing to use and has been removed.
|
|
||||||
Please migrate to using python3.withPackages(ps: [ ps.llm ]) instead.
|
|
||||||
|
|
||||||
See https://nixos.org/manual/nixpkgs/stable/#python.withpackages-function for more usage examples.
|
|
||||||
'';
|
|
||||||
in
|
in
|
||||||
llm
|
llm
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue