Merge 27df3b8847 brought back the hermes-agent[hindsight] extra
(hindsight-client==0.6.1) that 73c598e319 removed. The catalog
Hindsight plugin now requires hindsight-client>=0.10.1,<1, so any
workspace containing it fails `uv lock`. Remove the extra, its
exclude-newer entry and its legacy-takeover mapping, and regenerate
uv.lock.
The workspace-member rename from the original PR is dropped here;
#122098 landed that half.
Salvaged from #122092.
KittenTTS 0.8.1 requires misaki[en]>=0.9.4. PyPI's misaki 0.9.4 caps
Python below 3.13. NousResearch/misaki f03fd2be73 is upstream main with
the cap raised to <3.15 and no code change, so the extra declares
misaki[en] at that commit and uv resolves KittenTTS's requirement to it.
misaki[en] also lists spacy-curated-transformers. The newest release
that fits spacy 3.8, 0.3.1, caps Python below 3.14, so PM's `uv pip
check` rejected every 3.14 venv that carried it. Nothing imports it:
only transformer spaCy models use it, and KittenTTS never builds a
misaki G2P. A never-true override marker removes it from the lock.
torch, transformers, spaCy and num2words stay: misaki.en imports them
at module level and KittenTTS imports misaki.en.
Native bundles sync with --all-extras, so un-gating the extra would put
KittenTTS, torch and spaCy in every payload. [tool.hermes] opt-in-extras
names the extras that only an explicit selection installs. PM adds
--no-extra for each of them to an all-extras sync, so bundles and their
recorded feature list leave kittentts out, and setup still installs it
through sync_venv when the user picks it.
The extra is gated on platform instead of Python: onnxruntime has no
Intel macOS wheel and torch has no Windows ARM64 wheel. Nix gets the
hatchling build backend the misaki git source needs.
Verified on macOS arm64 with CPython 3.14.7 and uv 0.12.3:
uv sync --frozen --extra kittentts from this lock, then uv pip check
reports all 126 packages compatible. _generate_kittentts writes a
3.87 s 24 kHz WAV (RMS 3661), and no spaCy model is downloaded. A dry-run
all-extras sync with --no-extra kittentts selects none of kittentts,
misaki, torch, transformers or spaCy. The new build test fails without
the environment change and passes with it.
This reverts commit 694fe220a4.
misaki[en] also requires spacy-curated-transformers. With spacy 3.8
(thinc 8.3) only its 0.3.x line resolves, and 0.3.1 declares
requires-python <3.14. uv's lock ignores that upper bound, but PM's
dependency validation rejects it, so the win32-x64 bundle failed with
"spacy-curated-transformers requires Python >=3.9, <3.14". Restore the
<3.13 gate until misaki's English stack installs cleanly on 3.14.
KittenTTS 0.8.1 requires misaki[en]>=0.9.4, and PyPI's misaki 0.9.4
declares requires-python <3.13, so the extra was gated off the managed
3.14 interpreter. NousResearch/misaki f03fd2be73 is upstream main
(0.9.4 + "Enable Python 3.13") with the cap raised to <3.15 and no code
change. The extra now declares misaki[en] at that commit directly, so
uv resolves KittenTTS's transitive requirement to the fork. A
[tool.uv.sources] entry would not reach a transitive dependency, and
an override would bypass pip installs of the extra.
The extra is gated on platform instead of Python: onnxruntime has no
Intel macOS wheel and torch (pulled by misaki[en]) has no Windows ARM64
wheel, the same gate piper already carries.
Nix: uv.lock records no build backend for the git source, so
buildSystemOverrides supplies hatchling for misaki. Without it the
opt-in build fails with "No module named 'hatchling'". The default
package derivation is unchanged; kittentts is in no Nix bundle.
Verified on macOS arm64 with CPython 3.14.7: uv sync --frozen --extra
kittentts from this lock installs misaki from the fork commit, and
tools.tts_tool_local._generate_kittentts writes a 3.87 s 24 kHz WAV.
Pin ruamel.yaml before the release that requires ruamel.yaml.clib on
Python 3.14. Windows ARM64 has no clib wheel, and source builds fail in
CI's long temporary paths. Refresh both application and PM locks and
keep wheelhouse tests aligned with the locked pure-Python runtime.
The committed version is a placeholder now; a build stamps the real one.
Dev installs report their distance from the highest reachable release tag,
so an -rc claim sitting on the same commit never becomes the version.
Branch semantics kept where main and PM disagree: update_cmd_deps.py,
constraints-termux.txt, the Electron update-api-check module and the
post-swap hand-off test stay deleted; the pending-fleet-restart catch-up
and the local_runtime tag/download ladder stay retired (PM owns engines).
Ported from main onto the branch's shape: profile_scoped_chore for the
auto-archive and plugin-update housekeeping chores, the local-runtime
cross-process boot lock and residency cap, the checkpoint tmp_pack sweep,
the cua daemon-liveness status probe, the remote-served Desktop update
flag (posix.sh / windows.ps1), sign-in for env-pinned remote gateways
(urlDisabled on RemoteSetupFields), the uvloop extra split (uvicorn
without [standard]), and the umask-scoping spawn test.
uv.lock regenerated with pm.build_env --lock-only; new utf-8 reads from
main switched to utf-8-sig (check-windows-footguns).
Follow-up to the cherry-picked #116014:
- Pin per the dependency policy (pre-1.0: `<0.(minor+2)`): httptools
`>=0.6.3,<0.9` (floor = uvicorn[standard]'s own floor), uvloop
`>=0.15.1,<0.24`. `watchfiles>=0.20,<2` already complied.
- Copy uvicorn's own uvloop marker (win32, cygwin, PyPy) plus
`sys_platform != 'android'` so `pip install '.[all]'` on those
hosts does not fail on the extra either.
- `tools/lazy_deps.py` mirrors the `web` extra for the lazy dashboard
install: it also requested `uvicorn[standard]`, so a Termux user
opening the dashboard would have hit the same uvloop build at first
use. The web_server install hint follows.
- `uv lock` regenerated; the lock delta is exactly the pyproject delta.
- Two invariant tests: no Termux-reachable extra (or core, or the lazy
dashboard feature) requests uvloop; `[all]` still does, off Android.
- Docs: troubleshooting entry in the Termux guide.
Every native leg of the bundled release died at "Prepare the complete desktop
build" with the same validation failure:
The package `sherpa-onnx` requires `sherpa-onnx-core==1.13.8`, but it's not installed
`pm/environment.py::check` runs `uv pip check` after the payload venv is built,
and `pm/operations.py::build_environment` builds that venv with
`uv sync --frozen`. The lock is therefore authoritative, and the lock carried no
`sherpa-onnx-core` edge and no core package block.
uv resolves one distribution per version and reads the dependency graph from
that distribution's metadata. For sherpa-onnx 1.13.8 it selects the
cp311-linux_armv7l wheel (`uv lock -v` prints `Selecting: sherpa-onnx==1.13.8
[compatible] (sherpa_onnx-1.13.8-cp311-cp311-linux_armv7l.whl)`), and that wheel
is the one artifact of the release that declares no dependencies. Every wheel
the bundles install declares `Requires-Dist: sherpa-onnx-core==1.13.8`. The
sdist declares nothing either.
A lock regen cannot repair this, because the same metadata source is selected
again: `0dab3f5e3f` regenerated the lock for the widened floor, dropped the core
edge, and a fresh `uv lock` drops it again. Pin the core beside every
sherpa-onnx pin instead. Its wheels are platform-tagged and `py3-none`, so one
pin covers every target.
Verified with uv 0.12.3 on CPython 3.14.7 against the real project lock:
before (dbe4bfbc06): uv sync --frozen --extra wake --extra wake-sherpa
uv pip check -> Found 1 incompatibility (message above)
after: uv sync --frozen --all-extras
uv pip check -> All installed packages are compatible
(257 packages, sherpa_onnx_core present)
The lock has to cover the runtime, not the install bridge: with the floor at
>=3.11 the lock would otherwise resolve every supported version, where extras
that only ever coexist on 3.14 (kittentts vs neutts) are unsatisfiable -- uv
says as much ("Consider limiting your project's supported Python versions using
`requires-python`"). [tool.uv] environments now declares 3.14, which keeps the
lock satisfiable and still leaves the pip interface free to resolve ad hoc for a
bridge interpreter on 3.11 (verified: the same command still exits 0 there).
The diff is larger than the markers alone. It drops `sherpa-onnx-core`, which
the committed lock listed as an unconditional dependency of the pinned
sherpa-onnx 1.13.8 while also carrying wheels for interpreters other than the
3.14 floor -- i.e. that lock still held resolution the 3.14 move had left
behind. `uv lock --check` passes on the result, but the churn is worth a human
eye rather than being taken as mechanical.
pyproject.toml declares `google-cloud-pubsub` in [tool.uv.exclude-newer-package]
(the quarantined ==2.39.0 pin), but uv.lock's [options.exclude-newer-package]
block never picked the entry up.
uv >= 0.12 treats an exemption pyproject declares and the lock does not record
as lockfile drift, so `uv sync --locked` rejects the committed lock:
$ ~/.hermes/bin/uv lock --check # uv 0.12.9, the version the installer drops in $HERMES_HOME/bin
error: The lockfile at `uv.lock` needs to be updated, but `--check` was provided.
$ /tmp/uv-0.9.28/uv lock --check # the version the uv.lock CI check pins
rc=0
That makes the SQLite runtime repair (managed_uv._stage_candidate_venv, which
builds the replacement venv with `uv sync --extra all --locked`) fail on every
affected install: `hermes update` ends at "partially complete — SQLite … still
has the WAL-reset corruption bug" and never repairs the runtime. CI is blind to
it because every workflow pins uv 0.9.28.
Regenerated with uv 0.12.9; the diff is metadata only (the missing exemption
plus the block's key ordering) — no package version changes, and the
regenerated lock still passes `uv lock --check` under 0.9.28.
The origin/main merge took upstream's uv.lock (requires-python >=3.11,<3.14)
while pyproject.toml kept ours (>=3.14,<3.15), breaking the pyproject
lockstep: nix develop's requires-python assertion failed and fork CI's
icon-environment sync refused 3.14.7 against the 3.13 lock.
Re-locked from our own ==3.14.* lock as base so the 3.14 solution is
preserved and only upstream's additions merge in (pillow-heif v1.6.0,
hermes-agent 0.21.3); requires-python is ==3.14.* again, 270 packages.
Rollup patch tag so Hermes Cloud agents (which deploy the newest v* release tag)
pick up #110061: remote dashboard sessions no longer expire on refresh bursts.
Full curated notes for the window ship with v0.22.0.
Hosted/Docker images lock /opt/hermes/.venv, so --install-deps writing
site-packages fails with Permission denied and the adapter never starts.
Route Google Chat through lazy_deps (HERMES_LAZY_INSTALL_TARGET) and bake
the extra into the published image so a configured gateway can connect.
slack-sdk 3.44.1 contains the upstream fix for the aiohttp SocketModeClient
zombie retry loop (slackapi/python-slack-sdk#1956, closing #1913): connect()
used 'while True:' and never checked self.closed, so once close() closed the
shared aiohttp ClientSession, any connect/reconnect task in flight spun
forever logging 'Failed to connect (error: Session is closed); Retrying...'
every ping_interval.
Observed in production on this repo's own Slack adapter: the gateway's
socket watchdog (plugins/platforms/slack/adapter.py) heals wedged sockets by
rebuilding the AsyncSocketModeHandler, but the orphaned connect() task from
the pre-heal client kept retrying against the dead session indefinitely —
22k+ error lines per process per day while Slack itself remained connected.
The adapter's teardown docstring already references slackapi#1913.
3.44.1 adds the self.closed exit; slack-bolt 1.30.0 declares
slack_sdk>=3.38.0,<4, so the bump is compatible.
tornado 6.5.7 is affected by GHSA-5w76-955r-9v8r (CVSS 8.7): parse_multipart_form_data
splits the body unbounded before the max_parts check, so a request with a very large
number of parts can exhaust memory. 6.5.8 caps the split at max_parts+1 so the flooding
part is never materialized.
uv lock --upgrade-package tornado on current main; only the tornado block changes
(13 insertions / 13 deletions in uv.lock), no other package or marker moves.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QghbdVnZSkJbRRDxCSs2zr
uv refuses --locked/--check syncs when pyproject exclusion options differ from
the lockfile options block. Regenerated lock is metadata-only: the
[options.exclude-newer-package] table plus marker refinements; zero resolved
version or hash changes (verified: git diff has no version/sha256 lines).
* refactor(read_file): capability-gate the anydoc format list; PDF coverage teaching lives in the response-time warning (426 -> 244/291 tok/call)
* feat(read_file): bundle firecrawl-anydoc 0.2.4 in core, typed NeedsOcrError handling, config-gated hosted OCR with local-OCR-first guidance
* refine(read_file): NEEDS-OCR warning hints at checking for an OCR skill without naming one; hosted_ocr knob unadvertised (maintainer-directed)
* simplify(read_file): drop the anydoc schema gate — bundled core dep makes absence a broken install, not a variant; formats stated unconditionally (263 tok/call)
* feat(read_file): PDF wording upgrades to 'scanned or text' when a trusted hosted-OCR route exists (direct key or explicit config; nous gateway excluded until Parse proxy works)
* simplify(read_file): FIRECRAWL_API_KEY is the ONLY hosted-OCR gate — nous gateway route removed (Parse proxy broken), config true no longer unlocks; false still disables
tool_search now takes queries: string[] (searched independently against
the same catalog, limit applies per query, default 5 / max 25) and
returns the split shape: per-query groups carry tool names only, one
shared tools map holds each matched tool's source, description (400-char
cap) and required parameter names once. When some queries miss, a single
top-level available_sources + hint block replaces the old per-response
fallback.
tool_describe now takes names: string[] and returns a map keyed by name;
unknown names collect in not_found (with the refresh hint) and
non-deferrable names keep their per-name spelling-check error in errors,
so one bad name no longer fails the whole call. Duplicates dedupe
silently.
The shared tokenizer now applies Snowball stemming (english, exact-pinned
snowballstemmer) at both index and query time, closing the measured
plural/singular miss where 'issues' failed to return create_issue. The
inline BM25 is unchanged. Stemmer instances are thread-local (they carry
mutable parse state and bridge dispatch can run on parallel tool-call
threads).
New config knobs under tools.tool_search: max_queries / max_describe_names
(default 10 each, floor 1, no upper clamp) bound the per-call array
inputs; over-cap calls error so the model repairs in one round-trip.
No backward compatibility with the single query/name shapes, by decision.
scripts/analyze_livetest.py renders both shapes since transcripts on disk
may predate this change.
mcp 2.0.0 implements MCP revision 2026-07-28 and makes three breaking
changes Hermes sits on top of: `mcp.server.fastmcp` is gone, every model
field is renamed to snake_case (camelCase survives only as a
serialization alias, which pydantic does not expose to attribute
access), and the SDK's own HTTP stack moved from `httpx` to `httpx2`.
Bump the pin across the dev/mcp/computer-use extras and port the tree:
- `mcp_serve.py` and `agent/transports/hermes_tools_mcp_server.py` move
from `FastMCP` to `mcp.server.MCPServer`, which has the same
decorator/add_tool surface. The hermes-tools server already
synthesised `__signature__` from Hermes' JSON Schema, which is exactly
what 2.0's `add_tool` reads.
- SDK model reads go through `mcp_field(obj, snake, camel)`, which reads
both spellings. A single-spelling read fails *silently* on the other
generation — empty tool schemas, dropped structured content, tool
results vanishing from sampling conversations — and `mcp` is an
optional extra users install at their own version.
- `sdk_httpx()` resolves the httpx flavour from the SDK's own transport
module, so objects handed to `streamable_http_client`, the `sse_client`
factory, and the OAuth metadata helpers come from the module the
installed SDK actually imports.
- HTTP support is gated on either streamable-HTTP entry point, not just
the deprecated alias 2.0 removed.
- OAuth: `OAuthClientProvider` lost its `timeout` argument (the
configured `oauth.timeout` now bounds the callback waiter's own poll
loop, where the browser round-trip was always awaited), and
`callback_handler` must return `AuthorizationCodeResult` rather than a
tuple. 2.0 also validates the RFC 9207 `iss` parameter, so the
callback handler and paste fallback capture it.
`mcp`/`mcp-types` 2.0.0 are inside the 14-day `exclude-newer` window, so
two narrow `exclude-newer-package` entries unblock `uv lock`, annotated
for removal on or after 2026-08-11. `httpx2` needs no exemption: 2.7.0 is
already outside the window and satisfies mcp's floor.
Refs #69931
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The relative exclude-newer = "14 days" cutoff bricks installs whenever the
resolver cannot see (or accept) a package's upload date:
- defusedxml / python-olm / unpaddedbase64 (#80387, #79434): ancient frozen
releases (2021-2023) whose upload dates are often absent from mirror
indexes and stale uv HTTP caches. uv then filters them entirely
("there are no versions of defusedxml"), breaking [youtube]/[wecom]/
[matrix] resolution and daily `uv sync --locked` runs.
- setuptools / pillow / mcp (#78227, #75992, #76020): exact-pinned deps.
When the pinned version's upload date is invisible, the resolver filters
the ONLY acceptable candidate — setuptools==83.0.0 in
[build-system].requires meant the project could not even be built from a
git checkout on released v0.20.0. Exempting an exact pin costs nothing:
the version cannot float without a reviewed pin bump.
Changes:
- pyproject.toml: add all six to the existing exclude-newer-package
whitelist, with rationale comments per class.
- uv.lock: regenerated; diff is the whitelist metadata only (verified
zero version drift, still 249 packages).
- tests/test_packaging_metadata.py: new standing guard
test_build_system_requires_exempt_from_exclude_newer — every
[build-system].requires package must be whitelisted while a relative
exclude-newer cutoff is configured. Verified both directions (fails
when setuptools is removed from the whitelist).
- scripts/install.sh: fix the stale tier-name comparison ("all (with
RL/matrix extras)" vs actual "all") that mislabeled every successful
Tier-1 install as a fallback-tier install (#79434 bonus finding).
Verification: uv lock --check green on uv 0.11.19 and 0.12.5;
uv sync --extra all --locked green; uv pip install -e '.[all]' resolves;
whitelist mechanism A/B-proven on a minimal project (unsatisfiable ->
resolves; build-requires variant: uv build fails -> succeeds).
Reported-by: MichaelClawHub (#80387), liujianqiu (#79434), maxonliu (#78227)