Something went wrong. Try again.
What happens if I push all of nixpkgs
Something went wrong. Try again.
7.3 kB · 258 lines
Nix
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259{ lib, runCommand, callPackage, buildPythonPackage, fetchFromGitHub, pytestCheckHook, pythonOlder, replaceVars, setuptools, click-default-group, condense-json, numpy, openai, pip, pluggy, puremagic, pydantic, python, python-ulid, pyyaml, sqlite-migrate, cogapp, pytest-asyncio, pytest-httpx, pytest-recording, sqlite-utils, syrupy, llm-echo,}:let /** Make a derivation for `llm` that contains `llm` plus the relevant plugins. The function signature of `withPlugins` is the list of all the plugins `llm` knows about. Adding a parameter here requires that it be in `python3Packages` attrset.
# 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-docs ? false, llm-echo ? false, llm-fragments-github ? false, llm-fragments-pypi ? false, llm-fragments-reader ? false, llm-fragments-symbex ? false, llm-gemini ? false, llm-gguf ? false, llm-git ? false, llm-github-copilot ? false, llm-grok ? false, llm-groq ? false, llm-hacker-news ? false, llm-jq ? false, llm-llama-server ? false, llm-mistral ? false, llm-ollama ? false, llm-openai-plugin ? false, llm-openrouter ? false, llm-pdf-to-images ? false, llm-perplexity ? false, llm-sentence-transformers ? false, llm-templates-fabric ? false, llm-templates-github ? false, llm-tools-datasette ? false, llm-tools-quickjs ? false, llm-tools-simpleeval ? false, llm-tools-sqlite ? 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 the derivation name reflect what's inside it, up to a certain limit. setArgNames = lib.attrNames setArgs; drvName = let len = builtins.length setArgNames; in if len == 0 then "llm-${llm.version}" else if len > 20 then "llm-${llm.version}-with-${toString len}-plugins" else # Make a string with those names separated with a dash. "llm-${llm.version}-with-${lib.concatStringsSep "-" setArgNames}";
# 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 == withPluginsArgNames; pluginNames = lib.attrNames (lib.intersectAttrs ps withPluginsArgs); missingNamesList = lib.attrNames (lib.removeAttrs withPluginsArgs 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 withPluginsArgNames (name: true));
# 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> withPluginsArgs = lib.functionArgs withPlugins; withPluginsArgNames = lib.attrNames withPluginsArgs;
# In order to help with usability, we patch `llm install` and `llm uninstall` to tell users how to # customize `llm` with plugins in Nix, including the name of the plugin, its description, and # where it's coming from. listOfPackagedPlugins = builtins.toFile "plugins.txt" ( lib.concatStringsSep "\n " ( map (name: '' # ${python.pkgs.${name}.meta.description} <${python.pkgs.${name}.meta.homepage}> ${name} = true; '') withPluginsArgNames ) );
llm = buildPythonPackage rec { pname = "llm"; version = "0.26"; pyproject = true;
build-system = [ setuptools ];
disabled = pythonOlder "3.8";
src = fetchFromGitHub { owner = "simonw"; repo = "llm"; tag = version; hash = "sha256-KTlNajuZrR0kBX3LatepsNM3PfRVsQn+evEfXTu6juE="; };
patches = [ ./001-disable-install-uninstall-commands.patch ];
postPatch = '' substituteInPlace llm/cli.py \ --replace-fail "@listOfPackagedPlugins@" "$(< ${listOfPackagedPlugins})" '';
dependencies = [ click-default-group condense-json numpy openai pip pluggy puremagic pydantic python-ulid pyyaml setuptools # for pkg_resources sqlite-migrate sqlite-utils ];
nativeCheckInputs = [ cogapp numpy pytest-asyncio pytest-httpx pytest-recording syrupy pytestCheckHook ];
doCheck = true;
# The tests make use of `llm_echo` but that would be a circular dependency. # So we make a local copy in this derivation, as it's a super-simple package of one file. preCheck = '' cp ${llm-echo.src}/llm_echo.py llm_echo.py '';
pytestFlags = [ "-svv" ];
enabledTestPaths = [ "tests/" ];
pythonImportsCheck = [ "llm" ];
passthru = { inherit withPlugins withAllPlugins;
mkPluginTest = plugin: { ${plugin.pname} = callPackage ./mk-plugin-test.nix { inherit llm plugin; }; };
# include tests for all the plugins tests = lib.mergeAttrsList (map (name: python.pkgs.${name}.tests) withPluginsArgNames); };
meta = { homepage = "https://github.com/simonw/llm"; description = "Access large language models from the command-line"; changelog = "https://github.com/simonw/llm/releases/tag/${src.tag}"; license = lib.licenses.asl20; mainProgram = "llm"; maintainers = with lib.maintainers; [ aldoborrero mccartykim philiptaron ]; }; };inllm