mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-09 19:13:26 +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 @@
|
|||
{
|
||||
lib,
|
||||
python3Packages,
|
||||
enable-llm-anthropic ? false,
|
||||
enable-llm-cmd ? false,
|
||||
enable-llm-command-r ? false,
|
||||
enable-llm-deepseek ? false,
|
||||
enable-llm-fragments-github ? false,
|
||||
enable-llm-fragments-pypi ? false,
|
||||
enable-llm-gemini ? false,
|
||||
enable-llm-grok ? false,
|
||||
enable-llm-groq ? false,
|
||||
enable-llm-gguf ? false,
|
||||
enable-llm-hacker-news ? false,
|
||||
enable-llm-jq ? false,
|
||||
enable-llm-mistral ? false,
|
||||
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,
|
||||
}:
|
||||
# The `...` allows this derivation to be overridden with `enable-<llm-plugin>`.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# ```nix
|
||||
# llm.override {
|
||||
# enable-llm-anthropic = true;
|
||||
# enable-llm-gemini = true;
|
||||
# enable-llm-cmd = true;
|
||||
# enable-llm-templates-github = true;
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# Whatever names are accepted by `llm.withPlugins` are accepted with an added `enable-` prefix as
|
||||
# an override of this derivation. The user can also do `llm.withPlugins { llm-anthropic = true; }`.
|
||||
{ lib, python3Packages, ... }@args:
|
||||
|
||||
let
|
||||
inherit (python3Packages)
|
||||
toPythonApplication
|
||||
llm
|
||||
llm-anthropic
|
||||
llm-cmd
|
||||
llm-command-r
|
||||
llm-deepseek
|
||||
llm-fragments-github
|
||||
llm-fragments-pypi
|
||||
llm-gemini
|
||||
llm-gguf
|
||||
llm-grok
|
||||
llm-groq
|
||||
llm-hacker-news
|
||||
llm-jq
|
||||
llm-mistral
|
||||
llm-ollama
|
||||
llm-openai-plugin
|
||||
llm-openrouter
|
||||
llm-sentence-transformers
|
||||
llm-templates-fabric
|
||||
llm-templates-github
|
||||
llm-venice
|
||||
llm-video-frames
|
||||
;
|
||||
inherit (python3Packages) llm;
|
||||
|
||||
hasEnablePrefix = lib.hasPrefix "enable-";
|
||||
addEnablePrefix = name: "enable-${name}";
|
||||
removeEnablePrefix = lib.removePrefix "enable-";
|
||||
|
||||
# Filter to just the attributes which are named "enable-<plugin-name>"
|
||||
enableArgs = lib.filterAttrs (name: value: hasEnablePrefix name) args;
|
||||
pluginArgs = lib.mapAttrs' (
|
||||
name: value: lib.nameValuePair (removeEnablePrefix name) value
|
||||
) enableArgs;
|
||||
|
||||
# Provide some diagnostics for the plugin names
|
||||
pluginNames = lib.attrNames (lib.functionArgs llm.withPlugins);
|
||||
enableNames = lib.map addEnablePrefix pluginNames;
|
||||
unknownPluginNames = lib.removeAttrs pluginArgs pluginNames;
|
||||
unknownNames = lib.map addEnablePrefix (lib.attrNames unknownPluginNames);
|
||||
unknownNamesDiagnostic = ''
|
||||
Unknown plugins specified in override: ${lib.concatStringsSep ", " unknownNames}
|
||||
|
||||
Valid overrides:
|
||||
- ${lib.concatStringsSep "\n - " enableNames}
|
||||
'';
|
||||
in
|
||||
|
||||
toPythonApplication (
|
||||
llm.overrideAttrs (finalAttrs: {
|
||||
propagatedBuildInputs =
|
||||
(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 ];
|
||||
})
|
||||
)
|
||||
assert lib.assertMsg (lib.length unknownNames == 0) unknownNamesDiagnostic;
|
||||
|
||||
llm.withPlugins pluginArgs
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
lib,
|
||||
runCommand,
|
||||
callPackage,
|
||||
buildPythonPackage,
|
||||
fetchFromGitHub,
|
||||
|
@ -14,6 +15,7 @@
|
|||
pluggy,
|
||||
puremagic,
|
||||
pydantic,
|
||||
python,
|
||||
python-ulid,
|
||||
pyyaml,
|
||||
sqlite-migrate,
|
||||
|
@ -23,6 +25,103 @@
|
|||
sqlite-utils,
|
||||
}:
|
||||
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 {
|
||||
pname = "llm";
|
||||
version = "0.25";
|
||||
|
@ -75,7 +174,8 @@ let
|
|||
pythonImportsCheck = [ "llm" ];
|
||||
|
||||
passthru = {
|
||||
inherit withPlugins;
|
||||
inherit withPlugins withAllPlugins;
|
||||
|
||||
mkPluginTest = 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
|
||||
llm
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue