mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix(nix): fix build failures, TUI Node.js crash, and upgrade container to Node 22 (#12159)
* Add setuptools build dep for legacy alibabacloud packages and updated stale npm-deps hash * Add HERMES_NODE env var to pin Node.js version The TUI requires Node.js 20+ for regex `/v` flag support (used by string-width). Instead of relying on PATH lookup, explicitly set HERMES_NODE to the bundled Node 22 in the Nix wrapper, and add a fallback check in the Python code to use HERMES_NODE if available. Also upgrade container provisioning to Node 22 via NodeSource (Ubuntu 24.04 ships Node 18 which is EOL) and add a Nix check to verify the wrapper and Node version at build time.
This commit is contained in:
parent
2edebedc9e
commit
6fb69229ca
6 changed files with 56 additions and 10 deletions
|
|
@ -897,6 +897,10 @@ def _make_tui_argv(tui_dir: Path, tui_dev: bool) -> tuple[list[str], Path]:
|
||||||
_ensure_tui_node()
|
_ensure_tui_node()
|
||||||
|
|
||||||
def _node_bin(bin: str) -> str:
|
def _node_bin(bin: str) -> str:
|
||||||
|
if bin == "node":
|
||||||
|
env_node = os.environ.get("HERMES_NODE")
|
||||||
|
if env_node and os.path.isfile(env_node) and os.access(env_node, os.X_OK):
|
||||||
|
return env_node
|
||||||
path = shutil.which(bin)
|
path = shutil.which(bin)
|
||||||
if not path:
|
if not path:
|
||||||
print(f"{bin} not found — install Node.js to use the TUI.")
|
print(f"{bin} not found — install Node.js to use the TUI.")
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,29 @@ json.dump(sorted(leaf_paths(DEFAULT_CONFIG)), sys.stdout, indent=2)
|
||||||
echo "ok" > $out/result
|
echo "ok" > $out/result
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
# Verify HERMES_NODE is set in wrapper and points to Node 20+
|
||||||
|
# (string-width uses the /v regex flag which requires Node 20+)
|
||||||
|
hermes-node = pkgs.runCommand "hermes-node-version" { } ''
|
||||||
|
set -e
|
||||||
|
echo "=== Checking HERMES_NODE in wrapper ==="
|
||||||
|
grep -q "HERMES_NODE" ${hermes-agent}/bin/hermes || \
|
||||||
|
(echo "FAIL: HERMES_NODE not set in wrapper"; exit 1)
|
||||||
|
echo "PASS: HERMES_NODE present in wrapper"
|
||||||
|
|
||||||
|
HERMES_NODE=$(sed -n "s/^export HERMES_NODE='\(.*\)'/\1/p" ${hermes-agent}/bin/hermes)
|
||||||
|
test -x "$HERMES_NODE" || (echo "FAIL: HERMES_NODE=$HERMES_NODE not executable"; exit 1)
|
||||||
|
echo "PASS: HERMES_NODE executable at $HERMES_NODE"
|
||||||
|
|
||||||
|
NODE_MAJOR=$("$HERMES_NODE" --version | sed 's/^v//' | cut -d. -f1)
|
||||||
|
test "$NODE_MAJOR" -ge 20 || \
|
||||||
|
(echo "FAIL: Node v$NODE_MAJOR < 20, TUI needs /v regex flag support"; exit 1)
|
||||||
|
echo "PASS: Node v$NODE_MAJOR >= 20"
|
||||||
|
|
||||||
|
echo "=== All HERMES_NODE checks passed ==="
|
||||||
|
mkdir -p $out
|
||||||
|
echo "ok" > $out/result
|
||||||
|
'';
|
||||||
|
|
||||||
# Verify HERMES_MANAGED guard works on all mutation commands
|
# Verify HERMES_MANAGED guard works on all mutation commands
|
||||||
managed-guard = pkgs.runCommand "hermes-managed-guard" { } ''
|
managed-guard = pkgs.runCommand "hermes-managed-guard" { } ''
|
||||||
set -e
|
set -e
|
||||||
|
|
|
||||||
|
|
@ -121,11 +121,19 @@
|
||||||
# ── Provision apt packages (first boot only, cached in writable layer) ──
|
# ── Provision apt packages (first boot only, cached in writable layer) ──
|
||||||
# sudo: agent self-modification
|
# sudo: agent self-modification
|
||||||
# nodejs/npm: writable node so npm i -g works (nix store copies are read-only)
|
# nodejs/npm: writable node so npm i -g works (nix store copies are read-only)
|
||||||
# curl: needed for uv installer
|
# Node 22 via NodeSource — Ubuntu 24.04 ships Node 18 which is EOL.
|
||||||
|
# curl: needed for uv installer + NodeSource setup
|
||||||
if [ ! -f /var/lib/hermes-tools-provisioned ] && command -v apt-get >/dev/null 2>&1; then
|
if [ ! -f /var/lib/hermes-tools-provisioned ] && command -v apt-get >/dev/null 2>&1; then
|
||||||
echo "First boot: provisioning agent tools..."
|
echo "First boot: provisioning agent tools..."
|
||||||
apt-get update -qq
|
apt-get update -qq
|
||||||
apt-get install -y -qq sudo nodejs npm curl
|
apt-get install -y -qq sudo curl ca-certificates gnupg
|
||||||
|
mkdir -p /etc/apt/keyrings
|
||||||
|
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
|
||||||
|
| gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
||||||
|
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" \
|
||||||
|
> /etc/apt/sources.list.d/nodesource.list
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y -qq nodejs
|
||||||
touch /var/lib/hermes-tools-provisioned
|
touch /var/lib/hermes-tools-provisioned
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -171,7 +179,7 @@
|
||||||
# Package and entrypoint use stable symlinks (current-package, current-entrypoint)
|
# Package and entrypoint use stable symlinks (current-package, current-entrypoint)
|
||||||
# so they can update without recreation. Env vars go through $HERMES_HOME/.env.
|
# so they can update without recreation. Env vars go through $HERMES_HOME/.env.
|
||||||
containerIdentity = builtins.hashString "sha256" (builtins.toJSON {
|
containerIdentity = builtins.hashString "sha256" (builtins.toJSON {
|
||||||
schema = 3; # bump when identity inputs change
|
schema = 4; # bump when identity inputs change (4: Node 18→22 via NodeSource)
|
||||||
image = cfg.container.image;
|
image = cfg.container.image;
|
||||||
extraVolumes = cfg.container.extraVolumes;
|
extraVolumes = cfg.container.extraVolumes;
|
||||||
extraOptions = cfg.container.extraOptions;
|
extraOptions = cfg.container.extraOptions;
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,8 @@
|
||||||
--suffix PATH : "${runtimePath}" \
|
--suffix PATH : "${runtimePath}" \
|
||||||
--set HERMES_BUNDLED_SKILLS $out/share/hermes-agent/skills \
|
--set HERMES_BUNDLED_SKILLS $out/share/hermes-agent/skills \
|
||||||
--set HERMES_TUI_DIR $out/ui-tui \
|
--set HERMES_TUI_DIR $out/ui-tui \
|
||||||
--set HERMES_PYTHON ${hermesVenv}/bin/python3
|
--set HERMES_PYTHON ${hermesVenv}/bin/python3 \
|
||||||
|
--set HERMES_NODE ${pkgs.nodejs_22}/bin/node
|
||||||
'')
|
'')
|
||||||
[
|
[
|
||||||
"hermes"
|
"hermes"
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,20 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Legacy alibabacloud packages ship only sdists with setup.py/setup.cfg
|
||||||
|
# and no pyproject.toml, so setuptools isn't declared as a build dep.
|
||||||
|
buildSystemOverrides = final: prev: builtins.mapAttrs
|
||||||
|
(name: _: prev.${name}.overrideAttrs (old: {
|
||||||
|
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ final.setuptools ];
|
||||||
|
}))
|
||||||
|
(lib.genAttrs [
|
||||||
|
"alibabacloud-credentials-api"
|
||||||
|
"alibabacloud-endpoint-util"
|
||||||
|
"alibabacloud-gateway-dingtalk"
|
||||||
|
"alibabacloud-gateway-spi"
|
||||||
|
"alibabacloud-tea"
|
||||||
|
] (_: null));
|
||||||
|
|
||||||
pythonPackageOverrides = final: _prev:
|
pythonPackageOverrides = final: _prev:
|
||||||
if isAarch64Darwin then {
|
if isAarch64Darwin then {
|
||||||
numpy = mkPrebuiltOverride final python311.pkgs.numpy { };
|
numpy = mkPrebuiltOverride final python311.pkgs.numpy { };
|
||||||
|
|
@ -75,6 +89,7 @@ let
|
||||||
(lib.composeManyExtensions [
|
(lib.composeManyExtensions [
|
||||||
pyproject-build-systems.overlays.default
|
pyproject-build-systems.overlays.default
|
||||||
overlay
|
overlay
|
||||||
|
buildSystemOverrides
|
||||||
pythonPackageOverrides
|
pythonPackageOverrides
|
||||||
]);
|
]);
|
||||||
in
|
in
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ let
|
||||||
src = ../ui-tui;
|
src = ../ui-tui;
|
||||||
npmDeps = pkgs.fetchNpmDeps {
|
npmDeps = pkgs.fetchNpmDeps {
|
||||||
inherit src;
|
inherit src;
|
||||||
hash = "sha256-zsUPmbC6oMUO10EhS3ptvDjwlfpCSEmrkjyeORw7fac=";
|
hash = "sha256-mG3vpgGi4ljt4X3XIf3I/5mIcm+rVTUAmx2DQ6YVA90=";
|
||||||
};
|
};
|
||||||
|
|
||||||
packageJson = builtins.fromJSON (builtins.readFile (src + "/package.json"));
|
packageJson = builtins.fromJSON (builtins.readFile (src + "/package.json"));
|
||||||
|
|
@ -18,11 +18,6 @@ pkgs.buildNpmPackage {
|
||||||
|
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
|
|
||||||
postPatch = ''
|
|
||||||
# fetchNpmDeps strips the trailing newline; match it so the diff passes
|
|
||||||
sed -i -z 's/\n$//' package-lock.json
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
runHook preInstall
|
runHook preInstall
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue