Commit graph

109 commits

Author SHA1 Message Date
Teknium
0cf58de85e
Merge remote-tracking branch 'origin/main' into wake-toggle-config
# Conflicts:
#	tests/test_tui_gateway_server.py
#	tui_gateway/server.py
2026-07-28 12:37:35 -07:00
Teknium
3d2cc39158
chore: regenerate uv.lock with uv 0.11.33 to match CI
The rebase's lock was produced by uv 0.9.28 (runtime venv); CI runs uv
0.11.33, whose resolver rejected it (uv sync --locked failed). Relocked
with 0.11.33 — only wake-extra deps and their transitives added, no
unrelated version churn.
2026-07-28 08:04:28 -07:00
Ben Barclay
7d19033d2e
fix(wake): run openWakeWord on tflite on macOS ARM64
openWakeWord's ONNX backend returns near-zero scores on Apple Silicon
(dscripka/openWakeWord#336), so "Hey Hermes" never crossed the 0.5
threshold: the listener armed, the microphone worked, and nothing fired.

Bisecting the pipeline puts the fault in exactly one stage — feeding the
same audio through both backends, the melspectrogram front-end is
bit-identical (maxdiff 0.00000) and the wake classifier agrees on
identical features, while the shared embedding model diverges by 45.44.
Cross-feeding confirms it: tflite features scored through the *onnx*
classifier give 0.9948 vs 0.000009 for onnx features. A telling
secondary symptom is that scores fall as input gets louder (0.5x ->
0.00031, 8x -> 0.000066), which is garbage inference rather than a weak
detection.

Selecting tflite in config alone does not fix it. openWakeWord hardcodes
`import tflite_runtime.interpreter` but declares tflite-runtime for
`platform_system == "Linux"` only; on macOS the equivalent wheel is
ai-edge-litert, so that import always fails and model.py silently
downgrades back to onnx. The result is a detector that reports itself
listening and can never fire.

- default the backend per platform (tflite on macOS ARM64, onnx
  elsewhere) instead of hardcoding onnx, and pick the matching bundled
  model artifact
- bridge tflite_runtime -> ai_edge_litert through sys.modules, in-process,
  with no writes to site-packages
- refuse the silent onnx downgrade on macOS ARM64 and report the missing
  runtime through check_wake_word_requirements() so the GUI surfaces an
  actionable hint rather than arming a dead ear
- lazy-install ai-edge-litert via its own feature key, because lazy-dep
  specs cannot carry PEP 508 markers (_spec_is_safe rejects ";")

An explicit `inference_framework` in config still wins, so anyone pinning
a backend keeps it.

Verified on macOS 26.5.2 / M-series: "hey hermes" scores 0.0005 on onnx
and 0.9423 on tflite from the same clip, with cross-phrase controls at
0.0003. Live over-the-air through the real microphone fires 4/4
utterances (peak 0.9532).
2026-07-28 07:59:34 -07:00
Hermes Agent
0ae305ed4e
feat(voice): open-vocabulary wake phrases via sherpa-onnx KWS
New "sherpa" wake_word provider: the configured phrase is BPE-tokenized
at runtime against a small streaming zipformer KWS model (~13 MB English,
one-time download cached under HERMES_HOME), so ANY typed phrase works
with zero training — including per-profile phrases like "hey coder".

wake.sherpa lazy-dep group + [wake] extra grow sherpa-onnx/sentencepiece;
requirements probe routes per provider; sensitivity maps onto sherpa
keywords_threshold. E2E-verified on real audio (target phrase fires,
foreign phrase stays silent, reset drops buffered state).
2026-07-28 07:58:16 -07:00
Brooklyn Nicholson
9f84bc30bd
feat(voice): bundle the trained "hey hermes" model as the out-of-the-box default
From #53378: ships hey_hermes.onnx/.tflite (openWakeWord pipeline,
Apache-2.0) under tools/wakewords/, resolves the default (and hey_hermes
aliases) to the bundled file, ensures openWakeWord base feature models
are fetched for custom paths too, and updates config defaults + docs
from hey_jarvis to hey hermes.
2026-07-28 07:58:16 -07:00
Alex Fournier
14bed44c8c Reapply "feat(observability): integrate NeMo Relay runtime and shared metrics"
Signed-off-by: Alex Fournier <afournier@nvidia.com>
2026-07-27 21:10:51 -07:00
Jeffrey Quesnelle
841a5a744a
Revert "feat(observability): integrate NeMo Relay runtime and shared metrics" 2026-07-27 22:28:08 -04:00
Jeffrey Quesnelle
9216198601
Merge branch 'main' into feat/hermes-relay-shared-metrics 2026-07-26 23:14:26 -04:00
teknium1
623762f2f0 fix(deps): move CVE pins to current fixed versions so update stops downgrading patched envs
Adjusts the salvaged pin refresh (#60839 by @embwl0x) to the actually
mergeable versions and regenerates the lock:

- cryptography 46.0.7 -> 48.0.1 (GHSA-537c-gmf6-5ccf fixed in 48.0.1;
  49.x is NOT possible: msal caps <49 and alibabacloud-tea-openapi caps
  <49 — documented at the pin site). Also resolves the
  hindsight-api-slim>=48.0.1 conflict reported in Discord.
- starlette 1.0.1 -> 1.3.1 across core/web/mcp/computer-use/dev extras
  and LAZY_DEPS (fastapi accepts >=0.40, mcp >=0.27)
- python-multipart 0.0.27 -> 0.0.32 ([web] + tool.dashboard)
- uv.lock regenerated (tea-openapi 0.4.4->0.4.5 for the <49 crypto cap)

Keeps @embwl0x's anti-downgrade floor guard in test_packaging_metadata
with the corrected cryptography floor (48,0,1). Fixes #60685: a user env
already upgraded to these versions is no longer downgraded by
hermes update, because the pins now ARE those versions.
2026-07-26 19:29:07 -07:00
embwl0x
a48251c3dc fix(update): refresh cve dependency pins 2026-07-26 19:29:07 -07:00
teknium1
40dc36a842 fix(deps): converge huggingface-hub on one exact version (1.24.0) across lock and lazy pin
hermes update's lazy-refresh pass re-asserts LAZY_DEPS pins whenever the
package is present (active_features() is presence-based). The
tool.trace_upload pin huggingface-hub==1.2.3 sat below transformers'
>=1.5.0,<2 requirement, so every update force-downgraded the shared
package and broke Hindsight local embeddings on daemon startup (#60783).

Keep the exact-pin security posture — no ranges — but move the pin to
1.24.0 (current) and bump uv.lock in lockstep (uv lock --upgrade-package
huggingface-hub: hub 1.4.1->1.24.0, hf-xet 1.3.1->1.5.2, click
8.3.1->8.4.2, drops typer-slim), so the entire tree converges on ONE hub
version. The refresh pass now reports 'current' with zero churn.

Invariant tests (not snapshots): the lazy pin must equal the uv.lock
resolved version, and must sit inside transformers' accepted window.
HfApi surface used by trace upload (whoami/create_repo/upload_file)
verified present with identical kwargs on 1.24.0 in a live venv.
2026-07-26 17:24:31 -07:00
Alex Fournier
b4e105031a Merge upstream main into feat/hermes-relay-shared-metrics
# Conflicts:
#	MANIFEST.in
#	pyproject.toml
#	tests/test_project_metadata.py
2026-07-23 07:22:03 -07:00
ethernet
d84e11af4d
rip out brew + pip/PyPI wheel support (#68217)
Removes Homebrew and PyPI wheel/sdist as Hermes distribution paths while
preserving the supported source, Docker, and Nix workflows.

Changes:
- Removes the Homebrew formula, PyPI publish workflow, sdist manifest
  (MANIFEST.in), and wheel/sdist release-attachment logic from scripts/release.py.
- Keeps setuptools metadata and entry points required by editable installs
  and Docker/Nix builds, but adds a setup.py guard that rejects wheel/sdist
  builds outside a sealed Nix derivation (HERMES_NIX_BUILD=1).
- Removes pip/Homebrew install detection, PyPI update checks, the pip
  self-update path, the deprecation-banner state, the postinstall subcommand,
  wheel data-directory fallbacks in agent/i18n.py and hermes_constants.py,
  and the ACP Registry manifest/version-lockstep release logic.
- Adds /nix/store/ path detection so `nix run` / `nix profile install`
  installs (which don't set HERMES_MANAGED) are correctly identified as
  "nix" rather than falling through to "git"/"unknown".
- Retired install-method values ("pip", "homebrew") in existing
  .install_method stamps (both code-scoped and home-scoped) are ignored by
  the allowlist reader and fall through to "unknown" instead of resurrecting
  a retired enum value.
- Updates Nix packaging to ship bare runtime data (locales, optional-mcps)
  through store symlinks and wrapper env vars instead of wheel data-files.
- Removes the ACP Registry manifest/icon and their version-lockstep tests.
- Deletes or rewrites packaging, pip-update, Homebrew, and ACP Registry
  tests; adds parametrized coverage for the packaging build guard covering
  BOTH sdist and wheel paths (the guards live in separate cmdclass entries
  — a passing sdist test proves nothing about the wheel path).
- Updates installation/platform documentation and related user-facing copy.
- Adjusts the supply-chain scan so deleted install-hook files do not trigger
  a finding, while additions or modifications still require the existing
  ci-reviewed label gate.

Supported installation paths (unchanged):
- git installer (install.sh)
- Docker
- Nix/NixOS
- editable development installs (uv sync, uv pip install -e ., pip install -e .)
2026-07-22 16:51:01 -04:00
Alex Fournier
91c8f88a2d build(deps): require stable NeMo Relay 0.6
Signed-off-by: Alex Fournier <afournier@nvidia.com>
2026-07-22 13:18:23 -07:00
Alex Fournier
93e2998f89 Merge origin/main into feat/hermes-relay-shared-metrics
Signed-off-by: Alex Fournier <afournier@nvidia.com>

# Conflicts:
#	agent/tool_executor.py
2026-07-21 11:22:28 -07:00
Alex Fournier
6efc5fe0af fix(runtime): preserve provider payloads through Relay
Signed-off-by: Alex Fournier <afournier@nvidia.com>
2026-07-21 09:25:22 -07:00
yoniebans
25f4ba7b3c Merge remote-tracking branch 'origin/main' into feat/desktop-remote-ssh-current
# Conflicts:
#	apps/desktop/electron/connection-config.test.ts
#	apps/desktop/electron/connection-config.ts
#	apps/desktop/electron/main.ts
2026-07-21 10:16:01 +02:00
yoniebans
b14be881b9 build: declare pywin32 as a direct win32 dependency
hermes_cli/windows_ssh_runtime.py imports win32security/win32file/etc.
directly but pywin32 only arrived transitively via concurrent-log-handler
-> portalocker. Declare it with a sys_platform gate so the Windows SSH
runtime doesn't depend on the logging dep chain. Review follow-up on
PR #68130.
2026-07-21 10:02:28 +02:00
Teknium
3ef6bbd201
chore: release v0.19.0 (2026.7.20) (#68175) 2026-07-20 11:35:21 -07:00
Alex Fournier
9ab62e8b21 fix(packaging): bound the NeMo Relay dependency
Signed-off-by: Alex Fournier <afournier@nvidia.com>
2026-07-20 11:02:28 -07:00
Alex Fournier
9bc521b138 refactor(runtime): manage Relay LLM tool and subagent execution
Signed-off-by: Alex Fournier <afournier@nvidia.com>
2026-07-19 08:57:38 -04:00
Alex Fournier
64faff6768 refactor(observability): move Relay runtime ownership into core
Signed-off-by: Alex Fournier <afournier@nvidia.com>
2026-07-19 08:54:49 -04:00
Alex Fournier
3bd338d2a9 feat(observability): add Relay shared metrics pipeline
Signed-off-by: Alex Fournier <afournier@nvidia.com>
2026-07-19 08:54:27 -04:00
Erosika
29e0471708 fix(honcho): update SDK and restore CI coverage 2026-07-16 12:48:48 -07:00
Teknium
d6590f8b17 chore(slack): bump slack-bolt to 1.29.0 and slack-sdk to 3.43.0
Slack's June 30 Agent messaging experience changelog lists Bolt Python
1.29.0 / Python SDK 3.43.0 as the Agent View minimums. Bump the
messaging/slack extras and the platform.slack lazy-install pins to
match, and regenerate uv.lock. All adapter API surfaces verified
present against the new versions in a clean venv.
2026-07-14 13:58:36 -07:00
Bryan Bednarski
2d2bed5891
Merge origin/main into bbednarski/nemo-relay-upgrade
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
2026-07-13 14:50:20 -06:00
Bryan Bednarski
297dbf958f
chore(nemo-relay): refresh uv lock for relay 0.5
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
2026-07-13 14:50:02 -06:00
teknium1
651e632b6d fix(feishu): ship Channel signaling SDK support 2026-07-09 20:31:49 -07:00
Teknium
9de9c25f62
chore: release v0.18.2 (2026.7.7.2) (#60651) 2026-07-07 20:11:08 -07:00
Teknium
f9eca7e15f
chore: release v0.18.1 (2026.7.7) (#60595) 2026-07-07 18:14:48 -07:00
Teknium
7c1a029553
chore: release v0.18.0 (2026.7.1) (#56611) 2026-07-01 13:07:40 -07:00
Steve Lawton
c73e74386b feat(vertex): add Google Vertex AI provider for Gemini (OAuth2)
Adds Vertex AI as a first-class provider for Gemini models via Vertex's
OpenAI-compatible endpoint. Vertex authenticates with short-lived OAuth2
access tokens (service-account JSON or ADC), not a static API key — the
missing piece behind the recurring requests (#13484, #12639, #56259).

- agent/vertex_adapter.py: OAuth2 token minting + refresh-on-expiry
  (5-min margin), ADC->service-account fallback, global vs regional
  endpoint URLs. Config precedence: env var > config.yaml > default.
- plugins/model-providers/vertex/: provider profile (auth_type=vertex),
  reuses Gemini's extra_body.google.thinking_config translation.
- runtime_provider: vertex short-circuit BEFORE the credential pool so a
  credentials-file path is never mistaken for a static API key; mints a
  fresh token + computes base_url per resolve.
- run_agent + conversation_loop: _try_refresh_vertex_client_credentials()
  re-mints the token and rebuilds the client on a mid-session 401, so a
  long-lived gateway agent survives token expiry (~1h).
- auxiliary_client: vertex auth_type branch for side-LLM tasks.
- config.yaml: vertex.project_id / vertex.region (non-secret, bridged to
  env); credential path stays in .env (VERTEX_CREDENTIALS_PATH).
- setup wizard + model picker: dedicated _model_flow_vertex; curated
  google/gemini-* model list; --provider choices.
- pricing/metadata: Vertex prices off the gemini docs snapshot; endpoint
  host auto-maps to the vertex provider (no probe spam).
- lazy_deps + pyproject [vertex] extra: google-auth, opt-in only.
- docs: guides/google-vertex.md + providers page; tests for adapter +
  runtime resolution.

Salvages and modernizes #8427 by @slawt onto current main: rewired from
the legacy PROVIDER_REGISTRY path to the provider-profile architecture,
moved non-secret config out of .env into config.yaml, and added the
per-turn 401 token-refresh the original lacked.
2026-07-01 05:25:33 -07:00
teknium1
6d1291f2cc chore(deps): bump aiohttp to patched 3.14.1 (from 3.14.0)
3.14.1 is the current patched release on the 3.14 line; both CVE-2026-34993
(CookieJar.load RCE) and CVE-2026-47265 (per-request cookie leak on
cross-origin redirect) are fixed as of 3.14.0, and 3.14.1 rolls up the
subsequent point fixes. Re-locked uv.lock.
2026-07-01 02:51:45 -07:00
Wing Huang
6c37b2c785 security(deps): enforce aiohttp CVE floor on all lazy messaging paths + coverage guard
The messaging extra and platform.slack pin aiohttp==3.14.0, but several
lazy messaging features listed only their SDK and let aiohttp come in
transitively. Each of those SDKs caps aiohttp loosely enough that a
vulnerable already-installed aiohttp still satisfies the range, so the
eager extras got the patched floor while the lazy paths did not:

  - discord.py (aiohttp>=3.7.4,<4)
  - mautrix / aiohttp-socks (aiohttp>=3,<4 / aiohttp>=3.10.0)  [Matrix]
  - microsoft-teams-apps (aiohttp<4)                            [Teams]

(Teams additionally shipped an explicit but *stale* aiohttp==3.13.4 in
both the pyproject `teams` extra and platform.teams.)

- tools/lazy_deps.py: add aiohttp==3.14.0 to platform.discord, platform.matrix;
  bump the stale platform.teams pin 3.13.4 -> 3.14.0.
- pyproject.toml: add aiohttp==3.14.0 to the matrix extra; bump the teams extra
  3.13.4 -> 3.14.0 (homeassistant/sms/messaging already at 3.14.0).
- tests/test_packaging_metadata.py: test_security_pins_present_in_mirrored_lazy_features
  now covers platform.discord/slack/matrix/teams. The existing agree-guard only
  compares packages pinned in BOTH sources, so it can't catch a lazy feature
  that omits a pin entirely; this guard is an explicit coverage contract
  (security package -> lazy features that must carry it) and fails with
  'platform.matrix: aiohttp=MISSING' if a floor is dropped again.
- uv.lock: regenerated, zero drift (aiohttp 3.14.0).
2026-07-01 02:51:45 -07:00
Teknium
0434a9a5ec chore: regenerate uv.lock for supermemory + mem0 extras 2026-06-29 00:25:36 -07:00
teknium1
2bd1977d8f chore: release v0.17.0 (2026.6.19) 2026-06-19 12:38:31 -07:00
kshitijk4poor
6752da9a77 fix(dashboard): clean up upload temp file on client disconnect + pin python-multipart (NS-501)
Follow-up to #47663 (streaming multipart upload), fixing two issues that
landed with it.

1. Temp file leaked on client disconnect. The streaming upload endpoint's
   except chain caught only HTTPException / PermissionError / OSError — all
   Exception subclasses. asyncio.CancelledError, raised when a browser aborts
   a large upload mid-stream (the exact NS-501 scenario), is a BaseException,
   so it bypassed every except clause and reached a finally that only closed
   the file handle and never unlinked the temp file. Every aborted large
   upload orphaned a partial `.{name}.*.upload` file (up to ~100 MB) in the
   target directory. Cleanup now lives in finally, keyed on a `renamed`
   success flag, so the temp file is removed on every non-success exit
   including BaseException paths. Added test_stream_upload_cleans_temp_on_cancellation,
   which fails on the pre-fix code (leaks the temp file) and passes with the fix.

2. python-multipart pinned to ==0.0.27 instead of ==0.0.20. The package was
   already resolved at 0.0.27 transitively (via daytona) before #47663; the
   explicit ==0.0.20 pin in the [web] extra and the tool.dashboard lazy-install
   set downgraded it. Bumped both to ==0.0.27 and regenerated with `uv lock`,
   keeping the lockfile coherent. The base dependency stays >=0.0.9,<1.
2026-06-18 11:32:18 +05:30
Ben Barclay
c661634537
fix(dashboard): stream file uploads via multipart instead of base64 JSON (NS-501) (#47663)
* fix(dashboard): stream file uploads via multipart instead of base64 JSON

The dashboard file manager uploaded files (including backup/restore zip
archives) by reading them client-side with FileReader.readAsDataURL and
POSTing a base64 data URL inside a JSON body to /api/files/upload. For a
large backup this (a) inflates the payload ~33%, (b) buffers the whole
file plus its decoded copy in memory, and (c) reliably trips an upstream
proxy body-size/timeout limit, surfacing as a 502 with the upload
appearing to hang indefinitely (NS-501). Dashboard-only hosted users have
no shell fallback to place the archive, so backup restore was unusable.

Add a streaming multipart endpoint POST /api/files/upload-stream
(UploadFile + Form) that reads the request body in 1 MiB chunks straight
to a sibling temp file, enforces the existing 100 MB size cap as it
streams (413 on overflow, before buffering the whole file), and
atomically renames into place so a partial/aborted/over-limit upload
never clobbers an existing file. The frontend api.uploadFile now sends
multipart/form-data (raw bytes, no base64, browser-set boundary) and
FilesPage passes the File object directly; the dead readAsDataUrl helper
is removed. The legacy base64 JSON endpoint stays for backward compat.

FastAPI's UploadFile/Form require python-multipart, which is NOT pulled in
by fastapi itself, so it is added to the base deps, the [web] extra, and
the tool.dashboard lazy-install set (kept in sync).

Validated: 5 new endpoint tests (roundtrip, multi-chunk >1 MiB,
over-limit 413 without clobbering + no temp-file leak, overwrite=false
conflict, forced-root traversal containment); existing base64 tests still
pass; web typecheck + vite build clean; and a real uvicorn server E2E
(5 MB multipart upload -> HTTP 200 in 0.21s, exact byte match) plus a
30 MB TestClient roundtrip confirm constant-memory streaming end to end.

Reported via beta (NS-501).

* build(deps): regenerate uv.lock for python-multipart (NS-501)

CI ran uv lock --check / uv sync --locked which failed because the
python-multipart dependency add was not reflected in uv.lock. Regenerate
the lockfile (resolves to 0.0.20, matching the [web] extra pin) after
merging current main.
2026-06-18 15:54:32 +10:00
Austin Pickett
394cdf48ce
fix(logging): alias RotatingFileHandler to concurrent-log-handler (salvage #44921) (#46794)
* fix(logging): alias RotatingFileHandler to concurrent-log-handler

On Windows, stdlib RotatingFileHandler.doRollover() uses os.rename(), which
fails with PermissionError [WinError 32] whenever another process holds an
append-mode handle on agent.log — essentially always in Hermes (TUI, gateway,
hy_memory server, MCP servers, and on-demand CLI commands all log from separate
processes). This pinned agent.log at the 5 MiB threshold and spammed stderr
with a traceback on every emit (#44873).

Add concurrent-log-handler==0.9.29 as a core dep and alias its
ConcurrentRotatingFileHandler as RotatingFileHandler in hermes_logging.py. It
wraps the rename in a cross-process file lock (via portalocker: pywin32 on
Windows, fcntl on POSIX) so only one process rotates at a time. Aliasing keeps
every existing isinstance/class-declaration reference working unchanged.

Co-authored-by: tuancookiez-hub <tuancookiez@gmail.com>

* fix(logging): gate concurrent-log-handler swap to Windows only

The initial salvage aliased RotatingFileHandler -> ConcurrentRotatingFileHandler
unconditionally, which regressed POSIX: CLH opens lazily and rotates via its own
lock path, breaking managed-mode (NixOS) group-writable perms and eager file
creation that _ManagedRotatingFileHandler depends on. CI caught it as 2 failures
in test_managed_mode_*_group_writable on Linux.

The WinError 32 bug (#44873) is Windows-specific — POSIX renames an open file
fine, so stdlib already works on Linux/macOS. Gate the swap behind
sys.platform == 'win32': Windows uses CLH, POSIX keeps stdlib RotatingFileHandler.

- hermes_logging.py: platform-conditional import.
- tests/test_hermes_logging.py: import RotatingFileHandler from hermes_logging
  (single source of truth) so the autouse fixture's isinstance checks match the
  real handler class on both platforms.
- pyproject.toml/uv.lock: mark the dep 'sys_platform == "win32"' so portalocker
  /pywin32 only ship where used.

---------

Co-authored-by: tuancookiez-hub <tuancookiez@gmail.com>
Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
2026-06-17 15:39:04 -05:00
Austin Pickett
5f6be7f31b
fix(teams): package Microsoft Teams SDK as an installable extra (salvage #43945) (#46764)
* fix(teams): package Microsoft Teams SDK as an installable extra

The Teams adapter imports the microsoft-teams-apps SDK, but it was never
declared as a dependency, so source/local installs hit ImportError and the
adapter silently reported the SDK as unavailable. Add a 'teams' extra
(microsoft-teams-apps==2.0.13.4 + aiohttp) and document 'uv sync --extra teams'.

Per the 2026-05-12 [all] policy, opt-in messaging-platform SDKs are NOT added
to [all] (they would break every fresh install on a quarantined release); the
teams extra is installed on demand like the other platform backends.

Co-authored-by: rio-jeong <rio.jeong@thebytesize.ai>

* chore: map rio-jeong contributor email for attribution (#43945)

* feat(teams): lazy-install the Teams SDK on demand (parity with other channels)

The teams extra alone left Teams as the only messaging platform that wouldn't
auto-install its SDK — every other channel (telegram, discord, slack, matrix,
dingtalk, feishu) lazy-installs via tools.lazy_deps on first connect. Bring
Teams to parity:

- Add 'platform.teams' to LAZY_DEPS (microsoft-teams-apps + aiohttp).
- Replace the passive 'check_teams_requirements = check_requirements' alias with
  a real lazy-installer that calls ensure_and_bind('platform.teams', ...),
  rebinding all Teams SDK globals on success (mirrors check_slack_requirements).
- Call check_teams_requirements() at the top of TeamsAdapter.connect() so
  enabling Teams installs the SDK on demand.
- Keep the passive check_requirements() as the registry check_fn so 'gateway
  status' probes never trigger a pip install.

The 'teams' extra remains for packagers / explicit 'uv sync --extra teams'.

Tests: rework the alias test into shortcircuit + lazy-install assertions, and
update test_connect_fails_without_sdk to simulate an uninstallable SDK.

---------

Co-authored-by: rio-jeong <rio.jeong@thebytesize.ai>
Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
2026-06-15 14:35:15 -04:00
Austin Pickett
0bbff1fc7e
fix(deps): declare websockets as core dep + relax dev setuptools pin (salvage #45486, #44693) (#46744)
* fix: declare websockets as a core dependency

* fix(deps): relax dev setuptools pin 82.0.1 -> 81.0.0 (torch caps setuptools<82)

torch >= 2.11 publishes Requires-Dist: setuptools<82, so any environment
that resolves the dev extra together with torch is unsatisfiable:

    $ uv pip install --dry-run ".[dev]" "torch==2.12.0"
    x No solution found when resolving dependencies:
      ... torch==2.12.0 and all versions of hermes-agent[dev] are incompatible.

81.0.0 is the latest release under the cap and stays inside the declared
build-system window (setuptools>=77.0,<83). uv.lock regenerated with
'uv lock'; diff is scoped to the setuptools entry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: map salvaged contributor emails for attribution

Add AUTHOR_MAP entries for the two cherry-picked contributors so the
check-attribution CI gate passes:
- yehaotian@xuanshudeMac-mini.local -> ArcanePivot (#45486)
- dbeyer7@gmail.com -> benegessarit (#44693)

---------

Co-authored-by: 玄枢 <yehaotian@xuanshudeMac-mini.local>
Co-authored-by: David Beyer <dbeyer7@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
2026-06-15 12:44:44 -04:00
Teknium
f3fe99863d
revert(web): remove keyless Parallel search fallback (#46350)
Remove the free Parallel Search MCP path and restore the keyed Parallel backend behavior from before it was introduced.

Also drops the keyless fallback registration/display labeling tests and returns the Parallel SDK pin to the prior version.
2026-06-14 16:47:57 -07:00
Teknium
af5b526472 fix(ssl): validate CA bundle paths before provider calls 2026-06-13 21:14:32 -07:00
ethernet
2f9d18711f fix(ci): remove pytest-timeout, use per-file timeout only
fix(ci): write a new cache for test durations every time
change(ci): rip out error 4 retries because we found the real bug
2026-06-12 13:42:42 -04:00
Matt Harris
e0e2571711 feat(web): Parallel-backed web search & extract — free Search MCP when keyless, v1 REST when keyed
Make Parallel the web search/extract backend with a zero-setup free tier:

- Keyless (no PARALLEL_API_KEY): web_search/web_extract work out of the box via
  Parallel's free hosted Search MCP (search.parallel.ai/mcp), and parallel
  becomes the default backend when no other web credentials are configured
  (ahead of ddgs, which is search-only). A small hand-rolled Streamable-HTTP
  JSON-RPC client speaks the MCP's web_search/web_fetch tools; the existing
  web_search/web_extract tools are the only tools registered.
- Keyed (PARALLEL_API_KEY set): uses the Parallel v1 REST endpoints
  (client.search / client.extract with advanced_settings.full_content) — no beta.
  Bumps parallel-web 0.4.2 -> 0.6.0.
- Attribution: on the free path only, results carry provider/attribution and the
  CLI tool line reads "Parallel search" / "Parallel fetch"; the paid path is
  unbranded.
- Selection/registration: web tools register unconditionally (free MCP backstop)
  while check_web_api_key remains a real usability probe; explicit per-capability
  backends are honored (so misconfig surfaces) rather than masked by the fallback.

Tested: live web_search/web_extract against search.parallel.ai in keyless and
keyed modes; unit suites for the MCP client, backend selection, and display
labeling; full agent run shows the "Parallel search" label on the free path.
2026-06-10 19:54:38 -07:00
liuhao1024
f6416f50fc
fix(deps): bump urllib3 and PyJWT to clear CVEs (#40179)
* fix(deps): bump urllib3 and PyJWT to clear CVEs

urllib3 2.6.3 → 2.7.0: fixes GHSA-mf9v-mfxr-j63j (decompression-bomb
bypass in streaming API) and GHSA-qccp-gfcp-xxvc (sensitive headers
forwarded across origins in proxied redirects).

PyJWT 2.12.1 → 2.13.0: fixes PYSEC-2026-175/177/178/179.

Note: python-multipart and idna are already at patched versions in
uv.lock (0.0.27 and 3.15 respectively).

Fixes #40176

* fix(deps): add upper bound for urllib3 dependency spec

Add '<3' ceiling to urllib3 specifier to satisfy the PyPI dependency
upper bounds CI check. Per CONTRIBUTING.md policy, all PyPI deps must
use '>=floor,<next_major' pinning.
2026-06-09 11:19:05 -04:00
Brian D. Evans
b5421f4ba6
fix(deps): declare packaging as a core dependency so it ships everywhere (#40522)
* fix(deps): declare packaging as a core dependency so it ships everywhere

packaging is imported directly on three production paths but was never
declared in [project.dependencies], so it only reached users transitively
(pip/uv pull it for other tools). The slim official Docker image ships
without it, where each try/except-ImportError fallback silently degrades:

- plugins/memory/hindsight/__init__.py (_meets_minimum_version) returns
  False when packaging is absent, disabling update_mode='append' so every
  session leaks separate Hindsight documents (the reported #40503 symptom).
- tools/lazy_deps.py (_is_satisfied) falls back to "installed counts as
  satisfied", defeating every version-constraint check on lazy extras.
- hermes_cli/main.py drops to naive name==version requirement parsing.

Promote it to a declared core dep pinned to packaging==26.0 — the exact
version already resolved in uv.lock, so there is zero resolution churn (the
lock change is two edge annotations marking it transitive->direct). It is a
pure-Python py3-none-any wheel with no compiled extensions, safe to ship on
every platform. Declaring it also wires it into the
_verify_core_dependencies_installed() update-repair guard, which reinstalls
missing [project.dependencies] on hermes update.

Adds a hermetic tomllib-parse regression test that fails before the
declaration and passes after.

Fixes #40503

* test(deps): make packaging dep-name extraction PEP 508-robust

Address Copilot review on #40522: the inline name-extraction only handled
==, >=, [ and ; and could mis-parse valid requirement strings using <=, ~=,
!=, <, > or a direct reference (name @ url). Factor a _distribution_name
helper that drops markers, direct-reference URLs and extras, then strips any
version operator via regex, so a future dep declared with any PEP 508
specifier shape is matched correctly.

---------

Co-authored-by: briandevans <252620095+briandevans@users.noreply.github.com>
2026-06-09 11:11:48 -04:00
Teknium
2f510ca8e0
fix(deps): align anthropic extra pin with lazy pin + guard whole pin surface (#42335)
The anthropic extra pinned anthropic==0.86.0 while LAZY_DEPS['provider.anthropic']
pins 0.87.0 (CVE-2026-34450, CVE-2026-34452) — the same drift class as the
aiohttp #31817 downgrade. On hermes update the extra pin won and rolled
anthropic 0.87.0 -> 0.86.0, reopening both CVEs until the native-Anthropic
lazy refresh re-bumped it.

Bump the extra to 0.87.0, regenerate uv.lock, and generalize the regression
guard: test_pyproject_pins_match_lazy_deps_pins now fails if ANY package
pinned in both a pyproject extra and a LAZY_DEPS entry drifts, so a third
package can't reintroduce this class. The aiohttp-specific test is kept for
focused #31817 coverage.
2026-06-08 12:11:54 -07:00
cresslank
c6d27addf7 fix(deps): align aiohttp extras pins with lazy Slack pin (3.13.4)
The messaging/slack/homeassistant/sms extras exact-pinned aiohttp==3.13.3
while LAZY_DEPS['platform.slack'] already pins 3.13.4 (the CVE fix). On
`hermes update` the extras pin won, downgrading aiohttp 3.13.4 -> 3.13.3
and reopening 10 published advisories (CVE-2026-34513/34515/34516/34517/
34518/34519/34520/34525, -22815, -34514) until Slack's lazy refresh
re-upgraded it.

Bump all four extras to 3.13.4 to match the lazy pin, regenerate uv.lock,
and add test_pyproject_aiohttp_pins_match_lazy_slack_pin to guard the
alignment going forward.

Fixes #31817
2026-06-08 11:30:48 -07:00
teknium1
5b55f4fe8e chore(deps): regenerate uv.lock for Pillow core promotion
Pillow moves from the [vision] extra marker to an unconditional core
dependency. Keeps 'uv sync --locked' green.
2026-06-06 18:44:15 -07:00