From c771e8ad2fe2a0a2e755fbf5bba764b732bc2209 Mon Sep 17 00:00:00 2001 From: Mel Date: Tue, 16 Jun 2026 21:21:39 +0200 Subject: Extract renard agent configuration into a foundation module, allowing other hosts to have it's user Signed-off-by: Mel --- modules/foundation/agent.nix | 196 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 modules/foundation/agent.nix (limited to 'modules/foundation/agent.nix') diff --git a/modules/foundation/agent.nix b/modules/foundation/agent.nix new file mode 100644 index 0000000..6ac25aa --- /dev/null +++ b/modules/foundation/agent.nix @@ -0,0 +1,196 @@ +{ + config, + pkgs, + lib, + hermes-agent, + ... +}: + +let + inherit (lib) mkEnableOption mkIf mkMerge; + cfg = config.foundation.agent; + + # the set of tools the agent has access to by default. + # it should also always be able to call `nix-shell` to gain access to more tools. + agentPackages = with pkgs; [ + nix + nixfmt-rfc-style + + openssh + tailscale + + docker_29 + + jq + yq-go + ripgrep + fd + tree + file + unzip + gnused + gawk + + curl + wget + + htop + glances + lsof + iproute2 + iputils + inetutils + + dig + tcpdump + nmap + + git + + vim + ]; +in +{ + imports = [ + hermes-agent.nixosModules.default + ]; + + options.foundation.agent = { + home = mkEnableOption "the 'renard' agent to live on this machine"; + neighbor = mkEnableOption "letting the 'renard' agent access this machine"; + }; + + config = mkMerge [ + # both the home and each neighbor have a user for the agent. + (mkIf (cfg.home || cfg.neighbor) { + users = { + groups.renard = { }; + + users.renard = { + isSystemUser = true; + group = "renard"; + home = "/home/renard"; + createHome = true; + shell = pkgs.bashInteractive; + packages = agentPackages; + }; + }; + }) + + # the agent lives at home. + (mkIf cfg.home { + age.secrets.renard-agent = { + file = ../../secrets/renard-agent.age; + owner = "renard"; + group = "renard"; + mode = "0440"; + }; + + services.hermes-agent = { + enable = true; + + user = "renard"; + group = "renard"; + stateDir = "/home/renard"; + createUser = false; + + extraDependencyGroups = [ "messaging" ]; + + # both the user and the path house the same package set + extraPackages = agentPackages; + + environmentFiles = [ + # required secrets: + # * OPENROUTER_API_KEY + # * DISCORD_BOT_TOKEN + # * DISCORD_ALLOWED_USERS + config.age.secrets.renard-agent.path + ]; + + documents = { + "SOUL.md" = ../../assets/agent/SOUL.md; + }; + + settings = { + model = { + provider = "openrouter"; + # my current favorite budget model, with recent price + # changes by far the cheapest for the performance, + # with other chinese models also being close. + # only modality is text, requires auxiliary vision model! + # native price: $0.44/m in, $0.87/m out. + default = "deepseek/deepseek-v4-pro"; + }; + + agent = { + reasoning_effort = "high"; # 'high' rated highest in benchmarks, tune to taste! + max_turns = 90; + }; + + auxiliary.vision = { + # auxiliary vision model for image comprehension. + # this qwen model is built for this exact use-case and is extremely + # cheap for the performance (though below gemini), however, + # it does not do any reasoning on the visual input! + # possible upgrade path for reasoning: qwen3-vl-30b-a3b-thinking + # native price: $0.13/m in, $1.56/m out. + provider = "openrouter"; + model = "qwen/qwen3-vl-32b-instruct"; + timeout = 120; + }; + + toolsets = [ "all" ]; + + terminal = { + backend = "local"; + persistent_shell = true; + timeout = 180; + }; + + memory = { + memory_enabled = true; + user_profile_enabled = true; + }; + + # slightly higher limits and targets than default for better + # long session preservation. + compression = { + enabled = true; + threshold = 0.75; + target_ratio = 0.35; + protect_last_n = 40; + }; + + # progressive message editing, a little silly in discord but looks like + # the classic llm chats. + streaming = { + enabled = true; + }; + display = { + streaming = true; # small regression with streaming.enabled, keep both on. + tool_progress = "new"; # only show fresh new tool calls, not every call. + }; + + discord = { + require_mention = false; + thread_require_mention = false; + auto_thread = false; + reactions = true; + history_backfill = true; + allow_mentions = { + everyone = false; + roles = false; + users = true; + replied_user = true; + }; + }; + + unauthorized_dm_behavior = "ignore"; # ignore strangers + + timezone = "Europe/Berlin"; + group_sessions_per_user = false; + }; + }; + }) + ]; +} -- cgit 1.4.1