Commit Graph

667 Commits

Author SHA1 Message Date
Abd0r
04193cf71c feat(web): add Brave Search (free tier) and DDGS search providers
Both implement WebSearchProvider via tools/web_providers/ — matching the
existing SearXNG pattern (PR #5c906d702). Search-only; pair with any
extract provider via web.extract_backend.

- tools/web_providers/brave_free.py — Brave Search API (free tier, 2k
  queries/mo). Uses BRAVE_SEARCH_API_KEY as X-Subscription-Token.
- tools/web_providers/ddgs.py — DuckDuckGo via the ddgs Python package.
  No API key; gated on package importability.
- tools/web_tools.py: both backends added to _get_backend() config list
  and auto-detect chain (trails paid providers), _is_backend_available,
  web_search_tool dispatch, web_extract_tool + web_crawl_tool search-only
  refusals, check_web_api_key, and the __main__ diagnostic. Introduces
  _ddgs_package_importable() helper so tests can monkeypatch a single
  symbol for the ddgs availability check.
- hermes_cli/tools_config.py: picker entries for both providers; ddgs
  gets a post_setup handler that runs `pip install ddgs`.
- hermes_cli/config.py: BRAVE_SEARCH_API_KEY in OPTIONAL_ENV_VARS.
- scripts/release.py: AUTHOR_MAP entry for @Abd0r.
- tests: 14 new tests (brave-free) + 15 new tests (ddgs) covering
  provider unit behavior, backend wiring, and search-only refusals.

Salvages the brave-free + ddgs portion of PR #19796. Not included: the
in-line helpers in web_tools.py (replaced with provider modules to match
the shipped architecture), the lynx-based extract path (these backends
should refuse extract with a clear error — users pair with a real
extract provider), and scripts/start-llama-server.sh (unrelated).

Co-authored-by: Abd0r <223003280+Abd0r@users.noreply.github.com>
2026-05-07 09:59:17 -07:00
Teknium
498bfc7bc1
chore: release v0.13.0 (2026.5.7) (#21406)
The Tenacity Release — Hermes Agent now finishes what it starts.

- Durable multi-agent Kanban with heartbeat, reclaim, zombie detection,
  retry budgets, hallucination gate
- /goal persistent cross-turn goals (Ralph loop)
- Checkpoints v2 single-store rewrite with real pruning
- Gateway auto-resume interrupted sessions after restart
- no_agent cron watchdog mode
- Post-write delta lint on write_file + patch
- 8 P0 security closures — redaction ON by default, CVSS 8.1 Discord
  fix, WhatsApp stranger rejection, MCP/auth TOCTOU, SSRF floor,
  cron prompt-injection skill scanning
- Google Chat (20th platform) + generic platform-plugin hooks
- ProviderProfile ABC + plugins/model-providers/
- 7 i18n locales (zh/ja/de/es/fr/uk/tr) + display.language
- video_analyze tool, xAI Custom Voices, SearXNG, OpenRouter caching
- MCP SSE transport + OAuth + image MEDIA surfacing
- 864 commits, 588 merged PRs, 295 contributors
2026-05-07 09:22:48 -07:00
Teknium
bbff2f6345 chore(release): map maciekczech noreply email 2026-05-07 07:39:57 -07:00
Teknium
1baab8771a chore(release): add qWaitCrypto to AUTHOR_MAP for PR #21055 salvage 2026-05-07 07:17:12 -07:00
Teknium
43cf72a458 chore(release): map donramon77 to AUTHOR_MAP for PR #18425 salvage 2026-05-07 07:15:44 -07:00
teknium1
4ee6c3349a chore(release): map tuancanhnguyen706@gmail.com → xxxigm 2026-05-07 07:05:05 -07:00
Teknium
5a3e5b23d2 fix(memory): remove dead allOf schema block at the source
PR #21238 introduced top-level `allOf: [{if/then/required}]` blocks in the
built-in memory tool's parameters schema as conditional-required hints.
Two problems:

1. OpenAI's Codex backend (chatgpt.com/backend-api/codex, gpt-5.x) rejects
   top-level `allOf`/`anyOf`/`oneOf`/`enum`/`not` outright with a
   non-retryable 400 — affected every user on openai-codex/gpt-5.x.
2. The `if/then` hints were silently ignored by every other provider
   (Chat Completions doesn't honour them on function schemas), so they
   never actually enforced anything anywhere.

The runtime handler in `memory_tool()` already validates the per-action
required fields and returns actionable error messages, so removing the
block changes nothing behaviourally.

Paired with the defense-in-depth sanitizer in the previous commit, this
closes the bug both at the source (schema no longer emits the forbidden
form) and at the wire boundary (sanitizer strips it if anything else
re-introduces it).

- Rewrites `tests/tools/test_memory_tool_schema.py` to guard against
  regressing the forbidden-combinator shape instead of asserting it.
- Adds AUTHOR_MAP entry for @hrkzogw (author of the sanitizer fix).
2026-05-07 07:03:21 -07:00
Teknium
f5c9bb582c chore(release): add CashWilliams to AUTHOR_MAP 2026-05-07 06:54:29 -07:00
Teknium
6a4ecc0a9f
fix(whatsapp): reject strangers by default, never respond in self-chat (#8389) (#21291)
Self-chat mode (default) previously replied to ANY incoming DM with a
Python-side pairing-code message. Two compounding defaults:

1. allowlist.js::matchesAllowedUser returned true for an empty
   allowlist — so WHATSAPP_ALLOWED_USERS unset → everyone passes the JS
   bridge gate → messages reach Python gateway → _is_user_authorized
   returns False but _get_unauthorized_dm_behavior falls back to
   'pair' → stranger gets a pairing code reply.
2. bridge.js had no mode check on !fromMe messages, so self-chat mode
   (where the operator only wants to talk to themselves) forwarded
   everything anyway.

Fix:
- allowlist.js: empty allowlist now returns false. Operators who want
  an open bot must set WHATSAPP_ALLOWED_USERS=* explicitly (the
  existing wildcard behaviour, consistent with SIGNAL_GROUP_ALLOWED_USERS).
- bridge.js: self-chat mode hard-rejects all !fromMe messages at the
  bridge, before they ever reach the Python gateway. Bot mode still
  enforces the allowlist.
- Startup log message updated to reflect the new per-mode behaviour
  (was '⚠️ No WHATSAPP_ALLOWED_USERS set — all messages will be
  processed', which was both inaccurate post-fix and a bad default
  signal pre-fix).
- allowlist.test.mjs: new regression test pinning the empty-rejects
  contract, + null/undefined defensive cases.

Behaviour delta for existing users:
- self-chat mode, no allowlist: strangers got pairing codes, now
  silently dropped. Strictly better.
- bot mode, no allowlist: strangers got pairing codes via the
  Python-side pairing flow, now silently dropped at the JS bridge.
  Operators who genuinely want an open bot set
  WHATSAPP_ALLOWED_USERS=*.
2026-05-07 06:53:04 -07:00
Teknium
6769060ae2 chore: AUTHOR_MAP entry for @glesperance 2026-05-07 06:37:23 -07:00
Teknium
30c9990175 chore: correct AUTHOR_MAP for oluwadareab12 (was mismapped to bennytimz) 2026-05-07 06:35:54 -07:00
Teknium
f481395d4c chore(release): add subtract0 to AUTHOR_MAP for PR #19935 salvage 2026-05-07 06:32:45 -07:00
Teknium
33563df027 chore: AUTHOR_MAP entry for @paul-tian 2026-05-07 06:31:08 -07:00
Teknium
755b74fc2d chore: AUTHOR_MAP entry for @LucianoSP 2026-05-07 06:29:27 -07:00
Teknium
8aa30407c2 chore(release): add masonjames to AUTHOR_MAP for PR #10439 salvage 2026-05-07 06:28:11 -07:00
Teknium
25187ca05c chore: AUTHOR_MAP entry for @hedirman 2026-05-07 06:27:47 -07:00
Hedirman
a9ebee5f02 Fix WhatsApp long message splitting 2026-05-07 06:27:47 -07:00
Teknium
46d1fc16ab chore(release): add AJV20 to AUTHOR_MAP for PR #10287 salvage 2026-05-07 06:25:35 -07:00
Teknium
b7a97cd44f chore: AUTHOR_MAP entry for wabrent 2026-05-07 06:25:03 -07:00
Teknium
fcd619cae4 chore: AUTHOR_MAP entry for @kowenhaoai 2026-05-07 06:24:24 -07:00
Teknium
cfe019c782 chore: AUTHOR_MAP entry for @acc001k 2026-05-07 06:21:50 -07:00
Teknium
fd13b7d2b9 chore: AUTHOR_MAP entry for @agilejava 2026-05-07 06:19:58 -07:00
Teknium
8cef149131 chore: AUTHOR_MAP entry for @stevenchouai 2026-05-07 06:04:28 -07:00
Teknium
afbcca0f06 chore: AUTHOR_MAP entry for @shashwatgokhe 2026-05-07 05:58:11 -07:00
Teknium
ae1f058b3c
feat(curator): add hermes curator list-archived command (#21236)
Lists the skills sitting in ~/.hermes/skills/.archive/ so users have
something to pass to `hermes curator restore`. `curator status` already
shows counts; this fills the name-discovery gap.

Archive layout is flat (`archive_skill` writes to `.archive/<skill>/`),
so the directory name IS the skill name — no frontmatter parsing
needed. Timestamped collision directories (`<skill>-<ts>`) are listed
literally; user can still pass them to `restore`.

Reshape of @EvilDrag0n's #20651, simplified: drop the frontmatter
rglob + preamble/trailer output + duplicate subcommand registration.

Co-authored-by: EvilDrag0n <lxl694522264@gmail.com>
2026-05-07 05:46:51 -07:00
Teknium
47bf5d7ecb test+docs: cover transform_llm_output hook + release author map
- tests/test_transform_llm_output_hook.py: dispatch semantics
  (kwargs contract, first-non-empty-string-wins, empty-string
  pass-through, raising-plugin fail-open, no-plugins = no-op)
- tests/hermes_cli/test_plugins.py: assert the new hook name is in
  VALID_HOOKS alongside the other transform_* hooks
- website/docs/user-guide/features/hooks.md: summary-table entry +
  full section mirroring transform_tool_result / transform_terminal_output
- scripts/release.py: map barnacleboy.jezzahehn@agentmail.to -> JezzaHehn
  (existing entry only covers the gmail address)
2026-05-07 05:46:05 -07:00
Teknium
c4a7992317
fix(mcp-oauth): persist OAuth server metadata across process restarts (#21226)
The MCP SDK discovers OAuth server metadata (token_endpoint, etc.) on
demand and keeps it in memory only. Without disk persistence, a restart
with valid cached refresh tokens forces the SDK to fall back to the
guessed '{server_url}/token' path — which returns 404 on most real
providers (Notion, Atlassian, GitHub remote MCP, etc.) and triggers a
full browser re-authorization even though the refresh token is fine.

Add a .meta.json file next to the existing tokens/client_info files:

  HERMES_HOME/mcp-tokens/<server>.json        -- tokens (existing)
  HERMES_HOME/mcp-tokens/<server>.client.json -- client info (existing)
  HERMES_HOME/mcp-tokens/<server>.meta.json   -- oauth metadata (new)

Changes:
- HermesTokenStorage.save_oauth_metadata / load_oauth_metadata / _meta_path
  — disk layer for the discovered OAuthMetadata.
- HermesTokenStorage.remove() now also clears .meta.json so
  'hermes mcp remove <name>' and the manager's remove() path clean up fully.
- HermesMCPOAuthProvider._initialize cold-restores from disk before the
  existing pre-flight discovery runs. If disk has metadata we skip the
  discovery HTTP round-trips entirely.
- HermesMCPOAuthProvider._prefetch_oauth_metadata now persists ASM as
  soon as it's discovered, so even the first pre-flight run seeds disk.
- HermesMCPOAuthProvider._persist_oauth_metadata_if_changed() is called
  at the end of async_auth_flow so metadata discovered via the SDK's
  lazy 401-branch (not pre-flight) is also saved for next time.

Tests cover the storage roundtrip (save/load/missing/corrupt/remove) and
the manager provider path (cold-load restore, skip-when-in-memory,
persist-on-discover, noop-when-unchanged, end-to-end async_auth_flow).

Co-authored-by: nocturnum91 <50326054+nocturnum91@users.noreply.github.com>
2026-05-07 05:35:33 -07:00
Teknium
a5f116fc3f chore(release): map SandroHub013 email 2026-05-07 05:31:07 -07:00
Teknium
bda7b240b4 chore(release): map altriatree@gmail.com -> @TruaShamu 2026-05-07 05:27:45 -07:00
Teknium
3c8154e62c chore: AUTHOR_MAP entry for @GinWU05 2026-05-07 05:26:28 -07:00
Teknium
eef23354a5 chore: AUTHOR_MAP entry for @nouseman666 2026-05-07 05:24:43 -07:00
Teknium
aa9a2091f6 chore(release): add AUTHOR_MAP entries for ggnnggez and ehz0ah
Contributors to OpenViking local resource upload fix (#19569).
2026-05-07 05:21:50 -07:00
Teknium
4e27e4e05a chore: AUTHOR_MAP entry for @leon7609 2026-05-07 05:20:10 -07:00
Teknium
f0dd5b9c10 chore: add discodirector email to AUTHOR_MAP 2026-05-07 05:17:03 -07:00
Teknium
991df4ef81 chore: AUTHOR_MAP entry for @likejudy 2026-05-07 05:11:09 -07:00
Teknium
d856f4535d chore: AUTHOR_MAP entry for chenlinfeng@ruije / @noOne-list 2026-05-07 05:10:04 -07:00
Teknium
73d6371762 chore: add AUTHOR_MAP entries for thelumiereguy and counterposition 2026-05-07 05:07:59 -07:00
Teknium
38b1c7dce5 refactor(gateway): simplify auto-resume + extend to crash recovery
Follow-up on top of @kyan12's PR #20888 — same feature, cleaner shape,
wider coverage.

Changes:
- Drop the synthetic '[System note: ...]' in the internal MessageEvent.
  The existing _is_resume_pending branch in _handle_message_with_agent
  (run.py ~L13738) already injects a reason-aware recovery system note
  on the next turn.  With kyan's text in place the model saw two stacked
  system notes.  Now the event text is empty and the existing injection
  path owns the wording.
- Drop SessionStore.list_resume_pending() as a new public method.  The
  filter is 8 lines inline in _schedule_resume_pending_sessions() —
  one caller, no other pluggability need.
- Add 'restart_interrupted' to the auto-resume reason set.  That's the
  reason SessionStore.suspend_recently_active() stamps on sessions
  recovered from a crash/OOM/SIGKILL (no .clean_shutdown marker).
  Previously those sessions had to wait for a real user message to
  auto-resume; now they continue automatically at startup like
  drain-timeout interruptions do.
- Reasons live in a _AUTO_RESUME_REASONS frozenset at class scope so
  future reasons (e.g. 'manual_resume_request') can be opted in with
  one line.

Test coverage added:
- drain-timeout + crash-recovery both scheduled
- stale entries skipped (outside freshness window)
- suspended entries skipped (suspended > resume_pending)
- originless entries skipped (no routing target)
- disallowed reasons skipped (graceful forward-compat)

E2E verified end-to-end with a real on-disk SessionStore: 2 eligible
sessions scheduled, 2 ineligible skipped, empty-text internal events
delivered to the adapter.

Co-authored-by: Kevin Yan <kevyan1998@gmail.com>
2026-05-07 05:05:34 -07:00
Teknium
233bfd3621 chore(release): map mwnickerson noreply email 2026-05-07 05:05:20 -07:00
Teknium
595e906698 chore(release): map sonic-netizen noreply email 2026-05-07 05:05:20 -07:00
Teknium
63bd690a50 chore(release): map stephen0110 noreply email 2026-05-07 05:05:20 -07:00
Teknium
bf843adf05
feat(gateway): opt-in cleanup of temporary progress bubbles (#21186)
When display.cleanup_progress (or display.platforms.<plat>.cleanup_progress)
is true, the gateway deletes tool-progress bubbles, long-running ' Still
working...' notices, and status-callback messages after the final response
is delivered successfully. Currently effective on adapters that implement
delete_message (Telegram); silently no-ops elsewhere. Off by default.
Failed runs skip cleanup so bubbles stay as breadcrumbs.

Minimal plumbing: base.py's existing post_delivery_callback slot now chains
new registrations onto any existing callback (with per-callback exception
isolation) rather than clobbering. Stale-generation registrations are
rejected so they can't step on a fresher run's callbacks. This lets the
cleanup callback coexist with the background-review release hook already
registered on the same slot.

Co-authored-by: mrcharlesiv <Mrcharlesiv@gmail.com>
2026-05-07 05:04:37 -07:00
Teknium
aa5690342b chore(release): add Gutslabs to AUTHOR_MAP for PR #21148 salvage 2026-05-07 04:56:13 -07:00
Teknium
e7eb07cec7 chore: AUTHOR_MAP entry for mrcoferland 2026-05-07 04:51:46 -07:00
Teknium
d8b85bfd1c chore: add guillaumemeyer to AUTHOR_MAP
For cherry-picked commits in PR #20801.
2026-05-06 13:39:43 -07:00
ethernet
a345f7b6e5
Merge pull request #19908 from NousResearch/typecheck
change: enable ruff/ty
2026-05-06 14:43:14 -04:00
kshitijk4poor
28299afc21 chore: follow-up cleanup for Feishu topic thread fix
- Remove dead metadata.get('reply_to') fallback in _send_raw_message;
  nothing in the codebase ever sets 'reply_to' inside a metadata dict —
  the key only appears as a top-level send_voice() keyword argument
- Simplify _status_thread_metadata construction in run.py to use a
  single dict literal instead of create-then-mutate pattern; the
  or-{} guard was dead since source.thread_id implies _progress_thread_id
  is also set for Feishu
- Add yuqian@zmetasoft.com to AUTHOR_MAP for contributor attribution
2026-05-06 10:52:51 -07:00
ethernet
9627ee70e5 feat(ci): add typecheck (warnings only in CI) 2026-05-06 10:58:12 -04:00
Teknium
3ce1233ae4 chore(release): map cleo@edaphic.xyz → curiouscleo
Follow-up to the salvaged fix for /goal ENAMETOOLONG drop — adds
AUTHOR_MAP entry so the release script resolves the commit author to
the correct GitHub user.
2026-05-06 06:34:48 -07:00
Teknium
b1e0ef82f6 chore(release): map liuguangyong@hellobike -> liuguangyong93 2026-05-06 04:20:52 -07:00
Teknium
a869a523ee chore: AUTHOR_MAP entry for adybag14-cyber 2026-05-06 04:02:02 -07:00
adybag14-cyber
043a118d41 fix: harden install.sh against inherited Python env leakage 2026-05-06 04:02:02 -07:00
kshitijk4poor
aa88dcc57b fix: salvage batch — compaction guidance, memory authority, cache eviction after compression
- Fix /compact → /compress in context-overflow tips (closes #20020)
- Evict cached agent after session hygiene and /compress so system
  prompt refreshes with current SOUL.md, memory, and skills
- Restore memory authority across compaction: change 'informational
  background data' to 'authoritative reference data' in memory block
  and SUMMARY_PREFIX, with backward-compatible regex

Based on:
- PR #20027 by @LeonSGP43
- PR #18767 by @MacroAnarchy
- PR #17380 by @vominh1919

PR #17121 boundary marker fix already merged to main (2eef395e1).
PR #9262 user-message anchoring already on main via _ensure_last_user_message_in_tail().
2026-05-05 22:33:45 -07:00
Teknium
fab3ad9777 chore(release): AUTHOR_MAP entries for suncokret12 and mioimotoai-lgtm 2026-05-05 17:26:15 -07:00
Teknium
f0b95cc93d test(arcee): cover Trinity Large Thinking temperature + compression overrides
Salvage follow-up for PR #20344:
- AUTHOR_MAP entry for rob-maron (required by CI)
- 17 parametrized tests covering _is_arcee_trinity_thinking,
  _fixed_temperature_for_model Trinity override, and
  _compression_threshold_for_model, including sibling-model negatives
  (trinity-large-preview, trinity-mini) and the OpenRouter slug form.
2026-05-05 17:23:45 -07:00
teknium1
735349c679 chore: AUTHOR_MAP entry for olisikh 2026-05-05 17:21:59 -07:00
Teknium
ee8edd4169 chore: AUTHOR_MAP entry for bogerman1 2026-05-05 15:13:36 -07:00
Teknium
1efed67056 chore(release): AUTHOR_MAP entries for momowind and misery-hl 2026-05-05 15:09:28 -07:00
Teknium
50ab0a85a7 chore: AUTHOR_MAP entry for formulahendry 2026-05-05 14:16:30 -07:00
Teknium
f97d022149 chore: AUTHOR_MAP entry for zhanggttry 2026-05-05 14:15:05 -07:00
haidao1919
74e4f5f97a docs(i18n): add zh-Hans Tool Gateway, image gen, and Windows WSL guide
Made-with: Cursor
2026-05-05 14:14:03 -07:00
Teknium
a321874ab4 chore: AUTHOR_MAP entry for liu-collab 2026-05-05 14:12:49 -07:00
Teknium
a860a1098f chore: AUTHOR_MAP entry for acesjohnny 2026-05-05 14:12:09 -07:00
Zhen Liu
1c42d8ff53 docs: add Open WebUI bootstrap script 2026-05-05 14:12:09 -07:00
Teknium
92a08c633f chore: AUTHOR_MAP entry for binhnt92 2026-05-05 14:11:16 -07:00
Teknium
587ef55f2c chore: AUTHOR_MAP entry for xsfX20 2026-05-05 13:55:21 -07:00
Teknium
391e3fff56 chore: AUTHOR_MAP entry for Hypnus-Yuan 2026-05-05 13:54:33 -07:00
Teknium
bb2b129549 chore: AUTHOR_MAP entry for Fearvox 2026-05-05 13:52:46 -07:00
Teknium
79902a0278 chore: AUTHOR_MAP entry for counterposition 2026-05-05 13:51:56 -07:00
Teknium
1b1037171b chore: AUTHOR_MAP entry for CES4751 2026-05-05 13:48:37 -07:00
Teknium
7cc00087e7 chore: AUTHOR_MAP entry for deep-name 2026-05-05 13:44:09 -07:00
Teknium
8fa5a03752 chore: AUTHOR_MAP entry for jethac 2026-05-05 13:43:04 -07:00
Teknium
2b500ed68a chore: AUTHOR_MAP entry for asimons81 2026-05-05 13:34:03 -07:00
Teknium
c85a25faaa chore: AUTHOR_MAP entry for Beandon13 2026-05-05 13:26:12 -07:00
Teknium
87b113c2e3 chore: AUTHOR_MAP entry for Tkander1715 2026-05-05 10:18:58 -07:00
Teknium
cc2c820975 chore: AUTHOR_MAP entry for Aslaaen 2026-05-05 10:18:28 -07:00
Teknium
dbe9b15fa1 chore: AUTHOR_MAP entry for zeejaytan 2026-05-05 10:15:57 -07:00
Teknium
8c0f254c06 chore: AUTHOR_MAP entry for LeonSGP43 2026-05-05 10:15:31 -07:00
Teknium
4553e32bc4 chore: AUTHOR_MAP entry for Es1la 2026-05-05 10:15:09 -07:00
Teknium
77a102b7de chore: AUTHOR_MAP entry for jkausel-ai 2026-05-05 10:14:48 -07:00
Teknium
12135b4c8a chore: AUTHOR_MAP entry for wysie 2026-05-05 10:14:17 -07:00
Teknium
d9f0875591 chore: AUTHOR_MAP entry for hharry11 2026-05-05 10:13:55 -07:00
Teknium
935cf2fcca chore: AUTHOR_MAP entry for JTroyerOvermatch 2026-05-05 10:13:34 -07:00
Teknium
269be4ec84 chore: AUTHOR_MAP entry for Bongulielmi 2026-05-05 10:13:13 -07:00
Remigio Bongulielmi
d8097d587f refactor(env): use shared Hermes dotenv loader 2026-05-05 10:13:13 -07:00
Teknium
c62d8c9b74 chore: AUTHOR_MAP entry for Bartok9 2026-05-05 10:12:40 -07:00
Bartok
dad62c4c47 fix(whatsapp): auto-convert mp3/wav to ogg/opus in send-media for native voice bubbles
WhatsApp bridge (bridge.js) only sets ptt:true when file extension is .ogg
or .opus, causing mp3/wav files (from Edge TTS, NeuTTS, etc.) to arrive
as file attachments instead of voice bubbles — silently, with no error.

Fix: when audio type is sent with a non-ogg/opus format, run ffmpeg
conversion to ogg/opus in a temp file before sending. This makes
send_voice() self-sufficient regardless of what format the caller provides.

Fallback: if ffmpeg is unavailable, original buffer is sent (previous
behaviour) with a console.warn — no crash.

Addresses veloguardian's review comment on PR #4992.
2026-05-05 10:12:40 -07:00
Teknium
45949e944a chore: AUTHOR_MAP entry for Junass1 2026-05-05 10:05:23 -07:00
Teknium
b014a3d315 test(cron): update _isolate_tick_lock fixture for _get_lock_paths
After PR #13725 replaced the module-level _LOCK_DIR/_LOCK_FILE constants
with a dynamic _get_lock_paths() helper, the xdist-isolation fixture
needs to patch the function instead of the removed constants.
2026-05-05 09:57:06 -07:00
Teknium
7530ce04e0 chore: AUTHOR_MAP entry for MaHaoHao-ch 2026-05-05 06:12:42 -07:00
Teknium
8ebb81fd76 chore: AUTHOR_MAP entry for rxdxxxx 2026-05-05 06:12:11 -07:00
Teknium
fb311952d7 chore: AUTHOR_MAP entry for Krionex 2026-05-05 06:11:38 -07:00
Teknium
349d0da07e chore: AUTHOR_MAP entry for novax635 2026-05-05 06:11:03 -07:00
Teknium
37b5731694 chore: AUTHOR_MAP entry for npmisantosh 2026-05-05 06:08:14 -07:00
Teknium
f844e516d8 chore: AUTHOR_MAP entry for agentlinker 2026-05-05 06:07:44 -07:00
Teknium
c7fc5af122 chore: AUTHOR_MAP entry for tangyuanjc 2026-05-05 06:04:20 -07:00
Teknium
005b2f4c5d chore: AUTHOR_MAP entry for beardthelion 2026-05-05 05:46:16 -07:00
Teknium
fe8560fc12
feat(api-server): X-Hermes-Session-Key header for long-term memory scoping (#20199)
* feat(api-server): X-Hermes-Session-Key header for long-term memory scoping

API Server integrations (Open WebUI, custom web UIs) can now pass a stable
per-channel identifier via X-Hermes-Session-Key that scopes long-term memory
(Honcho, etc.) independently of the transcript-scoped X-Hermes-Session-Id.
This matches the native gateway's session_key / session_id split: one stable
key per assistant channel, many independent transcripts that rotate on /new.

- _create_agent and _run_agent accept gateway_session_key and pass it to
  AIAgent(gateway_session_key=...), which is already honored by the Honcho
  memory provider (plugins/memory/honcho/client.py resolve_session_name).
- New shared helper _parse_session_key_header applies the same API-key
  gate, control-character sanitization, and a 256-char length cap as the
  existing session-id header.
- All three agent endpoints honor the header: /v1/chat/completions,
  /v1/responses, /v1/runs. JSON and SSE responses echo it back.
- /v1/capabilities advertises session_key_header so clients can
  feature-detect.

Closes #20060.

Co-authored-by: Andy Stewart <lazycat.manatee@gmail.com>

* chore: AUTHOR_MAP entry for manateelazycat

---------

Co-authored-by: Andy Stewart <lazycat.manatee@gmail.com>
2026-05-05 05:34:47 -07:00
Teknium
436672de0e
feat(curator): add archive and prune subcommands (#20200)
* fix(curator): protect hub skills by frontmatter name

* test(skill_usage): add mark_agent_created to regression test

The cherry-picked test predates #19618/#19621 which rewrote
list_agent_created_skill_names() to require an explicit
created_by: 'agent' provenance marker. Without mark_agent_created(),
my-skill is excluded from the list and the positive assertion fails.

* feat(curator): add archive and prune subcommands

Adds 'hermes curator archive <skill>' and 'hermes curator prune
[--days N] [--yes] [--dry-run]' alongside the existing status, run,
pause, resume, pin, unpin, restore, backup, rollback verbs.

These are the two genuinely new user-facing verbs requested in #19384.
The other verbs proposed there ('stats' and 'restore') already exist
as 'curator status' and 'curator restore', so no duplicate surface is
added — all skill lifecycle commands live under the single 'hermes
curator' namespace.

- archive: manual archive of an agent-created skill. Refuses pinned
  skills with a hint pointing at 'hermes curator unpin'.
- prune: bulk-archive unpinned skills idle for >= N days (default 90).
  Falls back to created_at when last_activity_at is null so never-used
  skills can still be pruned. --dry-run previews, --yes skips prompt.

Adapted from @elmatadorgh's PR #19454 which placed the same verbs
under 'hermes skills' with a separate hermes_cli/skills_config.py
handler and rich table for stats. The 'stats' and 'restore' parts of
that PR duplicated existing surface, so only archive and prune are
kept, rewritten to match hermes_cli/curator.py's existing plain-text
handler style. Tests rewritten from scratch against the new handlers.

Closes #19384

Co-authored-by: elmatadorgh <coktinbaran5@gmail.com>

---------

Co-authored-by: LeonSGP43 <cine.dreamer.one@gmail.com>
Co-authored-by: elmatadorgh <coktinbaran5@gmail.com>
2026-05-05 05:15:54 -07:00
Teknium
4f76166cf0 chore: AUTHOR_MAP entry for qxxaa 2026-05-05 05:01:12 -07:00