diff --git a/secrets/discord-hermes-bridge.yml b/secrets/discord-hermes-bridge.yml index ec4705b..2b8b1ac 100644 --- a/secrets/discord-hermes-bridge.yml +++ b/secrets/discord-hermes-bridge.yml @@ -1,17 +1,17 @@ -hermes_discord_bridge_env: ENC[AES256_GCM,data:SJ2zitdGqLLt9seXzmxu3o8uVmJFG6k5pGaMACpZ2aWzqbgP6D8LwTPKlJZiSZ8lwNUnurJrQ3J9RBSJaIOkoKrRtwX0AMs6crxRJe+E6CU=,iv:czq1KzUHEQs2fdDObhA0WmGgQwNwjczVcctQimttFxQ=,tag:LLcMUdPc4gQWhnZdWYD7XQ==,type:str] -discord_bot_hermes_bridge_env: ENC[AES256_GCM,data:VHIQgLh0azzLBEB9vemDrSPjqqSvirlp4d1fL+1vXwAmAYWN4UPMpYlUAjWrar23JY+QZ7FkFjbGV18GoPta6UYSIK/2ICVmsPHhHo1G3hEw+BUYYF+X,iv:8lis93YMqPz8mJR7J/ifm/SyYi1k/5s5XZVjglqR8G4=,tag:8i4Ju5C78CD3hfL+KmJXYg==,type:str] +hermes_discord_bridge_env: ENC[AES256_GCM,data:N14TYsne5p5a7PJvMZzJELORa7xV5Njy2ThiYN4fe0xP+Lt+f5XYcY1dkVi6Azp5VD2ILz+PT9Bg3deitSGsO9sduO6FGD9SFveUZZ7MOA==,iv:VYDRuQKbZFp4vgCG8ZKTaBQNuIdlF6KNLsNfoZi5xOY=,tag:x/sxdzlDghT9Hd8IaVWBHw==,type:str] +discord_bot_hermes_bridge_env: ENC[AES256_GCM,data:aG1k7e5o8AEGugKnuozvyy/pNzv8j+WJoVNmqnG3lDRBqhnzsNQoRr8BN8CimoRDncKHfRHMc/UalFbw+87RODw+MXfyo6YhvouQqh6xrnpN5/xfbpo=,iv:ISVsE+hvJBYdkGqjTqXlDzghRPzMZqq4F70hVxGd1EU=,tag:0Agx+x9/dPsyN0gY+VUiNw==,type:str] sops: age: - enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqendZNnBBdW9FQ0lYOXJT - WmN1b1ZoL2htbG1XRndlM2hlU1BjZTNZemprCktteUkvREtZYlFCTCtIdVh5WkFR - L1MxblNxKy9pVnRCYU9ScjZZdGhkelEKLS0tIDBmdk0xeGVzY3MwbmZncnFya2Fv - Nm4wRFY2UFQ0eFNuYXlGUWFjdytaZDQKjhK7ZpoqiWjdMFEXZ3Fzsas1EdKbTKNq - /2rL0KJAmQu/7pn9qKAXdrO7W7qf6XEwiVSmoZ0Z4BATcI6xiX+UPQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRL2lLM3pKanU3cm5HRFI5 + SmFHKzdMbXNtNmE1cXdTeEJYaGZ3b2RjbWlNCjBaZ1k4enVMM1RiMUdDU1hTdzBO + RGw1ay93R0JseEhPODVkNTc2bzFkMHMKLS0tIGZUVElIRk81enIyVTFJSlB0UE1J + ejBIcnd1ZW1Fb2hKcDdQellxcm5rM0EKFiwGlSEkY6zmb97CdZdtvuCXrbZaIrFB + emRzpaYoiPFFZor3WSrVtsXSaL1ujKddtUAEULKem1V4OFBsKL72HQ== -----END AGE ENCRYPTED FILE----- recipient: age1usm3v0ugducrzcwud60dda7xfnj49fdhecj7kcsfm7dzwzrzeyqq2jc2hm - lastmodified: "2026-09-27T06:54:21Z" - mac: ENC[AES256_GCM,data:+tNIeBz2vsvMPNGFIYm/VNaBm/jzDc2XtvhiRZVxYC+3IGM5On+2F8qKEmFEDEejdLo9SkKU2+XI0OBuD3fcBo5Gb9hevQMxS48W7EIzjsQ8KxHsvuRPor8krw8Q0vNyvpxtLOf9SEhcFWoYiFJt5HQ9q6lhvV93ZgQdXiZk4uI=,iv:66NsoDMKqsJHBjD1OO7B5o6B7tbmQIKnHYCyfiz9bKg=,tag:D9Db4M6lLeiWGENN1nMXRA==,type:str] + lastmodified: "2026-09-27T20:35:36Z" + mac: ENC[AES256_GCM,data:tU15GvpxbBefkdaBFRPel7yRreS62E10FltgvwT66oCBuE3I9RR9fbAdF4Xf0dMfG6ANRBVw0QGqlihjfBI84Ghaf57YKNhDuTvYcdP6fI3uQ0cZCEscY7H52o6VbOekawkWRP33Xnq4x3L+4fI0GkWmzK60Xm5zjPuNGcAsaF8=,iv:9nZfRiUj2SZ0f9Tw9+SFAOmJt9KzX92VZ2hrDDsopcQ=,tag:Dmk4zq0E3AvQ3LDbs2831Q==,type:str] unencrypted_suffix: _unencrypted version: 3.13.3 diff --git a/services/discord-bot/default.nix b/services/discord-bot/default.nix index 869a20a..6ed1a71 100644 --- a/services/discord-bot/default.nix +++ b/services/discord-bot/default.nix @@ -18,7 +18,8 @@ port = 8050; }; - # Pont vers le gateway Hermes dédié (services/discord-hermes-bridge). + # Pont vers l'API server Hermes. Un seul listener par hôte (le profil default, + # cf. services/hermes) : un profil secondaire est servi sous /p//. # HERMES_BRIDGE_URL n'est pas secret (loopback local), seule la clé l'est. systemd.services.discord-bot.serviceConfig.EnvironmentFile = lib.mkAfter [ config.sops.secrets."discord_bot_hermes_bridge_env".path @@ -26,6 +27,9 @@ systemd.services.discord-bot.environment = { HERMES_BRIDGE_URL = "http://127.0.0.1:8643/v1/chat/completions"; HERMES_BRIDGE_ROLE_NAME = "hermes"; + # Surface de test locale du cog (loopback, PAS ouverte au firewall) : + # POST /hermes/ask {"message": "..."} -> {"answer": "..."}. + HERMES_BRIDGE_ASK_PORT = "8052"; }; sops.secrets."discord_bot_env" = {}; diff --git a/services/hermes/default.nix b/services/hermes/default.nix index efcbc15..aba694a 100644 --- a/services/hermes/default.nix +++ b/services/hermes/default.nix @@ -39,7 +39,8 @@ environmentFiles = [ config.sops.secrets."hermes_env".path ] ++ lib.optional config.services.hermes.enableMatrixToken config.sops.secrets."hermes_matrix_env".path - ++ lib.optional config.services.hermes.enableDiscordToken config.sops.secrets."hermes_discord_env".path; + ++ lib.optional config.services.hermes.enableDiscordToken config.sops.secrets."hermes_discord_env".path + ++ [ config.sops.secrets."hermes_api_server_env".path ]; addToSystemPackages = true; # venv nix scellé -> deps mem0 (mem0ai) installées au runtime dans une cible durable @@ -67,6 +68,19 @@ # (l'env du process se pose sur l'unité systemd, pas via `environment`, qui # n'écrit que $HERMES_HOME/.env) --- + # --- API Server (OpenAI-compatible) : UN SEUL listener pour l'hôte --- + # La topologie de Hermes est "un gateway par hôte qui sert tous les profils" + # (multiplex). Un profil secondaire qui demande son API server n'obtient PAS + # son propre port : le listener du profil default le sert sous + # /p//... (log gateway : "api_server is served by the default + # profile's listener at /p// — not starting a second listener"). + # C'est ce que consomme le pont Discord : services/discord-bot appelle + # http://127.0.0.1:8642/p/discord-bridge/v1/chat/completions. + # Bind loopback uniquement, clé obligatoire (sops), jamais ouvert au + # firewall, jamais routé par Pangolin. + environment.API_SERVER_ENABLED = "true"; + environment.API_SERVER_PORT = "8642"; + # psycopg2 buildé par nix (évite le wheel manylinux psycopg2-binary) # numpy N'EST PLUS LISTÉ ICI : depuis l'ajout de "stt-whisper" (onnxruntime -> # numpy 2.4.3) le venv scellé le fournit lui-même, et le build du paquet hermes @@ -360,6 +374,15 @@ sops.secrets."hermes_env" = {}; + # Clé du listener API Server du profil default (clé "hermes_api_server_env" + # du fichier sops, valeur = contenu dotenv "API_SERVER_KEY=..."). Même valeur + # que HERMES_BRIDGE_API_KEY côté services/discord-bot, qui l'envoie en Bearer : + # le pont Discord et l'API server partagent donc LA MÊME clé, chiffrée une + # seule fois dans secrets/discord-hermes-bridge.yml. + sops.secrets."hermes_api_server_env" = { + sopsFile = ../../secrets/discord-hermes-bridge.yml; + }; + # Token Matrix du bot (@hermes) — clé "hermes_matrix_env" du fichier sops, # valeur = contenu dotenv (MATRIX_ACCESS_TOKEN=...) fusionné dans .env. # Déclaré uniquement là où l'option est active : les destinataires du fichier