terra: ollama (ROCm) + LibreChat with local persistent memory
Local LLM server on the 6800 XT (ollama-rocm, gfx1030 needs no HSA_OVERRIDE_GFX_VERSION) fronted by a LibreChat web UI, talking to it over the OpenAI-compatible /v1 route. Also wires up LibreChat's persistent-memory feature, which needed its own agent+model plus a custom extraction prompt: the default 3b model couldn't reliably tell the user's stated facts apart from its own boilerplate, and even a tuned prompt didn't fix that — so memory extraction now reuses gemma4:12b, the same model as the daily-driver chat endpoint. flake.lock bump pulls in the ollama and librechat NixOS modules. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Generated
+42
-42
@@ -14,11 +14,11 @@
|
||||
"uv2nix": "uv2nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1785761909,
|
||||
"narHash": "sha256-M8FNG0aca0/JsETvpYSJgwIrgJ4kpgxo9i7SDS0LfHs=",
|
||||
"lastModified": 1786986906,
|
||||
"narHash": "sha256-DJ1oU9szQJNdEM0dysh4NnKOB1HwOKtNukrUYKpawVs=",
|
||||
"owner": "nix-community",
|
||||
"repo": "authentik-nix",
|
||||
"rev": "db4a267f345338659a290a76e5b28da31e9923df",
|
||||
"rev": "afdb2eeca1e0b38fabb93c4a8944be73d3581268",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -101,11 +101,11 @@
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1782949081,
|
||||
"narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=",
|
||||
"lastModified": 1785627969,
|
||||
"narHash": "sha256-4dtXQk/NMePegK/nWp5NSeuZKLATItOq61lpEvmXqGw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e",
|
||||
"rev": "427bf4bd9435fdf21321c8cc628c24efc14c0f7a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -142,11 +142,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1785119570,
|
||||
"narHash": "sha256-Rgs2xKnGLFWQscxUaXX07oyZeuMDOHEbqDOsgliLFGM=",
|
||||
"lastModified": 1786924861,
|
||||
"narHash": "sha256-hftabkb+73OcGzvwFAjCiQorAhprs9TnU1+FkGO5CIw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "d4fd24667c8cbef124bb70a20380cab75ec8474d",
|
||||
"rev": "09ae1b85a6db412d841d60f924b23f881f0d0a38",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -270,11 +270,11 @@
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1785356851,
|
||||
"narHash": "sha256-UYKTcayxYPE3yIruCv525WMbcYDLlkv79bRfkOuFNLs=",
|
||||
"lastModified": 1786520020,
|
||||
"narHash": "sha256-9b0hAKM8UtNsm4lD3aySuXPjPpSibh6yfYEcNvr4fU0=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixos-anywhere",
|
||||
"rev": "5887f1c72fbf0e88000716237194de414d2299ee",
|
||||
"rev": "4cf3b82df8422f82657ae98c3b8374a5fd74f9a1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -291,11 +291,11 @@
|
||||
"nixos-unstable": "nixos-unstable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1785407732,
|
||||
"narHash": "sha256-iv6OYbZgMqvudEFB4LvhpZDHyNqD+lx0WubIk6BdAVg=",
|
||||
"lastModified": 1786617555,
|
||||
"narHash": "sha256-r3brKkBWm34wltszIeoZw2VCFUEoS2nNAe3W2Zgzc9k=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixos-images",
|
||||
"rev": "e2a34c0ce9dcbb5169f2a233b49211f5f30b7d69",
|
||||
"rev": "f01878e82602ad3d0a2e74a14440521924e57bc5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -323,11 +323,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1785692966,
|
||||
"narHash": "sha256-vUfIeBEfpbAfZ5zjgIkYk7eHBeVfCYVjLbWnMkseYnk=",
|
||||
"lastModified": 1786862985,
|
||||
"narHash": "sha256-FBJRXmbGXiSUDvYEbfLYRkckayyZ6SK1UEqhCrIZ2Cs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "643809054d65fdd466a63e3155b8c498cb483c04",
|
||||
"rev": "e5bdc4a41d4c072fe1e3787eaa0320a384741d44",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -339,11 +339,11 @@
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1782614948,
|
||||
"narHash": "sha256-ePjCwr1sNm9NYUqywL7QfK3JnlS015msC+eBu2zKlp8=",
|
||||
"lastModified": 1785031560,
|
||||
"narHash": "sha256-OmshNvn2vupOFpYinLUu+1Dnpu4n7Q5N3ggGVNHpkUI=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "db3f255737b94216eb71cce308e2912cf6bc2d7c",
|
||||
"rev": "0e79af5e3d4dcfcd676ab5ba3f95d2e3352e078c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -354,11 +354,11 @@
|
||||
},
|
||||
"nixpkgs-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1785747939,
|
||||
"narHash": "sha256-D740uKsMbgsfK2oaDenJLLPIZfq7W0/g4KN/Fls8eKs=",
|
||||
"lastModified": 1786963906,
|
||||
"narHash": "sha256-3tkeMWSvHPo3tYljfXbPC/TgknikU1GvdVr/DkdfvE0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "104240a772428cc2e20d8fd86c9ddbb886bbaff2",
|
||||
"rev": "f4b6996c4e8b9ee06ce147ec344c885f51071b14",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -370,11 +370,11 @@
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1785734586,
|
||||
"narHash": "sha256-ODZkEK9Gy50yg6h98u7KkitZ3oc/uuTFK00bh1CRdNA=",
|
||||
"lastModified": 1786943417,
|
||||
"narHash": "sha256-b4qgjdFtlz5TAZ1Hi7DFJeqX3sjaDUnrwr9OO+O1rM0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "531670d871c0e29724a02f3cbcac170adc65b58c",
|
||||
"rev": "0dd31db7e6dbf9ce05697c4545f6fe01accec994",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -400,11 +400,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1785115949,
|
||||
"narHash": "sha256-8AM37BfyGaL2v/SZyg4PupRxJ01Y4htvM+WrTjWrPpo=",
|
||||
"lastModified": 1785730568,
|
||||
"narHash": "sha256-NjSPsgjJ7MSpBtTkUcmNhRe6AFZ96+zsca2M8YuQi8Y=",
|
||||
"owner": "pyproject-nix",
|
||||
"repo": "build-system-pkgs",
|
||||
"rev": "62c0d86027edb1c4f39a5facc09876348144f7c9",
|
||||
"rev": "90fde00db3687922d39d95fc591475fd0bbbcd72",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -450,11 +450,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1784591072,
|
||||
"narHash": "sha256-zP/WaDxrRu8GANZM61+V2LT/7ycEEdoyLWn7M6WzU7M=",
|
||||
"lastModified": 1786031528,
|
||||
"narHash": "sha256-cROiHKO3UbIKqF5FG5NikvydzlfIj4EcR1Cty9qOVt4=",
|
||||
"owner": "pyproject-nix",
|
||||
"repo": "pyproject.nix",
|
||||
"rev": "e3b599ca2e7fcf93d4edf65d7f19bbf6491724f3",
|
||||
"rev": "1b1485546d85f6f6c7aadb10c4923dbc09633263",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -507,11 +507,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1783174389,
|
||||
"narHash": "sha256-aCWC8ngycU7OdJrU2+Je3qf+1a2ykuBvpPhZT/9tXMc=",
|
||||
"lastModified": 1786629091,
|
||||
"narHash": "sha256-gkig4nPi1CWc4Z50GBsjE4ygSE7hMpl/TwID2an2Cck=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "f1406619a3884cd5c47992a70b8b35c9c0fcb4c9",
|
||||
"rev": "a8627b21b9107c5711c96b84f32a9a4b3d45295f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -559,11 +559,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1784369104,
|
||||
"narHash": "sha256-47cxbcZODibHv3rELFQ9vZly0vUNkND/atn/U7HLeb0=",
|
||||
"lastModified": 1785945821,
|
||||
"narHash": "sha256-NLSyTCW4K4ofhNBllt3omPasm6QpralXH1DBZOc91Dw=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "df3c0640565d04a0261253cdd89fce78ec50168a",
|
||||
"rev": "ae7910970dddc408fe6ab1c8e4b277bb21d72dc0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -584,11 +584,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1785277507,
|
||||
"narHash": "sha256-9Tq3UDX2hD/aveW/HvkBlAmEwJTOlY5HQXJM+L5BGmE=",
|
||||
"lastModified": 1786615403,
|
||||
"narHash": "sha256-U++y7nM/6xiEcWI7q4fQoPZjPvRaTwkSqzBOVoEBjUE=",
|
||||
"owner": "pyproject-nix",
|
||||
"repo": "uv2nix",
|
||||
"rev": "5a836d395cbf5fc22670eb98dd4aa4fc4d406977",
|
||||
"rev": "4b59abb2ae1896d2a0e1abfc47fbc9bf985ea730",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -17,6 +17,7 @@ in
|
||||
../../services/vpn/tailscale.nix
|
||||
../../services/desktop/desktop-hyprland.nix
|
||||
../../services/desktop/desktop-apps.nix
|
||||
../../services/desktop/librechat.nix
|
||||
];
|
||||
|
||||
networking.hostName = "terra";
|
||||
@@ -69,6 +70,34 @@ in
|
||||
# whisper.cpp/llama.cpp containers in ~/Data/Dev/repos/content-trigger-scanner.
|
||||
users.users.darman.extraGroups = [ "render" "video" ];
|
||||
|
||||
# ---- ollama (local LLM server, ROCm on the 6800 XT) ----
|
||||
# Navi 21 is gfx1030 — officially supported by ROCm, so no
|
||||
# rocmOverrideGfx/HSA_OVERRIDE_GFX_VERSION needed (that's for gpus ROCm
|
||||
# doesn't recognize, e.g. RDNA1/gfx101x). The upstream module runs the
|
||||
# service under DynamicUser with SupplementaryGroups=["render"] and
|
||||
# DeviceAllow for char-kfd/char-drm/char-fb already, so unlike jellyfin's
|
||||
# static user it needs no extraGroups wiring here.
|
||||
services.ollama = {
|
||||
enable = true;
|
||||
package = pkgs.ollama-rocm;
|
||||
# keep in sync with services/desktop/librechat.nix's endpoints.custom
|
||||
# default model — LibreChat's config schema needs a non-empty default
|
||||
# even though fetch=true replaces it with whatever's actually pulled.
|
||||
# gemma4:12b: general chat/coding daily driver, fits fully in 16G VRAM —
|
||||
# also doubles as the memory-extraction agent (see librechat.nix): a
|
||||
# 3b model (llama3.2:3b, dropped) couldn't reliably tell the user's
|
||||
# stated facts apart from its own boilerplate, e.g. saving "I am an AI
|
||||
# assistant with tool calling capabilities" as the user's personal_info
|
||||
# after "Hi I'm Erik Simon". Reusing gemma4:12b for both roles also means
|
||||
# no second model needs to swap into VRAM while it's already the active
|
||||
# chat model.
|
||||
# qwen3.6:35b-a3b: MoE (3B active/36B total), ~24GB Q4_K_M — doesn't fit
|
||||
# in VRAM alone, so ollama offloads the inactive experts to CPU RAM.
|
||||
# Sparse activation makes that far less painful than it'd be for a dense
|
||||
# model this size, but still expect it to run slower than the two above.
|
||||
loadModels = [ "gemma4:12b" "qwen3.6:35b-a3b" ];
|
||||
};
|
||||
|
||||
# ---- Dev-data disks — NOT in disko, mounted read-write, never wiped ----
|
||||
fileSystems."/mnt/hdd_01" = {
|
||||
device = "/dev/disk/by-uuid/b8445126-ec6d-4f88-818a-d9e13031d9a4";
|
||||
|
||||
@@ -21,4 +21,14 @@
|
||||
username=darman
|
||||
password=${config.sops.placeholder.samba_password}
|
||||
'';
|
||||
|
||||
# LibreChat's CREDS_KEY/IV encrypt stored user credentials (linked 3rd-party
|
||||
# API keys etc) at rest in mongo; JWT_SECRET/JWT_REFRESH_SECRET sign session
|
||||
# tokens. All four are random, generated once with `sops --set` (see
|
||||
# CLAUDE.md) — losing/rotating them just invalidates existing sessions and
|
||||
# any saved per-user API keys, nothing else depends on their value.
|
||||
sops.secrets.librechat_creds_key = { };
|
||||
sops.secrets.librechat_creds_iv = { };
|
||||
sops.secrets.librechat_jwt_secret = { };
|
||||
sops.secrets.librechat_jwt_refresh_secret = { };
|
||||
}
|
||||
|
||||
+6
-2
@@ -1,6 +1,10 @@
|
||||
tailscale_authkey: ENC[AES256_GCM,data:DgxbMrKTxC//cWd+ZckCbwZ9j/FgjYwNwadU5cWnnPz+nPEFhXLla2TuUE0pJKpcx9pKZCQmxcGtzQvIB+mbgxjgB0X2CRTp4Yy3WR+PBYMghKx36F8KBg==,iv:hJr6O41OTdMa4wkBXEsRUXgV4zWt21h1kx/CWArLU7o=,tag:IEpMIwKBHakvVYEFdEUe7A==,type:str]
|
||||
darman_password: ENC[AES256_GCM,data:G3ZM+NMxvKq5twblcBvyC+MiUX+X7nz+s1GqBHBkJQy1YgW4KN6rpbdj10F9jWxHph5dJ9j9fG6L7UlEg5W5zUYeLFdEx2xJGE1fxksch+6BB9FT6LKkhJ7MmbJmhNHYwJOZO3LM1f/oRw==,iv:abQTRe9kRyYj+TL0rtoxM6JFBaIBmxu7y77qt1h4eME=,tag:OgKrB3SUgSNJjmtJyrmh/Q==,type:str]
|
||||
samba_password: ENC[AES256_GCM,data:UkJLUa2hW1iZ++sfJAcg6G1RJMM=,iv:/HbZ9F+GxCydUP50PNBtJknPlmDWh1DAE26N9FJUyb0=,tag:z1cbwUaVdyfwEIU8LINEcw==,type:str]
|
||||
librechat_creds_key: ENC[AES256_GCM,data:e2Ptf41yHu0KxfzjW4DP04CSJfbtdsJ8bwrgJyv9up4/JSCbBzjPFmOi7jsHUL4jT0AGVuHG5w3y+YOil9EeNA==,iv:zneozNSkXsb4Vy/sq21b8HWCKpDkXVTxyLY2Zh0bwP0=,tag:6CxR5sIspbfzHlfdx+45Iw==,type:str]
|
||||
librechat_creds_iv: ENC[AES256_GCM,data:iuW1Rxfu7Ei8zHVG7wsBTYYznbtErj7DC9B71OiiWGA=,iv:Ngs88C44gcSzxQZU1lMiy5kn9mM/ckuWKRRGOFJeeoQ=,tag:Q9B8vM4YMkIP3RyYVWSQqg==,type:str]
|
||||
librechat_jwt_secret: ENC[AES256_GCM,data:f/gljrQPZIXeLHXtqKCCYGEu2pXgbZd69CjyEhSVJ+AMuaVj7DWVclD5IMsEVERBHw5a7OndBSfLvgXRaKN6Gg==,iv:DG5CwCbQLCTv1++APCdFzAiWGKiEJl+9MhKIM2ykJQM=,tag:wdpY6l+5h4UtsluIncsyhA==,type:str]
|
||||
librechat_jwt_refresh_secret: ENC[AES256_GCM,data:N/yAPtaodJX4t2C2A0bZ/LQaVc8SBMgg3KYJrWRyXCM6HAmgHtSQ9nWJO2fl+7A966mMtYvpATYcBIPj/K5nig==,iv:k5ZYi2OKjL9Z+lhVgdNsmGVQm+iCqmF15H3TUTbofWk=,tag:NVTdvlL1lpwVhjo2c2phpg==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- enc: |
|
||||
@@ -21,7 +25,7 @@ sops:
|
||||
sHjKfw8VrrmAR4pQf1dsY+wcyh4FsZxhP3Q+QIVq3eCIXS9PeJkGAg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
recipient: age1rfcmu6zh40v4260l9hnf8ajs9vly0s06rx3ey76eu78dp9t7getqyhmkut
|
||||
lastmodified: "2026-07-28T20:18:44Z"
|
||||
mac: ENC[AES256_GCM,data:TRh/Idd8MEq/5QRb7r+g6msdaObtVzsX5hK5gacJI6seZ5BLW5tcBO/E2m8ya4t50lTofxkwObWskMbCOucLDYt+lnYwHSqDvAeQRvswxaCZgiFOn0upqCi8H4OomvIK475SIH6bniyN9bCQ2gaSS0D9aecyCSmdUARkmcZEYLc=,iv:PBoEUZG0QNyj4B0c6zuWr6Y39EdL1CoAsVExU86P6Tw=,tag:NPxsWkxdojXNsoxVVMb5TQ==,type:str]
|
||||
lastmodified: "2026-08-17T21:14:30Z"
|
||||
mac: ENC[AES256_GCM,data:vbD0W0zN5WV4UonOWreZWvUrAP7A/PllGxTS29L0qSc8HdV+IzVtHfknl3QSrAx1cAgd0exz1mr2yVsBX5Ez4rzdyXO63KE1uwT/A5ZdZW8iEv/HP4I1dxuDN0U2nd5aFxAFqckYXQd24u/2JKZhtiwOG9QHlwm5bAr8+7o3r2k=,iv:BZ/8m4Gsbj/eg77qbcTFe7e6wqEBH2NVON/4zH74yAM=,tag:WumJmaIcIhm4nyouLGf7og==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.13.2
|
||||
|
||||
@@ -18,6 +18,7 @@ in
|
||||
"claude-code"
|
||||
"proton-pass-cli"
|
||||
"vivaldi"
|
||||
"mongodb" # librechat's local db (services/desktop/librechat.nix) — SSPL
|
||||
];
|
||||
|
||||
programs.steam = {
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
{ config, ... }:
|
||||
|
||||
# LibreChat — web chat UI, talking to the local ollama server (see
|
||||
# hosts/terra/configuration.nix) over its OpenAI-compatible /v1 route.
|
||||
# Only reachable over the tailnet (networking.firewall.trustedInterfaces =
|
||||
# [ "tailscale0" ] in services/vpn/tailscale.nix) — openFirewall stays off.
|
||||
{
|
||||
services.librechat = {
|
||||
enable = true;
|
||||
enableLocalDB = true; # spins up a local, unauthenticated-on-localhost mongodb
|
||||
|
||||
# LibreChat's isEnabled() treats an UNSET var as false, not true — so
|
||||
# registration is closed unless this is explicit, despite .env.example
|
||||
# suggesting true is the default. Only reachable over the tailnet
|
||||
# (trusted interface, see module comment below), so leaving it open is
|
||||
# fine; flip to false once your account exists if you want it locked down.
|
||||
env.ALLOW_REGISTRATION = true;
|
||||
|
||||
credentials = {
|
||||
CREDS_KEY = config.sops.secrets.librechat_creds_key.path;
|
||||
CREDS_IV = config.sops.secrets.librechat_creds_iv.path;
|
||||
JWT_SECRET = config.sops.secrets.librechat_jwt_secret.path;
|
||||
JWT_REFRESH_SECRET = config.sops.secrets.librechat_jwt_refresh_secret.path;
|
||||
};
|
||||
|
||||
settings = {
|
||||
version = "1.2.1";
|
||||
endpoints.custom = [
|
||||
{
|
||||
name = "Ollama";
|
||||
# required field but unchecked by ollama's OpenAI-compat shim
|
||||
apiKey = "ollama";
|
||||
baseURL = "http://127.0.0.1:11434/v1";
|
||||
models = {
|
||||
# schema requires >=1 entry even though fetch=true overwrites it
|
||||
# at runtime with whatever's pulled (see loadModels in
|
||||
# hosts/terra/configuration.nix) — kept roughly in sync anyway
|
||||
# so the UI has sane names before the first fetch completes.
|
||||
default = [ "gemma4:12b" "qwen3.6:35b-a3b" ];
|
||||
fetch = true; # pull the model list from ollama at startup
|
||||
};
|
||||
titleConvo = true;
|
||||
}
|
||||
];
|
||||
|
||||
# Persistent memory is opt-in at the CONFIG level — omitting this block
|
||||
# (as before) leaves the feature entirely off, no matter what a user
|
||||
# toggles in Settings > Personalization. `agent.provider` must match
|
||||
# endpoints.custom[].name above exactly ("Ollama"), which is how the
|
||||
# memory-extraction agent picks a backend/model.
|
||||
memory = {
|
||||
personalize = true; # still needs a per-user opt-in toggle in the UI
|
||||
# instructions REPLACES the default extraction prompt entirely (not
|
||||
# appended to it) — the 3b model (llama3.2:3b, dropped) was
|
||||
# defaulting to saving things like its own "I am a helpful
|
||||
# assistant..." boilerplate under an invented "user_conversation"
|
||||
# key, and even after adding this prompt, still saved "I am an AI
|
||||
# assistant with tool calling capabilities" as personal_info after
|
||||
# the user introduced THEMSELVES — a capability ceiling, not a
|
||||
# prompting problem. validKeys constrains it to a fixed whitelist
|
||||
# and instructions spells out the bar for each one.
|
||||
validKeys = [ "user_preferences" "personal_info" "ongoing_projects" "technical_context" ];
|
||||
agent = {
|
||||
enabled = true;
|
||||
provider = "Ollama";
|
||||
# same model as the chat endpoint's primary driver — when that's
|
||||
# the active chat model, extraction needs no second model swapped
|
||||
# into VRAM alongside it.
|
||||
model = "gemma4:12b";
|
||||
instructions = ''
|
||||
Save memory ONLY using the keys below, and only when the user's
|
||||
message states something durable and genuinely useful to recall
|
||||
in a LATER, unrelated conversation. Small talk, greetings, and
|
||||
anything about what the assistant said or is capable of are NOT
|
||||
memories — if nothing meets the bar, save nothing.
|
||||
|
||||
set_memory REPLACES the entire value stored at a key — it does
|
||||
NOT append to it. Before calling set_memory for a key, check the
|
||||
"Existing memory" section below. If that key already has a
|
||||
value, your new value MUST merge the old and new information
|
||||
into one complete sentence or short paragraph — calling
|
||||
set_memory with only the newest fact silently ERASES everything
|
||||
already stored under that key. Only drop prior details if the
|
||||
user is explicitly correcting or replacing them.
|
||||
|
||||
- user_preferences: explicitly stated preferences (tools, formats, style).
|
||||
- personal_info: durable facts about the user (name, role, timezone).
|
||||
- ongoing_projects: projects or tasks the user is actively working on.
|
||||
- technical_context: durable facts about the user's setup/stack
|
||||
relevant to future answers (e.g. "runs NixOS", "GPU is AMD ROCm").
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user