mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-09-29 17:23:59 +08:00
feat(python): pin bundled runtime to 3.14 everywhere (pm, termux lane, CI, installers)
pm python node: 3.14.7+20260901 (freshest python-build-standalone 3.14 build) for the 6 desktop targets; the bionic row moves from the third-party TUR python3.11 deb to the official termux-main python_3.14.6-1 deb (which lags PBS by one patch — pinned manually, documented). All 7 digests fetched from the live sources (PBS release API + termux-main Packages index). pm/packages.py: main_bin_rel python3.14, deb_package python, bionic fetch constant, latest_versions guards bionic (no PBS build exists). termux lane: PYTHON_ABI cp311->cp314, python3.11->python3.14 paths, libpython3.11.so->3.14, TARGET_ENV 3.11.15->3.14.6 AND sys_platform linux->android (CPython 3.13+ reports 'android', docs-verified) — linux- gated markers no longer admit the termux target. runtime_libs.json needs no change: every python 3.14.6-1 Depends is already staged. CI: python-version/--python 3.11->3.14 across all 11 workflows incl. the uv lockfile-check lane. Installers derive the minor from the lock already; fallbacks bumped. Sandbox images nikolaik/python-nodejs:python3.11-nodejs20 -> python3.14-nodejs22 (tag exists). runtime_repair fall-forward cap now tracks the <3.15 requires-python window. Docs/README python version claims updated.
This commit is contained in:
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.11'
|
||||
python-version: '3.14'
|
||||
|
||||
- name: Install PyYAML for skill extraction
|
||||
uses: ./.github/actions/retry
|
||||
|
||||
@@ -430,12 +430,12 @@ jobs:
|
||||
AZURE_TENANT_ID: ${{ vars.AZURE_TENANT_ID }}
|
||||
AZURE_TOKEN_CREDENTIALS: prod
|
||||
run: |
|
||||
uv run --no-project --python 3.11 python scripts/bundles/desktop.py --tag="$HERMES_PAYLOAD_TAG" --variant=bundled
|
||||
uv run --no-project --python 3.14 python scripts/bundles/desktop.py --tag="$HERMES_PAYLOAD_TAG" --variant=bundled
|
||||
# The Store-submission MSIX is the same bundled payload re-packed
|
||||
# with the Partner Center packaging identity (publish-win32-store
|
||||
# bundles these into the universal Store .msixbundle and submits it;
|
||||
# they also land in the tag archive, never a feed dir).
|
||||
uv run --no-project --python 3.11 python scripts/bundles/desktop.py --tag="$HERMES_PAYLOAD_TAG" --variant=store
|
||||
uv run --no-project --python 3.14 python scripts/bundles/desktop.py --tag="$HERMES_PAYLOAD_TAG" --variant=store
|
||||
|
||||
- name: Verify native signature cache contracts
|
||||
shell: bash
|
||||
@@ -730,7 +730,7 @@ jobs:
|
||||
# every Mach-O) — raise the fd limit and let DEBUG show progress.
|
||||
ulimit -n 16384 2>/dev/null || true
|
||||
echo "file descriptor limit: soft=$(ulimit -Sn) hard=$(ulimit -Hn)"
|
||||
uv run --no-project --python 3.11 python scripts/bundles/desktop.py --tag="$HERMES_PAYLOAD_TAG" --variant=bundled
|
||||
uv run --no-project --python 3.14 python scripts/bundles/desktop.py --tag="$HERMES_PAYLOAD_TAG" --variant=bundled
|
||||
|
||||
- name: Audit bundle architecture
|
||||
shell: bash
|
||||
|
||||
@@ -150,10 +150,10 @@ jobs:
|
||||
# fail the job (2026-07-28 incident). Keep in sync with tests.yml.
|
||||
version: "0.9.28"
|
||||
|
||||
- name: Set up Python 3.11 (for docker tests)
|
||||
- name: Set up Python 3.14 (for docker tests)
|
||||
uses: ./.github/actions/retry
|
||||
with:
|
||||
command: uv python install 3.11
|
||||
command: uv python install 3.14
|
||||
|
||||
- name: Install Python dependencies (for docker tests)
|
||||
# ``dev`` extra pulls in pytest, pytest-asyncio —
|
||||
@@ -162,7 +162,7 @@ jobs:
|
||||
# subprocess and don't import hermes_agent's optional deps.
|
||||
uses: ./.github/actions/retry
|
||||
with:
|
||||
command: uv sync --locked --python 3.11 --extra dev
|
||||
command: uv sync --locked --python 3.14 --extra dev
|
||||
|
||||
- name: Run docker integration tests
|
||||
env:
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.11"
|
||||
python-version: "3.14"
|
||||
|
||||
- name: Install ascii-guard
|
||||
uses: ./.github/actions/retry
|
||||
|
||||
@@ -70,15 +70,15 @@ jobs:
|
||||
pyproject.toml
|
||||
uv.lock
|
||||
|
||||
- name: Set up Python 3.11
|
||||
- name: Set up Python 3.14
|
||||
uses: ./.github/actions/retry
|
||||
with:
|
||||
command: uv python install 3.11
|
||||
command: uv python install 3.14
|
||||
|
||||
- name: Install Python dependencies
|
||||
uses: ./.github/actions/retry
|
||||
with:
|
||||
command: uv sync --locked --python 3.11 --extra all --extra dev
|
||||
command: uv sync --locked --python 3.14 --extra all --extra dev
|
||||
|
||||
# ── Build desktop app ─────────────────────────────────────────────
|
||||
# The Playwright step below runs `npm run build` before testing so
|
||||
|
||||
@@ -171,10 +171,10 @@ jobs:
|
||||
# fail the job (2026-07-28 incident). Keep in sync with tests.yml.
|
||||
version: "0.9.28"
|
||||
|
||||
- name: Set up Python 3.11
|
||||
- name: Set up Python 3.14
|
||||
uses: ./.github/actions/retry
|
||||
with:
|
||||
command: uv python install 3.11
|
||||
command: uv python install 3.14
|
||||
|
||||
- name: Run footgun checker
|
||||
run: python scripts/check-windows-footguns.py --all
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.11"
|
||||
python-version: "3.14"
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/retry
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y patchelf
|
||||
uv venv --python 3.11 .venv
|
||||
uv venv --python 3.14 .venv
|
||||
uv export --frozen --extra dev --no-emit-project --no-hashes -o "$RUNNER_TEMP/requirements.txt"
|
||||
uv pip install --python .venv/bin/python -r "$RUNNER_TEMP/requirements.txt"
|
||||
- name: Run the native linker and wheel contracts
|
||||
|
||||
@@ -80,10 +80,10 @@ jobs:
|
||||
pyproject.toml
|
||||
uv.lock
|
||||
|
||||
- name: Set up Python 3.11
|
||||
- name: Set up Python 3.14
|
||||
uses: ./.github/actions/retry
|
||||
with:
|
||||
command: uv python install 3.11
|
||||
command: uv python install 3.14
|
||||
|
||||
- name: Install dependencies
|
||||
# Same extras as the Linux test lane so an OS-marked test can import
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
# because it could not build here).
|
||||
uses: ./.github/actions/retry
|
||||
with:
|
||||
command: uv sync --locked --python 3.11 --extra all --extra dev --extra anthropic --extra mistral --extra fal --extra modal --extra daytona --extra hindsight --extra parallel-web
|
||||
command: uv sync --locked --python 3.14 --extra all --extra dev --extra anthropic --extra mistral --extra fal --extra modal --extra daytona --extra hindsight --extra parallel-web
|
||||
|
||||
- name: Minimize uv cache
|
||||
run: uv cache prune --ci
|
||||
|
||||
@@ -59,10 +59,10 @@ jobs:
|
||||
pyproject.toml
|
||||
uv.lock
|
||||
|
||||
- name: Set up Python 3.11
|
||||
- name: Set up Python 3.14
|
||||
uses: ./.github/actions/retry
|
||||
with:
|
||||
command: uv python install 3.11
|
||||
command: uv python install 3.14
|
||||
|
||||
- name: Install dependencies
|
||||
# `uv sync --locked` installs the exact pinned set from uv.lock (and
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
# also honors the exact supply-chain pins these extras carry.
|
||||
uses: ./.github/actions/retry
|
||||
with:
|
||||
command: uv sync --locked --python 3.11 --extra all --extra dev --extra anthropic --extra mistral --extra fal --extra modal --extra daytona --extra hindsight --extra parallel-web
|
||||
command: uv sync --locked --python 3.14 --extra all --extra dev --extra anthropic --extra mistral --extra fal --extra modal --extra daytona --extra hindsight --extra parallel-web
|
||||
|
||||
- name: Minimize uv cache
|
||||
# Optimized for CI: prunes pre-built wheels that are cheap to
|
||||
@@ -164,8 +164,8 @@ jobs:
|
||||
pyproject.toml
|
||||
uv.lock
|
||||
|
||||
- name: Set up Python 3.11
|
||||
run: uv python install 3.11
|
||||
- name: Set up Python 3.14
|
||||
run: uv python install 3.14
|
||||
|
||||
- name: Install dependencies
|
||||
# `uv sync --locked` installs the exact pinned set from uv.lock (and
|
||||
@@ -179,7 +179,7 @@ jobs:
|
||||
# in the venv up front.
|
||||
uses: ./.github/actions/retry
|
||||
with:
|
||||
command: uv sync --locked --python 3.11 --extra all --extra dev --extra anthropic --extra mistral --extra fal --extra modal --extra daytona --extra hindsight --extra parallel-web
|
||||
command: uv sync --locked --python 3.14 --extra all --extra dev --extra anthropic --extra mistral --extra fal --extra modal --extra daytona --extra hindsight --extra parallel-web
|
||||
|
||||
- name: Minimize uv cache
|
||||
# Optimized for CI: prunes pre-built wheels that are cheap to
|
||||
|
||||
@@ -42,15 +42,15 @@ jobs:
|
||||
pyproject.toml
|
||||
uv.lock
|
||||
|
||||
- name: Set up Python 3.11
|
||||
- name: Set up Python 3.14
|
||||
uses: ./.github/actions/retry
|
||||
with:
|
||||
command: uv python install 3.11
|
||||
command: uv python install 3.14
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/retry
|
||||
with:
|
||||
command: uv sync --locked --python 3.11 --extra dev --extra messaging
|
||||
command: uv sync --locked --python 3.14 --extra dev --extra messaging
|
||||
|
||||
- name: Run venv-holder live E2E
|
||||
shell: bash
|
||||
|
||||
@@ -50,7 +50,7 @@ Run this in PowerShell:
|
||||
iex (irm https://hermes-agent.nousresearch.com/install.ps1)
|
||||
```
|
||||
|
||||
The installer handles everything: uv, Python 3.11, Node.js, ripgrep, ffmpeg, **and a portable Git Bash** (MinGit, unpacked to `%LOCALAPPDATA%\hermes\git` — no admin required, completely isolated from any system Git install). Hermes uses this bundled Git Bash to run shell commands.
|
||||
The installer handles everything: uv, Python 3.14, Node.js, ripgrep, ffmpeg, **and a portable Git Bash** (MinGit, unpacked to `%LOCALAPPDATA%\hermes\git` — no admin required, completely isolated from any system Git install). Hermes uses this bundled Git Bash to run shell commands.
|
||||
|
||||
If you already have Git installed, the installer detects it and uses that instead. Otherwise a ~45MB MinGit download is all you need — it won't touch or interfere with any system Git.
|
||||
|
||||
@@ -239,7 +239,7 @@ against its own checkout, destroying the running runtime mid-session.
|
||||
|
||||
```bash
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
uv venv ~/.hermes/venvs/hermes-dev --python 3.11
|
||||
uv venv ~/.hermes/venvs/hermes-dev --python 3.14
|
||||
source ~/.hermes/venvs/hermes-dev/bin/activate
|
||||
uv pip install -e ".[all,dev]"
|
||||
scripts/run_tests.sh
|
||||
|
||||
@@ -2849,7 +2849,7 @@ def _show_terminal_section(config: Dict[str, Any]) -> None:
|
||||
print(f" Timeout: {terminal.get('timeout', 60)}s")
|
||||
|
||||
configured = lambda *names: 'configured' if all(get_env_value(n) for n in names) else '(not set)' # noqa: E731
|
||||
default_img = 'nikolaik/python-nodejs:python3.11-nodejs20'
|
||||
default_img = 'nikolaik/python-nodejs:python3.14-nodejs22'
|
||||
backend_lines = {
|
||||
'docker': lambda: [f" Docker image: {terminal.get('docker_image', default_img)}"],
|
||||
'singularity': lambda: [f" Image: {terminal.get('singularity_image', 'docker://' + default_img)}"],
|
||||
|
||||
@@ -301,15 +301,15 @@ DEFAULT_CONFIG = {
|
||||
# go first because n/nvm/asdf write PATH exports there without an interactivity guard. Turn
|
||||
# off if an rc file misbehaves when sourced non-interactively (exits on TTY check).
|
||||
"auto_source_bashrc": True,
|
||||
"docker_image": "nikolaik/python-nodejs:python3.11-nodejs20",
|
||||
"docker_image": "nikolaik/python-nodejs:python3.14-nodejs22",
|
||||
"docker_forward_env": [],
|
||||
# Exact key-value env pairs set inside Docker containers (unlike docker_forward_env, which
|
||||
# reads host values) — useful under systemd without the user's shell env. Example:
|
||||
# {"SSH_AUTH_SOCK": "/run/user/1000/ssh-agent.sock"}
|
||||
"docker_env": {},
|
||||
"singularity_image": "docker://nikolaik/python-nodejs:python3.11-nodejs20",
|
||||
"modal_image": "nikolaik/python-nodejs:python3.11-nodejs20",
|
||||
"daytona_image": "nikolaik/python-nodejs:python3.11-nodejs20",
|
||||
"singularity_image": "docker://nikolaik/python-nodejs:python3.14-nodejs22",
|
||||
"modal_image": "nikolaik/python-nodejs:python3.14-nodejs22",
|
||||
"daytona_image": "nikolaik/python-nodejs:python3.14-nodejs22",
|
||||
"vercel_runtime": "node24", # vercel_sandbox backend only: node24 | node22 | python3.13
|
||||
# Container limits (docker, singularity, modal, daytona, vercel_sandbox; not local/ssh).
|
||||
"container_cpu": 1,
|
||||
|
||||
@@ -530,14 +530,14 @@ def _install_safe_python_generation(
|
||||
return result
|
||||
|
||||
# All patches on the current minor line are vulnerable or rejected.
|
||||
# Fall forward to the next supported minor (e.g. 3.11 → 3.12) so the
|
||||
# user isn't stuck on every `hermes update` with no path to a fixed
|
||||
# runtime (issue #76106). The requires-python constraint
|
||||
# (>=3.11,<3.14) and the downstream import smoke-test gate
|
||||
# Fall forward to the next supported minor (e.g. 3.14 → 3.15 when the
|
||||
# ceiling rises) so the user isn't stuck on every `hermes update` with
|
||||
# no path to a fixed runtime (issue #76106). The requires-python
|
||||
# constraint (>=3.14,<3.15) and the downstream import smoke-test gate
|
||||
# compatibility; we only need to stay inside that window.
|
||||
cur_major, cur_minor = current.python_version[:2]
|
||||
fb_tried: set[tuple[int, int, int]] = set(tried_versions)
|
||||
for next_minor in range(cur_minor + 1, 14): # up to 3.13
|
||||
for next_minor in range(cur_minor + 1, 15): # up to 3.14 (<3.15 ceiling)
|
||||
next_request = f"{cur_major}.{next_minor}"
|
||||
print(
|
||||
f" → No fixed {cur_major}.{cur_minor} build available; "
|
||||
@@ -1182,5 +1182,5 @@ def repair_vulnerable_runtime(
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def rebuild_venv(uv_bin: str, venv_dir: Path, python_version: str = "3.11") -> bool:
|
||||
def rebuild_venv(uv_bin: str, venv_dir: Path, python_version: str = "3.14") -> bool:
|
||||
return True # dont remove me. ask ethernet
|
||||
|
||||
+15
-15
@@ -300,35 +300,35 @@
|
||||
"python": {
|
||||
"artifacts": {
|
||||
"darwin-arm64": {
|
||||
"sha256": "fcba9f3f676c83e07225e38116649f0c6eb94cb4fcc166632cf92769462b6e39",
|
||||
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.11.16+20260814-aarch64-apple-darwin-install_only.tar.gz"
|
||||
"sha256": "30daa970c7d223530120f1693cd3c6fa4c0c0d31ef158710b0dd77f286a5b23e",
|
||||
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260901/cpython-3.14.7+20260901-aarch64-apple-darwin-install_only.tar.gz"
|
||||
},
|
||||
"darwin-x64": {
|
||||
"sha256": "d9117d31251ba5c9a81ac7ad7c00dab1d5228e261eb0cda94550b4da1cc73bd1",
|
||||
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.11.16+20260814-x86_64-apple-darwin-install_only.tar.gz"
|
||||
"sha256": "dd8841a2e8ef94bd1a02b52f92843120942140f112145d4e0199abab56f120b1",
|
||||
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260901/cpython-3.14.7+20260901-x86_64-apple-darwin-install_only.tar.gz"
|
||||
},
|
||||
"linux-arm64": {
|
||||
"sha256": "9142c12dd3559eaac58a18d8905b99a293979d5e5a1b4fb5cf4cebbf82ef6f33",
|
||||
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.11.16+20260814-aarch64-unknown-linux-gnu-install_only.tar.gz"
|
||||
"sha256": "30f1cc489be654477d895b441e196bb080738bf0456da82080ad4ab66a22d80f",
|
||||
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260901/cpython-3.14.7+20260901-aarch64-unknown-linux-gnu-install_only.tar.gz"
|
||||
},
|
||||
"linux-arm64-bionic": {
|
||||
"sha256": "61a8df1dfee53de364757aa751faac033725262a4be04f086c3e3fedbe38991d",
|
||||
"url": "https://tur.kcubeterm.com/pool/tur/python3.11_3.11.16_aarch64.deb"
|
||||
"sha256": "3166e56c2b6c03fff41191fbb9d736302978e7c484702814d9f6dc99dd6006bd",
|
||||
"url": "https://packages.termux.dev/apt/termux-main/pool/main/p/python/python_3.14.6-1_aarch64.deb"
|
||||
},
|
||||
"linux-x64": {
|
||||
"sha256": "33994fad90145ba559ebbe8a18d69fa7e56653502f7ba14ba07199b52cde3775",
|
||||
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.11.16+20260814-x86_64-unknown-linux-gnu-install_only.tar.gz"
|
||||
"sha256": "0ab3305457051cd3e7c031857e005f1bda17c218a1990567dacaaac6dd1d14f0",
|
||||
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260901/cpython-3.14.7+20260901-x86_64-unknown-linux-gnu-install_only.tar.gz"
|
||||
},
|
||||
"win32-arm64": {
|
||||
"sha256": "450cbf91ff0dbfce7fa1d40ba19103187852076496b6153e528fa6dc43a88a58",
|
||||
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.11.16+20260814-aarch64-pc-windows-msvc-install_only.tar.gz"
|
||||
"sha256": "5efa2548bf1248ca07ed6f8afb0cb52b83d4869d533ea5be919a989c8ee1b17c",
|
||||
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260901/cpython-3.14.7+20260901-aarch64-pc-windows-msvc-install_only.tar.gz"
|
||||
},
|
||||
"win32-x64": {
|
||||
"sha256": "ffaee1e94c8488f833473e56e1c980ca1a58d91126d21ddf0f6ba052e69cf511",
|
||||
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.11.16+20260814-x86_64-pc-windows-msvc-install_only.tar.gz"
|
||||
"sha256": "5d9242012dded591d723a3a572dda265173ad58d8a3e6fdbc6dac8f94f36c80a",
|
||||
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260901/cpython-3.14.7+20260901-x86_64-pc-windows-msvc-install_only.tar.gz"
|
||||
}
|
||||
},
|
||||
"version": "3.11.16+20260814"
|
||||
"version": "3.14.7+20260901"
|
||||
},
|
||||
"ripgrep": {
|
||||
"artifacts": {
|
||||
|
||||
+16
-8
@@ -239,12 +239,20 @@ class Python(_BionicDebArm, BinaryPackage, DebPackage):
|
||||
probe_version = False
|
||||
binary_rel = {"win32": "python.exe", "posix": "bin/python3"}
|
||||
# The staged .deb's main binary: DebPackage.verify checks it.
|
||||
main_bin_rel = "bin/python3.11"
|
||||
main_bin_rel = "bin/python3.14"
|
||||
|
||||
def main_rel(self, target: str) -> str:
|
||||
return self.main_bin_rel
|
||||
|
||||
deb_package = "python3.11"
|
||||
# termux-main (official termux repo) python deb. It lags python-build-
|
||||
# standalone by one patch (3.14.6-1 vs 3.14.7), so the bionic row is a
|
||||
# manual pin -- never derived from the node version, and pm update leaves
|
||||
# it alone (no bionic resolver).
|
||||
deb_package = "python"
|
||||
_BIONIC_URL = (
|
||||
"https://packages.termux.dev/apt/termux-main/pool/main/p/python/"
|
||||
"python_3.14.6-1_aarch64.deb"
|
||||
)
|
||||
|
||||
def stage(self, store: Store, staged: Path, version: str, target: str) -> None:
|
||||
super().stage(store, staged, version, target)
|
||||
@@ -261,9 +269,8 @@ class Python(_BionicDebArm, BinaryPackage, DebPackage):
|
||||
|
||||
def fetch_url(self, version: str, target: str) -> str:
|
||||
if target == "linux-arm64-bionic":
|
||||
pyver = version.partition("+")[0]
|
||||
return f"https://tur.kcubeterm.com/pool/tur/python3.11_{pyver}_aarch64.deb"
|
||||
# lock version is "<python>+<release tag>", e.g. "3.11.13+202****0807"
|
||||
return self._BIONIC_URL
|
||||
# lock version is "<python>+<release tag>", e.g. "3.14.7+20260901"
|
||||
pyver, _, tag = version.partition("+")
|
||||
if not tag:
|
||||
raise InstallError(self.name, f"version {version!r} needs the +<release> tag")
|
||||
@@ -274,10 +281,11 @@ class Python(_BionicDebArm, BinaryPackage, DebPackage):
|
||||
)
|
||||
|
||||
def latest_versions(self, target: str, locked=None) -> list[str]:
|
||||
# Stay on the locked python minor line (3.11); bump only the
|
||||
# Stay on the locked python minor line (3.14); bump only the
|
||||
# +<build-tag>. A major/minor bump is a deliberate decision, never
|
||||
# an auto-update.
|
||||
if not locked or "+" not in locked:
|
||||
# an auto-update. The bionic row is a manual termux-main pin -- no
|
||||
# python-build-standalone build exists for it, so leave it locked.
|
||||
if target == "linux-arm64-bionic" or not locked or "+" not in locked:
|
||||
return []
|
||||
pyver = locked.partition("+")[0]
|
||||
minor = ".".join(pyver.split(".")[:2])
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ _VERSION_PART_RE = re.compile(r"\d+|[A-Za-z]+")
|
||||
|
||||
def version_key(version: str) -> tuple:
|
||||
"""A sortable key for a version string. Handles dot-separated numerics,
|
||||
+suffixes (python's 3.11.16+20260814, git's 2.53.0+3), and plain build
|
||||
+suffixes (python's 3.14.7+20260901, git's 2.53.0+3), and plain build
|
||||
numbers (llamacpp's 10362). Non-numeric segments sort after numerics so
|
||||
a prerelease never beats its release."""
|
||||
key = []
|
||||
|
||||
@@ -72,7 +72,7 @@ def make_maker(bin_dir, shebang_python, wrapper_text):
|
||||
|
||||
def mint_one(bin_dir, shebang_python, wrapper_text, spec):
|
||||
"""Mint one launcher exe; returns its absolute path. distlib also
|
||||
writes a python-versioned twin (hermes-3.11.exe) — the payload ships
|
||||
writes a python-versioned twin (hermes-3.14.exe) — the payload ships
|
||||
exactly one name per entry, so the twin is removed."""
|
||||
maker = make_maker(bin_dir, shebang_python, wrapper_text)
|
||||
filenames = maker.make(f"{spec['name']} = {spec['module']}:{spec['func']}")
|
||||
|
||||
@@ -115,7 +115,7 @@ try {
|
||||
Copy-Item (Join-Path $repoRoot 'hermes_constants.py') (Join-Path $installRoot 'hermes_constants.py')
|
||||
|
||||
$store = Join-Path $caseRoot 'store'
|
||||
$entryName = 'python-3.11.15+x20260807-win32-arm64'
|
||||
$entryName = 'python-3.14.7+x20260901-win32-arm64'
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $store $entryName) | Out-Null
|
||||
Copy-Item $python (Join-Path $store "$entryName\python.exe")
|
||||
('{"schema": 1, "packages": {"python": {"entry": "' + $entryName + '"}}}') |
|
||||
|
||||
@@ -24,7 +24,7 @@ export function generateIcons(args = [], { root = repoRoot, run = spawnSync, env
|
||||
delete childEnv.PYTHONPATH
|
||||
delete childEnv.PYTHONHOME
|
||||
const result = run('uv', [
|
||||
'run', '--isolated', '--locked', '--only-group', 'icon-build', '--python', '3.11',
|
||||
'run', '--isolated', '--locked', '--only-group', 'icon-build', '--python', '3.14',
|
||||
// PM copies its wheel cache into payloads. Keep build wheels outside it.
|
||||
'--cache-dir', path.join(root, '.cache', 'icon-build'),
|
||||
'python', path.join(root, 'scripts', 'generate_icons.py'), ...args
|
||||
|
||||
+1
-1
@@ -505,7 +505,7 @@ function Invoke-BootstrapPm {
|
||||
$uv = Get-Uv
|
||||
$lock = Get-Content (Join-Path $InstallDir "pm\lock.json") -Raw | ConvertFrom-Json
|
||||
$pyPin = $lock.packages.python
|
||||
$pyVersion = if ($pyPin) { ($pyPin.version -split '\+')[0] -replace '^(\d+\.\d+).*', '$1' } else { '3.11' }
|
||||
$pyVersion = if ($pyPin) { ($pyPin.version -split '\+')[0] -replace '^(\d+\.\d+).*', '$1' } else { '3.14' }
|
||||
Log "delegating python + venv + tools to pm (hash-verified via uv.lock)"
|
||||
Push-Location $InstallDir
|
||||
try {
|
||||
|
||||
+1
-1
@@ -289,7 +289,7 @@ bootstrap_pm() {
|
||||
_py="$(awk '/^ "python": \{/ { in_py = 1 }
|
||||
in_py && /^ "version":/ { gsub(/.*: "|"$|",$/, ""); print; exit }' \
|
||||
"$INSTALL_DIR/pm/lock.json" | cut -d+ -f1 | cut -d. -f1,2)"
|
||||
[ -n "$_py" ] || _py="3.11"
|
||||
[ -n "$_py" ] || _py="3.14"
|
||||
log "delegating python + venv + tools to pm (hash-verified via uv.lock)"
|
||||
(cd "$INSTALL_DIR" && "$UV_CMD" run --no-project --python "$_py" python -m pm.cli install) \
|
||||
|| fail "pm install failed"
|
||||
|
||||
@@ -14,7 +14,7 @@ PYTHON_ENTRY=$(node -e "
|
||||
" "$PWD")
|
||||
case "$(uname -s)" in
|
||||
MINGW*|MSYS*|CYGWIN*) PY="$PWD/tools/$PYTHON_ENTRY/python.exe"; SP="$PWD/venv/Lib/site-packages" ;;
|
||||
*) PY="$PWD/tools/$PYTHON_ENTRY/bin/python3"; SP="$PWD/venv/lib/python3.11/site-packages" ;;
|
||||
*) PY="$PWD/tools/$PYTHON_ENTRY/bin/python3"; SP="$PWD/venv/lib/python3.14/site-packages" ;;
|
||||
esac
|
||||
|
||||
[ -f "$PY" ] || { echo "FAIL: no store interpreter at $PY"; exit 1; }
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
PLATFORM_TAG="android_24_arm64_v8a"
|
||||
|
||||
# ABI tag of the bundled interpreter, derived from the pm python version
|
||||
# (cp311 for the 3.11.x line the lock pins). Kept beside the platform tag
|
||||
# (cp314 for the 3.14.x line the lock pins). Kept beside the platform tag
|
||||
# because index.json's pythonAbi field must agree with it.
|
||||
PYTHON_ABI="cp311"
|
||||
PYTHON_ABI="cp314"
|
||||
|
||||
# Toolchain pins for the psutil patched-local build path (--no-build-
|
||||
# isolation). Pure-python installs only: maturin is deliberately absent --
|
||||
|
||||
@@ -70,7 +70,7 @@ COMMIT="$(git -C "$REPO_ABS" rev-parse --verify "refs/tags/$TAG^{commit}")" \
|
||||
for d in python node uv npm ffmpeg ripgrep runtime-libs app wheelhouse; do
|
||||
[ -d "$PAYLOAD_ABS/$d" ] || fail "payload missing $d/ -- run termux_build.sh + build_cpython.sh + build_node.sh first"
|
||||
done
|
||||
PYBIN_REL="data/data/com.termux/files/usr/bin/python3.11"
|
||||
PYBIN_REL="data/data/com.termux/files/usr/bin/python3.14"
|
||||
[ -f "$PAYLOAD_ABS/python/$PYBIN_REL" ] || fail "payload python tree lacks $PYBIN_REL"
|
||||
NODEBIN_REL="data/data/com.termux/files/usr/bin/node"
|
||||
[ -f "$PAYLOAD_ABS/node/$NODEBIN_REL" ] || fail "payload node tree lacks $NODEBIN_REL"
|
||||
@@ -130,7 +130,7 @@ docker run --rm --platform linux/arm64 \
|
||||
# The staged tree is mounted at its REAL $PREFIX path so the venv
|
||||
# recorded absolute paths are correct on-device from birth.
|
||||
mkdir -p "$PREFIX" 2>/dev/null || true
|
||||
PY="$PREFIX/lib/hermes-agent/tools/python$PREFIX/bin/python3.11"
|
||||
PY="$PREFIX/lib/hermes-agent/tools/python$PREFIX/bin/python3.14"
|
||||
UV="$PREFIX/lib/hermes-agent/tools/uv$PREFIX/bin/uv"
|
||||
# Desktop payload canon: the venv holds the DEPENDENCY tree only;
|
||||
# the app runs from its own directory via PYTHONPATH (the wheel
|
||||
|
||||
@@ -218,15 +218,18 @@ def build_wheels(build_set: list[str], specs: dict[str, str], wheelhouse: Path)
|
||||
|
||||
TARGET_ENV = {
|
||||
"implementation_name": "cpython",
|
||||
"implementation_version": "3.11.15",
|
||||
"implementation_version": "3.14.6",
|
||||
"os_name": "posix",
|
||||
"platform_machine": "aarch64",
|
||||
"platform_release": "",
|
||||
"platform_system": "Linux",
|
||||
"platform_version": "",
|
||||
"python_full_version": "3.11.15",
|
||||
"python_version": "3.11",
|
||||
"sys_platform": "linux",
|
||||
"python_full_version": "3.14.6",
|
||||
"python_version": "3.14",
|
||||
# 3.13+ Android CPython reports sys.platform "android" (docs: changed in
|
||||
# 3.13), so markers keying on `sys_platform == 'linux'` no longer admit
|
||||
# the termux target; `platform_system` stays "Linux" (Android kernel).
|
||||
"sys_platform": "android",
|
||||
}
|
||||
|
||||
# Mirrors the documented misses in termux_build.sh's probe (single
|
||||
|
||||
@@ -5,7 +5,7 @@ The sealed termux deb is self-contained by contract: the device's termux
|
||||
tree may have NONE of the payload interpreters' runtime libs installed
|
||||
(first real-device install: `import ctypes` dlopened libffi.so and died).
|
||||
The pin table (runtime_libs.json) is derived from the suppliers' own
|
||||
dependency metadata -- the TUR python3.11 .deb's Depends line, uv's zstd,
|
||||
dependency metadata -- the termux-main python .deb's Depends line, uv's zstd,
|
||||
nodejs's libc++/c-ares/libicu -- not from whichever lib happens to error
|
||||
first.
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ if [ "${1:-}" = "--in-container" ]; then
|
||||
# interpreter the phone will run.
|
||||
PAYLOAD_ROOT="${5:-}"
|
||||
export PREFIX=/data/data/com.termux/files/usr
|
||||
STAGED_PY="$PAYLOAD_ROOT/python$PREFIX/bin/python3.11"
|
||||
STAGED_PY="$PAYLOAD_ROOT/python$PREFIX/bin/python3.14"
|
||||
STAGED_UV="$PAYLOAD_ROOT/uv$PREFIX/bin/uv"
|
||||
# The staged binaries' RUNPATHs point at the phone's $PREFIX layout
|
||||
# (linkerconfig on-device). Inside the container the tree lives at
|
||||
@@ -88,7 +88,7 @@ if [ "${1:-}" = "--in-container" ]; then
|
||||
export UV_CONCURRENT_BUILDS=1
|
||||
# Native extension links need the STAGED payload's libpython: the
|
||||
# container's own $PREFIX/lib (bootstrap only) is on the default
|
||||
# -L path, but libpython3.11.so lives in the staged tree. setuptools
|
||||
# -L path, but libpython3.14.so lives in the staged tree. setuptools
|
||||
# honors LDFLAGS, so every sdist build's link step finds it.
|
||||
STAGED_PYLIB="$PAYLOAD_ROOT/python$PREFIX/lib"
|
||||
export LDFLAGS="-L$STAGED_PYLIB ${LDFLAGS:-}"
|
||||
@@ -259,20 +259,22 @@ import json, re, sys, urllib.request
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
# The TARGET environment the wheelhouse must satisfy: Termux's bionic
|
||||
# python. TUR 3.11 reports sys.platform "linux" (the android value only
|
||||
# arrived in 3.13), so markers keying on linux admit it -- and windows/
|
||||
# darwin markers exclude it, which is the whole point.
|
||||
# python. termux-main 3.14 reports sys.platform "android" (the linux value
|
||||
# applied to 3.11/3.12; 3.13 changed it), so markers keying on
|
||||
# `sys_platform == 'linux'` no longer admit the termux target -- and
|
||||
# `platform_system` stays "Linux" (Android kernel), admitting
|
||||
# platform_system-gated deps. windows/darwin markers exclude it as before.
|
||||
TARGET_ENV = {
|
||||
"implementation_name": "cpython",
|
||||
"implementation_version": "3.11.15",
|
||||
"implementation_version": "3.14.6",
|
||||
"os_name": "posix",
|
||||
"platform_machine": "aarch64",
|
||||
"platform_release": "",
|
||||
"platform_system": "Linux",
|
||||
"platform_version": "",
|
||||
"python_full_version": "3.11.15",
|
||||
"python_version": "3.11",
|
||||
"sys_platform": "linux",
|
||||
"python_full_version": "3.14.6",
|
||||
"python_version": "3.14",
|
||||
"sys_platform": "android",
|
||||
}
|
||||
|
||||
def locked_version(spec: str) -> str | None:
|
||||
@@ -358,7 +360,7 @@ fi
|
||||
# interpreter by construction. The payload must be staged before this.
|
||||
log "Building the wheelhouse inside the pinned container (payload ABI)"
|
||||
PAYLOAD_ABS="$OUT_ABS"
|
||||
[ -f "$PAYLOAD_ABS/python/data/data/com.termux/files/usr/bin/python3.11" ] \
|
||||
[ -f "$PAYLOAD_ABS/python/data/data/com.termux/files/usr/bin/python3.14" ] \
|
||||
|| fail "staged payload python missing -- run build_cpython.sh first (the wheelhouse builds with the payload interpreter)"
|
||||
# The container mounts OUT_ABS at /out; translate the host-side work
|
||||
# paths before crossing the boundary (host absolutes do not exist inside).
|
||||
|
||||
@@ -681,15 +681,15 @@ class TestMinorLineFallForward:
|
||||
def test_returns_none_with_bounded_attempts_when_all_minors_exhausted(
|
||||
self, tmp_path, monkeypatch
|
||||
):
|
||||
"""When every build on every supported minor line (3.11-3.13) is
|
||||
"""When every build on every supported minor line (3.11-3.14) is
|
||||
vulnerable, the provisioner must give up with None -- and the total
|
||||
install workload must stay bounded by _MAX_PATCH_RETRIES per line."""
|
||||
import hermes_cli.runtime_repair as runtime_repair
|
||||
|
||||
install_calls = []
|
||||
resolutions = {"3.11": (3, 11, 14), "3.12": (3, 12, 30), "3.13": (3, 13, 30)}
|
||||
resolutions = {"3.11": (3, 11, 14), "3.12": (3, 12, 30), "3.13": (3, 13, 30), "3.14": (3, 14, 30)}
|
||||
patch_lists = {}
|
||||
for minor in (11, 12, 13):
|
||||
for minor in (11, 12, 13, 14):
|
||||
versions = [(3, minor, v) for v in range(30, 10, -1)] # 20 patches
|
||||
patch_lists[f"3.{minor}"] = versions
|
||||
for version in versions:
|
||||
@@ -713,13 +713,14 @@ class TestMinorLineFallForward:
|
||||
|
||||
cap = runtime_repair._MAX_PATCH_RETRIES
|
||||
# Per line: one bare request + at most _MAX_PATCH_RETRIES explicit
|
||||
# patches; three lines total (3.11, 3.12, 3.13) and nothing beyond
|
||||
# 3.13 (requires-python is <3.14).
|
||||
# patches; four lines total (3.11, 3.12, 3.13, 3.14) and nothing beyond
|
||||
# 3.14 (requires-python is <3.15).
|
||||
assert install_calls.count("3.11") == 1
|
||||
assert install_calls.count("3.12") == 1
|
||||
assert install_calls.count("3.13") == 1
|
||||
assert not any(call.startswith("3.14") for call in install_calls)
|
||||
for minor in (11, 12, 13):
|
||||
assert install_calls.count("3.14") == 1
|
||||
assert not any(call.startswith("3.15") for call in install_calls)
|
||||
for minor in (11, 12, 13, 14):
|
||||
explicit = [
|
||||
call for call in install_calls
|
||||
if call.startswith(f"3.{minor}.")
|
||||
@@ -727,7 +728,7 @@ class TestMinorLineFallForward:
|
||||
assert len(explicit) <= cap, (
|
||||
f"3.{minor} explicit retries must be capped at {cap}: {explicit}"
|
||||
)
|
||||
assert len(install_calls) <= 3 * (1 + cap)
|
||||
assert len(install_calls) <= 4 * (1 + cap)
|
||||
|
||||
|
||||
class TestListAvailablePatches:
|
||||
|
||||
@@ -53,7 +53,7 @@ def _fake_repo(tmp_path: Path, monkeypatch) -> Path:
|
||||
"""A fake repo root with a synced venv, substituted for pm.paths.repo_root."""
|
||||
repo = tmp_path / "repo"
|
||||
win = current_target().startswith("win32")
|
||||
site = repo / "venv" / ("Lib" if win else "lib/python3.11") / "site-packages"
|
||||
site = repo / "venv" / ("Lib" if win else "lib/python3.14") / "site-packages"
|
||||
site.mkdir(parents=True)
|
||||
monkeypatch.setattr(paths, "repo_root", lambda: repo)
|
||||
return repo
|
||||
@@ -63,7 +63,7 @@ def _develop_env(tmp_path, monkeypatch, *, with_python=True):
|
||||
_fake_store(tmp_path, monkeypatch, with_python=with_python)
|
||||
repo = _fake_repo(tmp_path, monkeypatch)
|
||||
win = current_target().startswith("win32")
|
||||
site = repo / "venv" / ("Lib" if win else "lib/python3.11") / "site-packages"
|
||||
site = repo / "venv" / ("Lib" if win else "lib/python3.14") / "site-packages"
|
||||
return pm_cli._develop_env(["faketool"]), repo, site
|
||||
|
||||
|
||||
|
||||
@@ -490,12 +490,12 @@ def test_python_package_url_carries_release_tag():
|
||||
from pm.registry import get_package
|
||||
|
||||
python = get_package("python")
|
||||
url = python.fetch_url("3.11.16+20260814", "win32-arm64")
|
||||
assert "download/20260814/" in url
|
||||
assert "cpython-3.11.16+20260814-aarch64-pc-windows-msvc-install_only" in url
|
||||
url = python.fetch_url("3.14.7+20260901", "win32-arm64")
|
||||
assert "download/20260901/" in url
|
||||
assert "cpython-3.14.7+20260901-aarch64-pc-windows-msvc-install_only" in url
|
||||
|
||||
try:
|
||||
python.fetch_url("3.11.16", "win32-arm64")
|
||||
python.fetch_url("3.14.7", "win32-arm64")
|
||||
raise AssertionError("bare version must be rejected")
|
||||
except PmInstallError:
|
||||
pass
|
||||
@@ -742,7 +742,7 @@ def test_python_stage_drops_unloadable_x64_vc_runtime_on_arm64(monkeypatch, tmp_
|
||||
(staged / "vcruntime140.dll").write_bytes(b"arm64")
|
||||
|
||||
monkeypatch.setattr(packages, "_macos_sign_managed_python", lambda p: False)
|
||||
get_package("python").stage(None, staged, "3.11.16", "win32-arm64")
|
||||
get_package("python").stage(None, staged, "3.14.7", "win32-arm64")
|
||||
|
||||
assert not (staged / "vcruntime140_1.dll").exists()
|
||||
assert (staged / "vcruntime140.dll").is_file()
|
||||
@@ -757,7 +757,7 @@ def test_python_stage_keeps_vc_runtimes_on_other_targets(monkeypatch, tmp_path):
|
||||
(staged / "vcruntime140_1.dll").write_bytes(b"x64")
|
||||
|
||||
monkeypatch.setattr(packages, "_macos_sign_managed_python", lambda p: False)
|
||||
get_package("python").stage(None, staged, "3.11.16", "win32-x64")
|
||||
get_package("python").stage(None, staged, "3.14.7", "win32-x64")
|
||||
|
||||
assert (staged / "vcruntime140_1.dll").is_file()
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ def _pkg(pkg_name="node", version_style="semver", **latest):
|
||||
|
||||
def test_version_key_sorts_numeric_and_suffixes():
|
||||
assert version_key("2.53.0+5") > version_key("2.53.0+3")
|
||||
assert version_key("3.11.16+20260814") > version_key("3.11.16+20260801")
|
||||
assert version_key("3.14.7+20260901") > version_key("3.14.7+20260900")
|
||||
assert version_key("26.8.1") > version_key("26.7.0")
|
||||
assert version_key("10362") > version_key("10361")
|
||||
# prerelease-ish segments sort after numerics
|
||||
@@ -46,7 +46,7 @@ def test_version_key_sorts_numeric_and_suffixes():
|
||||
|
||||
def test_minor_of():
|
||||
assert minor_of("26.7.0") == (26, 7)
|
||||
assert minor_of("3.11.16+20260814") == (3, 11)
|
||||
assert minor_of("3.14.7+20260901") == (3, 14)
|
||||
assert minor_of("10362") is None # single component
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ We value contributions in this order:
|
||||
| Requirement | Notes |
|
||||
| -------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| **Git** | With the `git-lfs` extension installed |
|
||||
| **Python 3.11–3.13** | uv will install it if missing |
|
||||
| **Python 3.14** | uv will install it if missing |
|
||||
| **uv** | Fast Python package manager ([install](https://docs.astral.sh/uv/)) |
|
||||
| **Node.js 26+** | Optional — needed for browser tools and WhatsApp bridge (matches root `package.json` engines) |
|
||||
|
||||
@@ -92,8 +92,8 @@ tree means no relative path from the workspace resolves to it.
|
||||
git clone https://github.com/NousResearch/hermes-agent.git
|
||||
cd hermes-agent
|
||||
|
||||
# Create venv with Python 3.11, OUTSIDE the source tree
|
||||
uv venv ~/.hermes/venvs/hermes-dev --python 3.11
|
||||
# Create venv with Python 3.14, OUTSIDE the source tree
|
||||
uv venv ~/.hermes/venvs/hermes-dev --python 3.14
|
||||
export VIRTUAL_ENV="$HOME/.hermes/venvs/hermes-dev"
|
||||
export PATH="$VIRTUAL_ENV/bin:$PATH"
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ You don't need to rebuild your setup from scratch. Restore a full backup with `h
|
||||
**Installer:** On non-Windows platforms, the only prerequisite is **Git**. On Linux, also make sure `curl` and `xz-utils` are available (the installer downloads Node.js as a `.tar.xz` archive). The desktop app additionally requires `g++` (or `build-essential` on Debian/Ubuntu) to compile native modules. The installer automatically handles everything else:
|
||||
|
||||
- **uv** (fast Python package manager)
|
||||
- **Python 3.11** (via uv, no sudo needed)
|
||||
- **Python 3.14** (via uv, no sudo needed)
|
||||
- **Node.js v26** (for browser automation and WhatsApp bridge; existing system Node 22.22+, 24.11+, or 26+ is used as-is)
|
||||
- **ripgrep** (fast file search)
|
||||
- **ffmpeg** (audio format conversion for TTS)
|
||||
|
||||
@@ -146,7 +146,7 @@ The installer adds `~/.local/bin` to your PATH. If you use a non-standard shell
|
||||
|
||||
#### Python version too old
|
||||
|
||||
**Cause:** Hermes requires Python 3.11 or newer.
|
||||
**Cause:** Hermes requires Python 3.14 or newer.
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
|
||||
@@ -126,8 +126,7 @@ wake_word:
|
||||
confirmation_frames: 3 # openWakeWord only — consecutive over-threshold frames required to fire
|
||||
start_new_session: true # start a fresh session on wake vs. continue the current one
|
||||
openwakeword:
|
||||
model: hey_hermes # bundled default; OR a built-in name OR a path to a custom .onnx/.tflite
|
||||
inference_framework: "" # "" (auto) | "onnx" | "tflite"
|
||||
model: hey_hermes # bundled default; OR a built-in name OR a path to a custom .tflite
|
||||
porcupine:
|
||||
keyword: jarvis # built-in keyword OR path to a custom .ppn
|
||||
```
|
||||
@@ -165,13 +164,12 @@ The `sherpa` and `porcupine` engines decode the whole phrase internally, so they
|
||||
don't have the single-frame-spike problem and ignore `confirmation_frames`
|
||||
(but they still honor `sensitivity`).
|
||||
|
||||
`inference_framework` picks the openWakeWord backend. Leave it empty (the
|
||||
default) to let Hermes choose per platform: **tflite on Apple Silicon**, onnx
|
||||
everywhere else. openWakeWord's onnx backend returns near-zero scores on macOS
|
||||
ARM64 ([openWakeWord#336](https://github.com/dscripka/openWakeWord/issues/336)),
|
||||
so a listener pinned to `onnx` there will arm, show as listening, and never
|
||||
fire. The tflite backend needs `ai-edge-litert` on macOS, which Hermes installs
|
||||
on demand alongside the other wake-word deps.
|
||||
The `openwakeword` engine is [pyopen-wakeword](https://github.com/rhasspy/pyopen-wakeword)
|
||||
(rhasspy's maintained fork of openWakeWord): it runs TFLite via a library
|
||||
bundled in its wheel and ships the same shared feature models openWakeWord
|
||||
downloaded at runtime (byte-identical, verified by hash), so the shipped
|
||||
`hey_hermes.tflite` scores exactly as before — with no runtime download and no
|
||||
backend to pick. There is no `inference_framework` setting anymore.
|
||||
|
||||
### Surfaces (CLI, TUI, GUI)
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ Each dep has a `shutil.which(...)`-style check; if a binary is missing and the r
|
||||
Top-to-bottom, in order:
|
||||
|
||||
1. **Bootstraps `uv`** — Astral's fast Python manager. Installed to `%USERPROFILE%\.local\bin`.
|
||||
2. **Installs Python 3.11** via `uv`. No existing Python needed.
|
||||
2. **Installs Python 3.14** via `uv`. No existing Python needed.
|
||||
3. **Installs Node.js 26** (winget if available, else a portable Node tarball unpacked under `%LOCALAPPDATA%\hermes\node`). Used for the browser tool and the WhatsApp bridge.
|
||||
4. **Installs portable Git** — if `git` is already on PATH the installer uses it; otherwise it downloads a trimmed, self-contained **PortableGit** (~45 MB, from the official `git-for-windows` release) to `%LOCALAPPDATA%\hermes\git`. No admin, no Windows installer registry, no interference with anything else on the box.
|
||||
5. **Clones the repo** to `%LOCALAPPDATA%\hermes\hermes-agent` and creates a virtualenv inside it.
|
||||
|
||||
Reference in New Issue
Block a user