This commit is contained in:
@@ -31,6 +31,7 @@ in
|
|||||||
];
|
];
|
||||||
|
|
||||||
nixpkgs.overlays = [
|
nixpkgs.overlays = [
|
||||||
|
hostConfig.inputs.self.overlays.default
|
||||||
hostConfig.inputs.claude-code-nix.overlays.default
|
hostConfig.inputs.claude-code-nix.overlays.default
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
Generated
+17
@@ -267,6 +267,22 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hindsight-src": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1780589667,
|
||||||
|
"narHash": "sha256-Zb8zIdlnm9spUiVbGdByGKE/V/5q+RKjbuSbayNIDxY=",
|
||||||
|
"owner": "vectorize-io",
|
||||||
|
"repo": "hindsight",
|
||||||
|
"rev": "7683f29004ab9d88e0ef3f0f18b8ffe6fc741905",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "vectorize-io",
|
||||||
|
"repo": "hindsight",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"home-manager": {
|
"home-manager": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -441,6 +457,7 @@
|
|||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"hermes-agent": "hermes-agent",
|
"hermes-agent": "hermes-agent",
|
||||||
|
"hindsight-src": "hindsight-src",
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"microvm": "microvm",
|
"microvm": "microvm",
|
||||||
"nix-index-database": "nix-index-database",
|
"nix-index-database": "nix-index-database",
|
||||||
|
|||||||
@@ -94,6 +94,13 @@
|
|||||||
uv2nix.inputs.pyproject-nix.follows = "hermes-agent/pyproject-nix";
|
uv2nix.inputs.pyproject-nix.follows = "hermes-agent/pyproject-nix";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Hindsight memory server (vectorize-io). No upstream flake; consumed as a
|
||||||
|
# bare source tree and packaged via the uv2nix toolchain from hermes-agent.
|
||||||
|
hindsight-src = {
|
||||||
|
url = "github:vectorize-io/hindsight";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, ... }@inputs:
|
outputs = { self, nixpkgs, ... }@inputs:
|
||||||
|
|||||||
@@ -21,6 +21,9 @@
|
|||||||
|
|
||||||
extraPackages = with pkgs; [ nix git ripgrep fd jq codex ];
|
extraPackages = with pkgs; [ nix git ripgrep fd jq codex ];
|
||||||
|
|
||||||
|
# Pulls in hindsight-client (the HTTP client lib the memory plugin uses).
|
||||||
|
extraDependencyGroups = [ "hindsight" ];
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
SIGNAL_HTTP_URL = "http://127.0.0.1:8080";
|
SIGNAL_HTTP_URL = "http://127.0.0.1:8080";
|
||||||
CODEX_HOME = "/var/lib/hermes/.codex";
|
CODEX_HOME = "/var/lib/hermes/.codex";
|
||||||
@@ -44,14 +47,14 @@
|
|||||||
toolsets = [ "all" ];
|
toolsets = [ "all" ];
|
||||||
terminal.backend = "local";
|
terminal.backend = "local";
|
||||||
|
|
||||||
# Self-hosted memory: pure SQLite in-process, no external services or
|
# Memory lives in a sibling hindsight-api process (see systemd unit
|
||||||
# API keys. db file lives under HERMES_HOME (= /var/lib/hermes/.hermes),
|
# below) backed by system postgres. Plugin talks HTTP to it locally.
|
||||||
# which is on the persisted bind-mount.
|
memory.provider = "hindsight";
|
||||||
memory.provider = "holographic";
|
plugins.hermes-hindsight = {
|
||||||
plugins.hermes-memory-store = {
|
mode = "local_external";
|
||||||
db_path = "/var/lib/hermes/.hermes/memory_store.db";
|
api_url = "http://127.0.0.1:8888";
|
||||||
auto_extract = true;
|
bank_id = "hermes";
|
||||||
default_trust = 0.5;
|
memory_mode = "hybrid";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -80,6 +83,8 @@
|
|||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
"d /var/lib/hermes/.codex 0700 googlebot users -"
|
"d /var/lib/hermes/.codex 0700 googlebot users -"
|
||||||
"C+ /var/lib/hermes/.codex/config.toml 0644 googlebot users - /etc/hermes-codex-config.toml"
|
"C+ /var/lib/hermes/.codex/config.toml 0644 googlebot users - /etc/hermes-codex-config.toml"
|
||||||
|
"d /var/lib/hermes/hindsight 0700 googlebot users -"
|
||||||
|
"d /var/lib/hermes/postgresql 0750 postgres postgres -"
|
||||||
];
|
];
|
||||||
|
|
||||||
# signal-cli runs an HTTP JSON-RPC daemon on localhost; hermes-agent talks to
|
# signal-cli runs an HTTP JSON-RPC daemon on localhost; hermes-agent talks to
|
||||||
@@ -102,4 +107,103 @@
|
|||||||
RestartSec = "5";
|
RestartSec = "5";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Hindsight memory backend
|
||||||
|
#
|
||||||
|
# Architecture:
|
||||||
|
# hermes-agent --HTTP--> hindsight-api (port 8888) --asyncpg--> postgres
|
||||||
|
# hindsight-worker (background async retain/reflect)
|
||||||
|
#
|
||||||
|
# The api + worker run as googlebot with HOME=/var/lib/hermes so the
|
||||||
|
# `openai-codex` provider's hardcoded Path.home() / ".codex" / "auth.json"
|
||||||
|
# resolves to the persisted codex tokens.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
services.postgresql = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.postgresql_17;
|
||||||
|
extensions = ps: [ ps.pgvector ];
|
||||||
|
# Persist DB state on the /var/lib/hermes bind mount so the hindsight
|
||||||
|
# memory bank survives `nixos-rebuild switch` (which recreates the
|
||||||
|
# incus container and wipes its writable layer).
|
||||||
|
dataDir = "/var/lib/hermes/postgresql/17";
|
||||||
|
ensureDatabases = [ "hindsight" ];
|
||||||
|
ensureUsers = [{
|
||||||
|
name = "googlebot";
|
||||||
|
# Superuser so the hindsight-api alembic migrations can `CREATE EXTENSION`
|
||||||
|
# and own the schema. Acceptable here because postgres is local-only to
|
||||||
|
# the sandboxed workspace and only talks to hindsight-api over the unix
|
||||||
|
# socket.
|
||||||
|
ensureClauses.superuser = true;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.hindsight-api =
|
||||||
|
let
|
||||||
|
env = {
|
||||||
|
# Connection — postgres is on the local unix socket; sqlalchemy gets
|
||||||
|
# an asyncpg URL via the asyncpg+host=<socket-dir> trick.
|
||||||
|
HINDSIGHT_API_DATABASE_URL = "postgresql+asyncpg:///hindsight?host=/run/postgresql";
|
||||||
|
HINDSIGHT_API_HOST = "127.0.0.1";
|
||||||
|
HINDSIGHT_API_PORT = "8888";
|
||||||
|
|
||||||
|
# LLM + embeddings both ride codex OAuth — no separate keys.
|
||||||
|
HINDSIGHT_API_LLM_PROVIDER = "openai-codex";
|
||||||
|
HINDSIGHT_API_EMBEDDINGS_PROVIDER = "openai-codex";
|
||||||
|
|
||||||
|
# We did not install [local-ml] extras, so disable the reranker
|
||||||
|
# (default is "local" which requires sentence-transformers).
|
||||||
|
HINDSIGHT_API_RERANKER_PROVIDER = "none";
|
||||||
|
|
||||||
|
# HOME drives where the codex auth file is read from
|
||||||
|
# (CodexLLM/CodexOAuthEmbeddings: Path.home() / ".codex" / "auth.json").
|
||||||
|
HOME = "/var/lib/hermes";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
description = "Hindsight memory API server";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "postgresql.service" "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
requires = [ "postgresql.service" ];
|
||||||
|
before = [ "hermes-agent.service" ];
|
||||||
|
environment = env;
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
User = "googlebot";
|
||||||
|
Group = "users";
|
||||||
|
ExecStart = "${pkgs.hindsight-api}/bin/hindsight-api";
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = "5";
|
||||||
|
WorkingDirectory = "/var/lib/hermes/hindsight";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.hindsight-worker =
|
||||||
|
let
|
||||||
|
env = {
|
||||||
|
HINDSIGHT_API_DATABASE_URL = "postgresql+asyncpg:///hindsight?host=/run/postgresql";
|
||||||
|
HINDSIGHT_API_LLM_PROVIDER = "openai-codex";
|
||||||
|
HINDSIGHT_API_EMBEDDINGS_PROVIDER = "openai-codex";
|
||||||
|
HINDSIGHT_API_RERANKER_PROVIDER = "none";
|
||||||
|
HOME = "/var/lib/hermes";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
description = "Hindsight background worker (async retain / reflect)";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "hindsight-api.service" ];
|
||||||
|
requires = [ "hindsight-api.service" ];
|
||||||
|
environment = env;
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
User = "googlebot";
|
||||||
|
Group = "users";
|
||||||
|
ExecStart = "${pkgs.hindsight-api}/bin/hindsight-worker";
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = "5";
|
||||||
|
WorkingDirectory = "/var/lib/hermes/hindsight";
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,4 +52,13 @@ in
|
|||||||
qtmultimedia qtwayland qtwebengine qcoro;
|
qtmultimedia qtwayland qtwebengine qcoro;
|
||||||
inherit (prev) lib fetchFromGitLab pkg-config sdl3 libcec wayland;
|
inherit (prev) lib fetchFromGitLab pkg-config sdl3 libcec wayland;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Hindsight agent-memory server. Built via uv2nix against the upstream
|
||||||
|
# workspace; uses hermes-agent's toolchain pin to avoid duplicating uv2nix.
|
||||||
|
hindsight-api = prev.callPackage ../pkgs/hindsight {
|
||||||
|
hindsight-src = inputs.hindsight-src;
|
||||||
|
uv2nix = inputs.hermes-agent.inputs.uv2nix;
|
||||||
|
pyproject-nix = inputs.hermes-agent.inputs.pyproject-nix;
|
||||||
|
pyproject-build-systems = inputs.hermes-agent.inputs.pyproject-build-systems;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
{ lib
|
||||||
|
, callPackage
|
||||||
|
, python312
|
||||||
|
, stdenv
|
||||||
|
, makeWrapper
|
||||||
|
|
||||||
|
, hindsight-src
|
||||||
|
, uv2nix
|
||||||
|
, pyproject-nix
|
||||||
|
, pyproject-build-systems
|
||||||
|
}:
|
||||||
|
|
||||||
|
# Build the hindsight-api-slim venv from upstream's uv workspace. We pick
|
||||||
|
# `hindsight-api-slim` (not `hindsight-api`) so we skip the `[all]` extras
|
||||||
|
# (local-ml, embedded-db). With openai-codex provider for both LLM and
|
||||||
|
# embeddings, and system postgres as the store, those extras are unused weight.
|
||||||
|
let
|
||||||
|
workspace = uv2nix.lib.workspace.loadWorkspace {
|
||||||
|
workspaceRoot = hindsight-src;
|
||||||
|
};
|
||||||
|
|
||||||
|
overlay = workspace.mkPyprojectOverlay {
|
||||||
|
sourcePreference = "wheel";
|
||||||
|
};
|
||||||
|
|
||||||
|
pythonSet =
|
||||||
|
(callPackage pyproject-nix.build.packages {
|
||||||
|
python = python312;
|
||||||
|
}).overrideScope
|
||||||
|
(lib.composeManyExtensions [
|
||||||
|
pyproject-build-systems.overlays.default
|
||||||
|
overlay
|
||||||
|
]);
|
||||||
|
|
||||||
|
venv = pythonSet.mkVirtualEnv "hindsight-api-env" {
|
||||||
|
hindsight-api-slim = [ ];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
pname = "hindsight-api";
|
||||||
|
version = "0.7.2";
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
nativeBuildInputs = [ makeWrapper ];
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
mkdir -p $out/bin
|
||||||
|
# The venv ships hindsight-api / hindsight-worker / hindsight-admin /
|
||||||
|
# hindsight-local-mcp / alembic in $venv/bin. Link them out so callers
|
||||||
|
# don't have to know about the venv layout.
|
||||||
|
for bin in hindsight-api hindsight-worker hindsight-admin hindsight-local-mcp alembic; do
|
||||||
|
if [ -e ${venv}/bin/$bin ]; then
|
||||||
|
ln -s ${venv}/bin/$bin $out/bin/$bin
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
passthru = {
|
||||||
|
inherit venv pythonSet;
|
||||||
|
pythonEnv = venv;
|
||||||
|
};
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Hindsight: agent memory with knowledge graph and tiered retrieval";
|
||||||
|
homepage = "https://github.com/vectorize-io/hindsight";
|
||||||
|
license = licenses.mit;
|
||||||
|
mainProgram = "hindsight-api";
|
||||||
|
platforms = platforms.linux;
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user