Commit Graph

261 Commits

Author SHA1 Message Date
Teknium
9a655ff57b chore(release): map fr@tecompanytea.com → ifrederico 2026-04-21 01:31:58 -07:00
Teknium
517f5e2639 chore(release): map abdi.moya@gmail.com -> AxDSan for release notes 2026-04-21 01:28:32 -07:00
opriz
cbe29db774 fix(gateway): prevent --replace race condition causing multiple instances
When starting the gateway with --replace, concurrent invocations could
leave multiple instances running simultaneously. This happened because
write_pid_file() used a plain overwrite, so the second racer would
silently replace the first process's PID record.

Changes:
- gateway/status.py: write_pid_file() now uses atomic O_CREAT|O_EXCL
  creation. If the file already exists, it raises FileExistsError,
  allowing exactly one process to win the race.
- gateway/run.py: before writing the PID file, re-check get_running_pid()
  and catch FileExistsError from write_pid_file(). In both cases, stop
  the runner and return False so the process exits cleanly.

Fixes #11718
2026-04-21 00:43:50 -07:00
Teknium
cecf84daf7 fix: extend hostname-match provider detection across remaining call sites
Aslaaen's fix in the original PR covered _detect_api_mode_for_url and the
two openai/xai sites in run_agent.py. This finishes the sweep: the same
substring-match false-positive class (e.g. https://api.openai.com.evil/v1,
https://proxy/api.openai.com/v1, https://api.anthropic.com.example/v1)
existed in eight more call sites, and the hostname helper was duplicated
in two modules.

- utils: add shared base_url_hostname() (single source of truth).
- hermes_cli/runtime_provider, run_agent: drop local duplicates, import
  from utils. Reuse the cached AIAgent._base_url_hostname attribute
  everywhere it's already populated.
- agent/auxiliary_client: switch codex-wrap auto-detect, max_completion_tokens
  gate (auxiliary_max_tokens_param), and custom-endpoint max_tokens kwarg
  selection to hostname equality.
- run_agent: native-anthropic check in the Claude-style model branch
  and in the AIAgent init provider-auto-detect branch.
- agent/model_metadata: Anthropic /v1/models context-length lookup.
- hermes_cli/providers.determine_api_mode: anthropic / openai URL
  heuristics for custom/unknown providers (the /anthropic path-suffix
  convention for third-party gateways is preserved).
- tools/delegate_tool: anthropic detection for delegated subagent
  runtimes.
- hermes_cli/setup, hermes_cli/tools_config: setup-wizard vision-endpoint
  native-OpenAI detection (paired with deduping the repeated check into
  a single is_native_openai boolean per branch).

Tests:
- tests/test_base_url_hostname.py covers the helper directly
  (path-containing-host, host-suffix, trailing dot, port, case).
- tests/hermes_cli/test_determine_api_mode_hostname.py adds the same
  regression class for determine_api_mode, plus a test that the
  /anthropic third-party gateway convention still wins.

Also: add asslaenn5@gmail.com → Aslaaen to scripts/release.py AUTHOR_MAP.
2026-04-20 22:14:29 -07:00
Teknium
5125a78283 chore(release): map yukipukikedy@gmail.com to Yukipukii1 2026-04-20 22:13:07 -07:00
jerilynzheng
e1b29c474e chore: register contributor in AUTHOR_MAP for release-note attribution
Adds zheng.jerilyn@gmail.com → jerilynzheng to scripts/release.py so
the check-attribution CI workflow passes.
2026-04-20 21:02:28 -07:00
Teknium
34c5c2538e
chore: map Es1la contributor email for AUTHOR_MAP (#13294)
Credit preserved for PR #13270 (WhatsApp Windows disconnect fix).
2026-04-20 20:53:10 -07:00
Teknium
5031aa37a2 chore(release): map mavrickdeveloper email for attribution 2026-04-20 20:52:50 -07:00
Teknium
e00d9630c5 fix: thread api_key through ollama num_ctx probe + author map
Follow-up for salvaged PR #3185:
- run_agent.py: pass self.api_key to query_ollama_num_ctx() so Ollama
  behind an auth proxy (same issue class as the LM Studio fix) can be
  probed successfully.
- scripts/release.py AUTHOR_MAP: map @tannerfokkens-maker's local-hostname
  commit email.
2026-04-20 20:51:56 -07:00
Teknium
36e8435d3e fix: follow-up for salvaged PRs #6293, #7387, #9091, #13131
- Fix duplicate 'timezone' import in e2e conftest
- Fix test_text_before_command_not_detected asserting send() is awaited
  when no agent is present in mock setup (text messages don't produce
  command output)
2026-04-20 14:56:04 -07:00
cdanis
4a424f1fbb feat(send_message): add media delivery support for Signal
Cherry-picked from PR #13159 by @cdanis.

Adds native media attachment delivery to Signal via signal-cli JSON-RPC
attachments param. Signal messages with media now follow the same
early-return pattern as Telegram/Discord/Matrix — attachments are sent
only with the last chunk to avoid duplicates.

Follow-up fixes on top of the original PR:
- Moved Signal into its own early-return block above the restriction
  check (matches Telegram/Discord/Matrix pattern)
- Fixed media_files being sent on every chunk in the generic loop
- Restored restriction/warning guards to simple form (Signal exits early)
- Fixed non-hermetic test writing to /tmp instead of tmp_path
2026-04-20 13:24:15 -07:00
Teknium
5a2118a70b test: add _resolve_path tests + AUTHOR_MAP entry for aniruddhaadak80 2026-04-20 12:29:31 -07:00
Teknium
f01e65196a chore: add MassiveMassimo to AUTHOR_MAP 2026-04-20 11:56:19 -07:00
Mibayy
3273f301b7 fix(stt): map cloud-only model names to valid local size for faster-whisper (#2544)
Cherry-picked from PR #2545 by @Mibayy.

The setup wizard could leave stt.model: "whisper-1" in config.yaml.
When using the local faster-whisper provider, this crashed with
"Invalid model size 'whisper-1'". Voice messages were silently ignored.

_normalize_local_model() now detects cloud-only names (whisper-1,
gpt-4o-transcribe, etc.) and maps them to the default local model
with a warning. Valid local sizes (tiny, base, small, medium, large-v3)
pass through unchanged.

- Renamed _normalize_local_command_model -> _normalize_local_model
  (backward-compat wrapper preserved)
- 6 new tests including integration test
- Added lowercase AUTHOR_MAP alias for @Mibayy

Closes #2544
2026-04-20 05:18:48 -07:00
Teknium
9725b452a1 fix: extract _repair_tool_call_arguments helper, add tests, bound loop
Follow-up for PR #12252 salvage:
- Extract 75-line inline repair block to _repair_tool_call_arguments()
  module-level helper for testability and readability
- Remove redundant 'import re as _re' (re already imported at line 33)
- Bound the while-True excess-delimiter removal loop to 50 iterations
- Add 17 tests covering all 6 repair stages
- Add sirEven to AUTHOR_MAP in release.py
2026-04-20 05:12:55 -07:00
Sanjays2402
570f8bab8f fix(compression): exclude completion tokens from compression trigger (#12026)
Cherry-picked from PR #12481 by @Sanjays2402.

Reasoning models (GLM-5.1, QwQ, DeepSeek R1) inflate completion_tokens
with internal thinking tokens. The compression trigger summed
prompt_tokens + completion_tokens, causing premature compression at ~42%
actual context usage instead of the configured 50% threshold.

Now uses only prompt_tokens — completion tokens don't consume context
window space for the next API call.

- 3 new regression tests
- Added AUTHOR_MAP entry for @Sanjays2402

Closes #12026
2026-04-20 05:12:10 -07:00
Teknium
34ae13e6ed chore: add jplew to AUTHOR_MAP 2026-04-20 05:10:23 -07:00
PStarH
00192d51f1 fix(install): quote PYTHON_PATH and UV_CMD for paths with spaces on macOS (#10009)
Cherry-picked from PR #10019 by @PStarH.

On macOS, uv stores Python in ~/Library/Application Support/uv/...
which contains a space. Unquoted $PYTHON_PATH and $UV_CMD caused
word-splitting under set -e, silently aborting install.sh.

Quotes all variable expansions in check_python():
- "$PYTHON_PATH" in command invocations
- "$UV_CMD" in uv calls
- Outer quotes on $(...) assignments

Closes #10009
2026-04-20 05:03:14 -07:00
houguokun
6cdab70320 fix(batch_runner): mark discarded no-reasoning prompts as completed (#9950)
Cherry-picked from PR #10005 by @houziershi.

Discarded prompts (has_any_reasoning=False) were skipped by `continue`
before being added to completed_in_batch. On --resume they were retried
forever. Now they are added to completed_in_batch before the continue.

- Added AUTHOR_MAP entry for @houziershi

Closes #9950
2026-04-20 04:56:06 -07:00
Teknium
3218d58fc5 chore(release): add Swift42 to AUTHOR_MAP 2026-04-20 04:15:04 -07:00
Teknium
9f22977fc0 chore(release): add haileymarshall to AUTHOR_MAP 2026-04-20 03:10:19 -07:00
Teknium
0cff992f0a chore(release): add alexzhu0 to AUTHOR_MAP 2026-04-20 03:07:32 -07:00
Teknium
649ef5c8f1 chore(release): add sjz-ks to AUTHOR_MAP 2026-04-20 03:04:06 -07:00
Teknium
8f4db7bbd5 chore(release): map withapurpose37@gmail.com -> StefanIsMe
Author mapping for the salvaged PR #8191 contributor.
2026-04-20 02:59:57 -07:00
Teknium
2614586306 chore(release): add lumenradley to AUTHOR_MAP 2026-04-20 02:53:40 -07:00
Teknium
93f9db59b2 fix(doctor): update config validation for current auth.py API
Follow-up for #3171 cherry-pick — the contributor's validation block
called get_provider_credentials() which doesn't exist on current main.
Replaces it with get_auth_status() limited to API-key providers in
PROVIDER_REGISTRY so providers without a registry entry (openrouter,
anthropic, custom) don't trigger false 'not authenticated' failures.
Also runs the provider name through resolve_provider() so aliases like
'glm'/'moonshot' validate correctly.

Adds StefanIsMe to AUTHOR_MAP.
2026-04-20 02:41:25 -07:00
Teknium
c470a325f7 chore(release): add Linux2010 and elmatadorgh to AUTHOR_MAP 2026-04-20 02:40:20 -07:00
Teknium
acca428c81 chore: add haileymarshall to AUTHOR_MAP 2026-04-20 02:10:53 -07:00
Teknium
440764e013 chore(release): add salt-555 to AUTHOR_MAP 2026-04-20 00:47:40 -07:00
Teknium
edf1aecacd chore(release): add cresslank to AUTHOR_MAP 2026-04-20 00:42:10 -07:00
kshitijk4poor
098d554aac test: cover vision config temperature wiring\n\n- add regression tests for auxiliary.vision.temperature and timeout\n- add bugkill3r to AUTHOR_MAP for the salvaged commit 2026-04-20 00:32:09 -07:00
JackJin
5157f5427f chore(release): add jackjin1997 qq email to AUTHOR_MAP 2026-04-19 22:46:47 -07:00
Teknium
65a31ee0d5
fix(anthropic): complete third-party Anthropic-compatible provider support (#12846)
Third-party gateways that speak the native Anthropic protocol (MiniMax,
Zhipu GLM, Alibaba DashScope, Kimi, LiteLLM proxies) now work end-to-end
with the same feature set as direct api.anthropic.com callers.  Synthesizes
eight stale community PRs into one consolidated change.

Five fixes:

- URL detection: consolidate three inline `endswith("/anthropic")`
  checks in runtime_provider.py into the shared _detect_api_mode_for_url
  helper.  Third-party /anthropic endpoints now auto-resolve to
  api_mode=anthropic_messages via one code path instead of three.

- OAuth leak-guard: all five sites that assign `_is_anthropic_oauth`
  (__init__, switch_model, _try_refresh_anthropic_client_credentials,
  _swap_credential, _try_activate_fallback) now gate on
  `provider == "anthropic"` so a stale ANTHROPIC_TOKEN never trips
  Claude-Code identity injection on third-party endpoints.  Previously
  only 2 of 5 sites were guarded.

- Prompt caching: new method `_anthropic_prompt_cache_policy()` returns
  `(should_cache, use_native_layout)` per endpoint.  Replaces three
  inline conditions and the `native_anthropic=(api_mode=='anthropic_messages')`
  call-site flag.  Native Anthropic and third-party Anthropic gateways
  both get the native cache_control layout; OpenRouter gets envelope
  layout.  Layout is persisted in `_primary_runtime` so fallback
  restoration preserves the per-endpoint choice.

- Auxiliary client: `_try_custom_endpoint` honors
  `api_mode=anthropic_messages` and builds `AnthropicAuxiliaryClient`
  instead of silently downgrading to an OpenAI-wire client.  Degrades
  gracefully to OpenAI-wire when the anthropic SDK isn't installed.

- Config hygiene: `_update_config_for_provider` (hermes_cli/auth.py)
  clears stale `api_key`/`api_mode` when switching to a built-in
  provider, so a previous MiniMax custom endpoint's credentials can't
  leak into a later OpenRouter session.

- Truncation continuation: length-continuation and tool-call-truncation
  retry now cover `anthropic_messages` in addition to `chat_completions`
  and `bedrock_converse`.  Reuses the existing `_build_assistant_message`
  path via `normalize_anthropic_response()` so the interim message
  shape is byte-identical to the non-truncated path.

Tests: 6 new files, 42 test cases.  Targeted run + tests/run_agent,
tests/agent, tests/hermes_cli all pass (4554 passed).

Synthesized from (credits preserved via Co-authored-by trailers):
  #7410  @nocoo           — URL detection helper
  #7393  @keyuyuan        — OAuth 5-site guard
  #7367  @n-WN            — OAuth guard (narrower cousin, kept comment)
  #8636  @sgaofen         — caching helper + native-vs-proxy layout split
  #10954 @Only-Code-A     — caching on anthropic_messages+Claude
  #7648  @zhongyueming1121 — aux client anthropic_messages branch
  #6096  @hansnow         — /model switch clears stale api_mode
  #9691  @TroyMitchell911 — anthropic_messages truncation continuation

Closes: #7366, #8294 (third-party Anthropic identity + caching).
Supersedes: #7410, #7367, #7393, #8636, #10954, #7648, #6096, #9691.
Rejects:    #9621 (OpenAI-wire caching with incomplete blocklist — risky),
            #7242 (superseded by #9691, stale branch),
            #8321 (targets smart_model_routing which was removed in #12732).

Co-authored-by: nocoo <nocoo@users.noreply.github.com>
Co-authored-by: Keyu Yuan <leoyuan0099@gmail.com>
Co-authored-by: Zoee <30841158+n-WN@users.noreply.github.com>
Co-authored-by: sgaofen <135070653+sgaofen@users.noreply.github.com>
Co-authored-by: Only-Code-A <bxzt2006@163.com>
Co-authored-by: zhongyueming <mygamez@163.com>
Co-authored-by: Xiaohan Li <hansnow@users.noreply.github.com>
Co-authored-by: Troy Mitchell <i@troy-y.org>
2026-04-19 22:43:09 -07:00
Teknium
be3bec55be chore(release): add draix to AUTHOR_MAP 2026-04-19 22:16:37 -07:00
Teknium
09195be979 docs: repoint tui.md skin reference to features/skins.md
The example-skin.yaml was removed as part of the stale docs cleanup.
Docusaurus features/skins.md covers the same material.

Also update AUTHOR_MAP for balyan.sid@gmail.com → alt-glitch (actual
GitHub login; balyansid returns 404).
2026-04-19 20:39:49 -07:00
Teknium
5d01fc4e6f chore(attribution): add taeng02@icloud.com → taeng0204
Salvaged commit 0c652e9b in this branch is authored by taeng02@icloud.com.
check-attribution CI blocks PRs whose new author emails aren't in
AUTHOR_MAP, so add the mapping to unblock #12680's salvage PR.

GitHub username confirmed via `gh api users/taeng0204` (Taein Lim).
2026-04-19 18:54:35 -07:00
Teknium
af53039dbc chore(release): add etherman-os and mark-ramsell to AUTHOR_MAP 2026-04-19 16:47:20 -07:00
Teknium
a3a4932405
fix(mcp-oauth): bidirectional auth_flow bridge + absolute expires_at (salvage #12025) (#12717)
* [verified] fix(mcp-oauth): bridge httpx auth_flow bidirectional generator

HermesMCPOAuthProvider.async_auth_flow wrapped the SDK's auth_flow with
'async for item in super().async_auth_flow(request): yield item', which
discards httpx's .asend(response) values and resumes the inner generator
with None. This broke every OAuth MCP server on the first HTTP response
with 'NoneType' object has no attribute 'status_code' crashing at
mcp/client/auth/oauth2.py:505.

Replace with a manual bridge that forwards .asend() values into the
inner generator, preserving httpx's bidirectional auth_flow contract.

Add tests/tools/test_mcp_oauth_bidirectional.py with two regression
tests that drive the flow through real .asend() round-trips. These
catch the bug at the unit level; prior tests only exercised
_initialize() and disk-watching, never the full generator protocol.

Verified against BetterStack MCP:
  Before: 'Connection failed (11564ms): NoneType...' after 3 retries
  After:  'Connected (2416ms); Tools discovered: 83'

Regression from #11383.

* [verified] fix(mcp-oauth): seed token_expiry_time + pre-flight AS discovery on cold-load

PR #11383's consolidation fixed external-refresh reloading and 401 dedup
but left two latent bugs that surfaced on BetterStack and any other OAuth
MCP with a split-origin authorization server:

1. HermesTokenStorage persisted only a relative 'expires_in', which is
   meaningless after a process restart. The MCP SDK's OAuthContext
   does NOT seed token_expiry_time in _initialize, so is_token_valid()
   returned True for any reloaded token regardless of age. Expired
   tokens shipped to servers, and app-level auth failures (e.g.
   BetterStack's 'No teams found. Please check your authentication.')
   were invisible to the transport-layer 401 handler.

2. Even once preemptive refresh did fire, the SDK's _refresh_token
   falls back to {server_url}/token when oauth_metadata isn't cached.
   For providers whose AS is at a different origin (BetterStack:
   mcp.betterstack.com for MCP, betterstack.com/oauth/token for the
   token endpoint), that fallback 404s and drops into full browser
   re-auth on every process restart.

Fix set:

- HermesTokenStorage.set_tokens persists an absolute wall-clock
  expires_at alongside the SDK's OAuthToken JSON (time.time() + TTL
  at write time).
- HermesTokenStorage.get_tokens reconstructs expires_in from
  max(expires_at - now, 0), clamping expired tokens to zero TTL.
  Legacy files without expires_at fall back to file-mtime as a
  best-effort wall-clock proxy, self-healing on the next set_tokens.
- HermesMCPOAuthProvider._initialize calls super(), then
  update_token_expiry on the reloaded tokens so token_expiry_time
  reflects actual remaining TTL. If tokens are loaded but
  oauth_metadata is missing, pre-flight PRM + ASM discovery runs
  via httpx.AsyncClient using the MCP SDK's own URL builders and
  response handlers (build_protected_resource_metadata_discovery_urls,
  handle_auth_metadata_response, etc.) so the SDK sees the correct
  token_endpoint before the first refresh attempt. Pre-flight is
  skipped when there are no stored tokens to keep fresh-install
  paths zero-cost.

Test coverage (tests/tools/test_mcp_oauth_cold_load_expiry.py):
- set_tokens persists absolute expires_at
- set_tokens skips expires_at when token has no expires_in
- get_tokens round-trips expires_at -> remaining expires_in
- expired tokens reload with expires_in=0
- legacy files without expires_at fall back to mtime proxy
- _initialize seeds token_expiry_time from stored tokens
- _initialize flags expired-on-disk tokens as is_token_valid=False
- _initialize pre-flights PRM + ASM discovery with mock transport
- _initialize skips pre-flight when no tokens are stored

Verified against BetterStack MCP:
  hermes mcp test betterstack -> Connected (2508ms), 83 tools
  mcp_betterstack_telemetry_list_teams_tool -> real team data, not
    'No teams found. Please check your authentication.'

Reference: mcp-oauth-token-diagnosis skill, Fix A.

* chore: map hermes@noushq.ai to benbarclay in AUTHOR_MAP

Needed for CI attribution check on cherry-picked commits from PR #12025.

---------

Co-authored-by: Hermes Agent <hermes@noushq.ai>
2026-04-19 16:31:07 -07:00
Teknium
13febe60ca chore(release): add dodo-reach to AUTHOR_MAP 2026-04-19 11:57:51 -07:00
Teknium
d48d6fadff test(run_agent): pin proxy-env forwarding through keepalive transport
Adds a regression guard for the #11277 → proxy-bypass regression fixed in
42b394c3. With HTTPS_PROXY / HTTP_PROXY / ALL_PROXY set, the custom httpx
transport used for TCP keepalives must still route requests through an
HTTPProxy pool; without proxy env, no HTTPProxy mount should exist.

Also maps zrc <zhurongcheng@rcrai.com> → heykb in scripts/release.py
AUTHOR_MAP so the salvage PR passes the author-attribution CI check.
2026-04-19 11:44:43 -07:00
Teknium
eb247e6c0a chore: add bingo906 numeric qq email to AUTHOR_MAP
Maps 906014227@qq.com → bingo906 for PR #12450 attribution in the
weekly release notes.
2026-04-19 11:36:04 -07:00
Teknium
5a23f3291a fix(model_switch): section 3 base_url/model/dedup follow-up
On top of the salvaged PR #12505 (Jason/farion1231, which adds dict-format
models: enumeration to both sections), three section-3 refinements from
competing PR #11534 (YangManBOBO):

- accept base_url as canonical (matches Hermes's writer and custom_providers
  entries); keep api/url as fallbacks for legacy/hand-edited configs
- accept singular model as a default_model synonym, matching custom_providers
- add seen_slugs guard so the same provider slug appearing in both
  providers: dict and custom_providers: list emits exactly one picker row
  (providers: dict wins since section 3 runs first)

Two regression tests cover the new behavior. AUTHOR_MAP entry added for
farion1231 so CI doesn't reject the cherry-picked commit.
2026-04-19 11:07:29 -07:00
Teknium
a3b76ae36d
chore(attribution): add AUTHOR_MAP entry for Mibayy
Adds the Mibayy noreply email to the AUTHOR_MAP so CI attribution checks
pass for the #3884 maps skill feat commit (7fa01faf).
2026-04-19 05:19:51 -07:00
kshitijk4poor
4f0e49dc7b chore: add sgaofen to AUTHOR_MAP 2026-04-19 03:30:03 -07:00
kshitijk4poor
0a8d48809f chore: add LeonSGP43 numeric noreply email to AUTHOR_MAP
The cherry-picked commit from #11434 uses the 154585401+ prefixed
noreply format. Add it alongside the existing bare entry so the
contributor audit passes.
2026-04-18 22:50:55 -07:00
Teknium
41560192c4
chore(attribution): add AUTHOR_MAP entry for nish3451
Adds the nish3451 noreply email to the AUTHOR_MAP so CI attribution checks
pass for the #6100 Telegram DM fallback fix merged in 1a9a2d7f.
2026-04-18 18:52:41 -07:00
Teknium
11ee87e605 chore(attribution): add AUTHOR_MAP entry for kshitijk4poor@gmail.com
Covers the non-noreply email used on commit dd3e6424 (rename of the
TouchDesigner skill to touchdesigner-mcp).
2026-04-18 17:43:42 -07:00
LVT382009
f7af90e2da fix: wire _ephemeral_max_output_tokens into chat_completions and add NVIDIA NIM default
Based on #12152 by @LVT382009.

Two fixes to run_agent.py:

1. _ephemeral_max_output_tokens consumption in chat_completions path:
   The error-recovery ephemeral override was only consumed in the
   anthropic_messages branch of _build_api_kwargs.  All chat_completions
   providers (OpenRouter, NVIDIA NIM, Qwen, Alibaba, custom, etc.)
   silently ignored it.  Now consumed at highest priority, matching the
   anthropic pattern.

2. NVIDIA NIM max_tokens default (16384):
   NVIDIA NIM falls back to a very low internal default when max_tokens
   is omitted, causing models like GLM-4.7 to truncate immediately
   (thinking tokens exhaust the budget before the response starts).

3. Progressive length-continuation boost:
   When finish_reason='length' triggers a continuation retry, the output
   budget now grows progressively (2x base on retry 1, 3x on retry 2,
   capped at 32768) via _ephemeral_max_output_tokens.  Previously the
   retry loop just re-sent the same token limit on all 3 attempts.
2026-04-18 12:51:30 -07:00
jarvischer
0f778f7768 fix: prevent tool name duplication in streaming accumulator (MiniMax/NVIDIA NIM)
Based on #11984 by @maxchernin.  Fixes #8259.

Some providers (MiniMax M2.7 via NVIDIA NIM) resend the full function
name in every streaming chunk instead of only the first.  The old
accumulator used += which concatenated them into 'read_fileread_file'.

Changed to simple assignment (=), matching the OpenAI Node SDK, LiteLLM,
and Vercel AI SDK patterns.  Function names are atomic identifiers
delivered complete — no provider splits them across chunks, so
concatenation was never correct semantics.
2026-04-18 12:50:32 -07:00
Teknium
0bebf5b948 chore(attribution): add AUTHOR_MAP entry for Honghua Yang (honghua) 2026-04-18 12:40:56 -07:00
Teknium
b73ebfee30 chore(attribution): add AUTHOR_MAP entry for Jim Liu (JimLiu)
Maps junminliu@gmail.com → JimLiu for the baoyu-infographic skill port
co-author attribution.
2026-04-18 12:32:16 -07:00
teknium1
3b69b2fd61 test(session-search): regression coverage for CJK LIKE fallback
Twelve tests under TestCJKSearchFallback guarding:
 - CJK detection across Chinese/Japanese/Korean/Hiragana/Katakana ranges
   (including the full Hangul syllables block \uac00-\ud7af, to catch
   the shorter-range typo from one of the duplicate PRs)
 - Substring match for multi-char Chinese, Japanese, Korean queries
 - Filter preservation (source_filter, exclude_sources, role_filter)
   in the LIKE path — guards against the SQL-builder bug from another
   duplicate PR where filter clauses landed after LIMIT/OFFSET
 - Snippet centered on the matched term (instr-based substr window),
   not the leading 200 chars of content
 - English fast-path untouched
 - Empty/no-match cases
 - Mixed CJK+English queries

Also:
 - hermes_state.py: LIKE-fallback snippet is now
   `substr(content, max(1, instr(content, ?) - 40), 120)`, centered on
   the match instead of the whole-content default. Credit goes to
   @iamagenius00 for the snippet idea in PR #11517.
 - scripts/release.py: add @iamagenius00 to AUTHOR_MAP so future
   release attribution resolves cleanly.

Refs #11511, #11516, #11517, #11541.

Co-authored-by: iamagenius00 <iamagenius00@users.noreply.github.com>
2026-04-18 01:57:57 -07:00
Teknium
c20e236b71 chore: map AviArora02-commits author email in release AUTHOR_MAP 2026-04-17 21:30:17 -07:00
Teknium
38436eb4e3 chore(release): add pedh to AUTHOR_MAP 2026-04-17 19:26:53 -07:00
Teknium
213e39463b chore(release): add akhater to AUTHOR_MAP
Contributor of PR #11858 (nous OAuth providers mirror fix).  CI
blocks releases on unmapped author emails.
2026-04-17 19:13:40 -07:00
Teknium
b449a0e049 fix(feishu-comment): use get_hermes_home(); drop dead asyncio wrapper; AUTHOR_MAP
Follow-up polish on top of the cherry-picked #11023 commit.

- feishu_comment_rules.py: replace import-time "~/.hermes" expanduser fallback
  with get_hermes_home() from hermes_constants (canonical, profile-safe).
- tools/feishu_doc_tool.py, tools/feishu_drive_tool.py: drop the
  asyncio.get_event_loop().run_until_complete(asyncio.to_thread(...)) dance.
  Tool handlers run synchronously in a worker thread with no running loop, so
  the RuntimeError branch was always the one that executed. Calls client.request
  directly now. Unused asyncio import removed.
- tests/gateway/test_feishu.py: add register_p2_customized_event to the mock
  EventDispatcher builder so the existing adapter test matches the new handler
  registration for drive.notice.comment_add_v1.
- scripts/release.py: map liujinkun@bytedance.com -> liujinkun2025 for
  contributor attribution on release notes.
2026-04-17 19:04:11 -07:00
Teknium
bb85404b16 chore: add Sara Reynolds to AUTHOR_MAP 2026-04-17 18:58:29 -07:00
WideLee
287d3e12c7 chore: add author map 2026-04-17 15:31:14 -07:00
Teknium
f362083c64 fix(providers): complete NVIDIA NIM parity with other providers
Follow-up on the native NVIDIA NIM provider salvage. The original PR wired
PROVIDER_REGISTRY + HERMES_OVERLAYS correctly but missed several touchpoints
required for full parity with other OpenAI-compatible providers (xai,
huggingface, deepseek, zai).

Gaps closed:

- hermes_cli/main.py:
  - Add 'nvidia' to the _model_flow_api_key_provider dispatch tuple so
    selecting 'NVIDIA NIM' in `hermes model` actually runs the api-key
    provider flow (previously fell through silently).
  - Add 'nvidia' to `hermes chat --provider` argparse choices so the
    documented test command (`hermes chat --provider nvidia --model ...`)
    parses successfully.

- hermes_cli/config.py: Register NVIDIA_API_KEY and NVIDIA_BASE_URL in
  OPTIONAL_ENV_VARS so setup wizard can prompt for them and they're
  auto-added to the subprocess env blocklist.

- hermes_cli/doctor.py: Add NVIDIA NIM row to `_apikey_providers` so
  `hermes doctor` probes https://integrate.api.nvidia.com/v1/models.

- hermes_cli/dump.py: Add NVIDIA_API_KEY → 'nvidia' mapping for
  `hermes dump` credential masking.

- tests/tools/test_local_env_blocklist.py: Extend registry_vars fixture
  with NVIDIA_API_KEY to verify it's blocked from leaking into subprocesses.

- agent/model_metadata.py: Add 'nemotron' → 131072 context-length entry
  so all Nemotron variants get 128K context via substring match (rather
  than falling back to MINIMUM_CONTEXT_LENGTH).

- hermes_cli/models.py: Fix hallucinated model ID
  'nvidia/nemotron-3-nano-8b-a4b' → 'nvidia/nemotron-3-nano-30b-a3b'
  (verified against live integrate.api.nvidia.com/v1/models catalog).
  Expand curated list from 5 to 9 agentic models mapping to OpenRouter
  defaults per provider-guide convention: add qwen3.5-397b-a17b,
  deepseek-v3.2, llama-3.3-nemotron-super-49b-v1.5, gpt-oss-120b.

- cli-config.yaml.example: Document 'nvidia' provider option.

- scripts/release.py: Map asurla@nvidia.com → anniesurla in AUTHOR_MAP
  for CI attribution.

E2E verified: `hermes chat --provider nvidia ...` now reaches NVIDIA's
endpoint (returns 401 with bogus key instead of argparse error);
`hermes doctor` detects NVIDIA NIM when NVIDIA_API_KEY is set.
2026-04-17 13:47:46 -07:00
Henkey
d49126b987 fix(release): map HenkDz contributor email 2026-04-17 13:29:26 -07:00
Teknium
6ea7386a6f chore: map memosr, anthhub, shenuu, xiayh0107 emails to AUTHOR_MAP 2026-04-17 06:50:36 -07:00
Teknium
c7334b4a50 chore(release): map @Hypn0sis and @OwenYWT to AUTHOR_MAP 2026-04-17 06:46:52 -07:00
Teknium
fc04f83062 chore(release): map jvcl author email for release notes 2026-04-17 06:33:21 -07:00
Teknium
fdf42d62a0 chore: map briandevans and LLQWQ emails to AUTHOR_MAP 2026-04-17 06:26:43 -07:00
Teknium
c60b6dc317 test(dingtalk): cover get_connected_platforms + null platform_toolsets
Follow-ups to the salvaged commits in this PR:

* gateway/config.py — strip trailing whitespace from youngDoo's diff
  (line 315 had ~140 trailing spaces).

* hermes_cli/tools_config.py — replace `config.get("platform_toolsets", {})`
  with `config.get("platform_toolsets") or {}`. Handles the case where the
  YAML key is present but explicitly null (parses as None, previously
  crashed with AttributeError on the next line's .get(platform)).
  Cherry-picked from yyq4193's #9003 with attribution.

* tests/gateway/test_config.py — 4 new tests for TestGetConnectedPlatforms
  covering DingTalk via extras, via env vars, disabled, and missing creds.

* tests/hermes_cli/test_tools_config.py — regression test for the null
  platform_toolsets edge case.

* scripts/release.py — add kagura-agent, youngDoo, yyq4193 to AUTHOR_MAP.

Co-authored-by: yyq4193 <39405770+yyq4193@users.noreply.github.com>
2026-04-17 06:26:18 -07:00
Teknium
ee95822e07 chore(release): map jz.pentest@gmail.com to @0xyg3n 2026-04-17 05:48:26 -07:00
Teknium
0741f22463 chore(release): map gnanasekaran.sekareee@gmail.com to @gnanam1990 2026-04-17 05:42:04 -07:00
Teknium
13f2d997b0 test(dingtalk): cover QR device-flow auth + OpenClaw branding disclosure
Adds 15 regression tests for hermes_cli/dingtalk_auth.py covering:
  * _api_post — network error mapping, errcode-nonzero mapping, success path
  * begin_registration — 2-step chain, missing-nonce/device_code/uri
    error cases
  * wait_for_registration_success — success path, missing-creds guard,
    on_waiting callback invocation
  * render_qr_to_terminal — returns False when qrcode missing, prints
    when available
  * Configuration — BASE_URL default + override, SOURCE default

Also adds a one-line disclosure in dingtalk_qr_auth() telling users
the scan page will be OpenClaw-branded. Interim measure: DingTalk's
registration portal is hardcoded to route all sources to /openapp/
registration/openClaw, so users see OpenClaw branding regardless of
what 'source' value we send. We keep 'openClaw' as the source token
until DingTalk-Real-AI registers a Hermes-specific template.

Also adds meng93 to scripts/release.py AUTHOR_MAP.
2026-04-17 05:08:07 -07:00
Teknium
08930a65ea chore: map Patrick Wang, Hedgeho9, Berny Linville emails to AUTHOR_MAP 2026-04-17 05:01:29 -07:00
Teknium
ca03e80348 chore: map LehaoLin email to AUTHOR_MAP for release script 2026-04-17 04:22:40 -07:00
dieutx
b594b30de4 fix(release): map dieutx email in author map 2026-04-17 04:22:40 -07:00
Teknium
aca81ac7bb test(dingtalk): cover require_mention + allowed_users gating
Adds 16 regression tests for the gating logic introduced in the
salvaged commit:

  * TestAllowedUsersGate — empty/wildcard/case-insensitive matching,
    staff_id vs sender_id, env var CSV population
  * TestMentionPatterns — compilation, case-insensitivity, invalid
    regex is skipped-not-raised, JSON env var, newline fallback
  * TestShouldProcessMessage — DM always accepted, group gating via
    require_mention / is_in_at_list / wake-word pattern / free_response_chats

Also adds yule975 to scripts/release.py AUTHOR_MAP (release CI blocks
unmapped emails).
2026-04-17 04:21:49 -07:00
Teknium
0231f8882b chore(release): add Asunfly to AUTHOR_MAP for #10070 salvage 2026-04-17 04:11:30 -07:00
Teknium
8b312248dc chore: map RucchiZ email to AUTHOR_MAP for release script 2026-04-17 04:09:21 -07:00
Teknium
5d929caa59 chore(release): map michel.belleau@malaiwah.com to @malaiwah 2026-04-17 04:08:42 -07:00
Teknium
3438d274f6 fix(dingtalk): repair _extract_text for dingtalk-stream >= 0.20 SDK shape
The cherry-picked SDK compat fix (previous commit) wired process() to
parse CallbackMessage.data into a ChatbotMessage, but _extract_text()
was still written against the pre-0.20 payload shape:

  * message.text changed from dict {content: ...} → TextContent object.
    The old code's str(text) fallback produced 'TextContent(content=...)'
    as the agent's input, so every received message came in mangled.
  * rich_text moved from message.rich_text (list) to
    message.rich_text_content.rich_text_list.

This preserves legacy fallbacks (dict-shaped text, bare rich_text list)
while handling the current SDK layout via hasattr(text, 'content').

Adds regression tests covering:
  * webhook domain allowlist (api.*, oapi.*, and hostile lookalikes)
  * _IncomingHandler.process is a coroutine function
  * _extract_text against TextContent object, dict, rich_text_content,
    legacy rich_text, and empty-message cases

Also adds kevinskysunny to scripts/release.py AUTHOR_MAP (release CI
blocks unmapped emails).
2026-04-17 00:52:35 -07:00
Teknium
816e3e3774 test(feishu): cover new SDK event handler registrations
Extends test_build_event_handler_registers_reaction_and_card_processors
to assert that register_p2_im_chat_access_event_bot_p2p_chat_entered_v1
and register_p2_im_message_recalled_v1 are called when building the
event handler, matching the production registrations.

Also adds Fatty911 to scripts/release.py AUTHOR_MAP for credit on the
salvaged event-handler fix.
2026-04-16 22:08:11 -07:00
Teknium
19c589a20b refactor(concept-diagrams): rename + tighten v1k22's skill for merge
Salvage of PR #11045 (original by v1k22). Changes on top of the
original commit:

- Rename 'architecture-visualization-svg-diagrams' -> 'concept-diagrams'
  to differentiate from the existing architecture-diagram skill.
  architecture-diagram stays as the dark-themed Cocoon-style option for
  software/infra; concept-diagrams covers physics, chemistry, math,
  engineering, physical objects, and educational visuals.
- Trigger description scoped to actual use cases; removed the 'always
  use this skill' language and long phrase-capture list to stop
  colliding with architecture-diagram, excalidraw, generative-widgets,
  manim-video.
- Default output is now a standalone self-contained HTML file (works
  offline, no server). The preview server is opt-in and no longer part
  of the default workflow.
- When the server IS used: bind to 127.0.0.1 instead of 0.0.0.0 (was a
  LAN exposure hazard on shared networks) and let the OS pick a free
  ephemeral port instead of hard-coding 22223 (collision prone).
- Shrink SKILL.md from 1540 to 353 lines by extracting reusable
  material into linked files:
    - templates/template.html (host page with full CSS design system)
    - references/physical-shape-cookbook.md
    - references/infrastructure-patterns.md
    - references/dashboard-patterns.md
  All 15 examples kept intact.
- Add dhandhalyabhavik@gmail.com -> v1k22 to AUTHOR_MAP.

Preserves v1k22's authorship on the underlying commit.
2026-04-16 20:39:55 -07:00
Teknium
7af9bf3a54
fix(feishu): queue inbound events when adapter loop not ready (#5499) (#11372)
Inbound Feishu messages arriving during brief windows when the adapter
loop is unavailable (startup/restart transitions, network-flap reconnect)
were silently dropped with a WARNING log. This matches the symptom in
issue #5499 — and users have reported seeing only a subset of their
messages reach the agent.

Fix: queue pending events in a thread-safe list and spawn a single
drainer thread that replays them once the loop becomes ready. Covers
these scenarios:

  * Queue events instead of dropping when loop is None/closed
  * Single drainer handles the full queue (not thread-per-event)
  * Thread-safe with threading.Lock on the queue and schedule flag
  * Handles mid-drain bursts (new events arrive while drainer is working)
  * Handles RuntimeError if loop closes between check and submit
  * Depth cap (1000) prevents unbounded growth during extended outages
  * Drops queue cleanly on disconnect rather than holding forever
  * Safety timeout (120s) prevents infinite retention on broken adapters

Based on the approach proposed in #4789 by milkoor, rewritten for
thread-safety and correctness.

Test plan:
  * 5 new unit tests (TestPendingInboundQueue) — all passing
  * E2E test with real asyncio loop + fake WS thread: 10-event burst
    before loop ready → all 10 delivered in order
  * E2E concurrent burst test: 20 events queued, 20 more arrive during
    drainer dispatch → all 40 delivered, no loss, no duplicates
  * All 111 existing feishu tests pass

Related: #5499, #4789

Co-authored-by: milkoor <milkoor@users.noreply.github.com>
2026-04-16 20:36:59 -07:00
Teknium
764536b684 chore(release): map mbelleau@Michels-MacBook-Pro.local to @malaiwah
Follow-up for #11272 so release notes attribute the RTP padding fix correctly.
2026-04-16 16:50:15 -07:00
asheriif
6c34bf3d00 fix(gateway): fix matrix read receipts 2026-04-16 13:18:12 -07:00
kshitijk4poor
37913d9109 chore: add Opus 4.7 PR contributors to AUTHOR_MAP
Add trevthefoolish, ziliangpeng, centripetal-star for the consolidated
Opus 4.7 salvage PR (#11107, #11145, #11152, #11157).
2026-04-16 10:48:20 -07:00
kshitij
7e3845ac50
chore: add bare noreply email for kshitijk4poor to AUTHOR_MAP (#11120)
The numbered form (82637225+kshitijk4poor@) was already mapped but
the bare form (kshitijk4poor@users.noreply.github.com) used by
cherry-pick commits was missing, causing check-attribution CI to fail.

Co-authored-by: kshitijk4poor <kshitijk4poor@users.noreply.github.com>
2026-04-16 09:22:04 -07:00
kshitij
0a9229c8c6
chore: add salvage PR contributors to AUTHOR_MAP (#11076)
Add 11 community contributors whose work was cherry-picked via
salvage PRs during the April 16 triage session. Without these
entries, contributor_audit strict mode fails for release attribution.

Contributors: sontianye, jackjin1997, danieldoderlein, lrawnsley,
taeuk178, ogzerber, cola-runner, ygd58, vominh1919, LeonSGP43,
Lubrsy706

Co-authored-by: kshitijk4poor <kshitijk4poor@users.noreply.github.com>
2026-04-16 07:44:41 -07:00
Teknium
f938fe460c chore: add iacker to AUTHOR_MAP 2026-04-16 06:49:57 -07:00
Teknium
dc7d47a6b8 chore: add GenKoKo to AUTHOR_MAP 2026-04-16 06:10:40 -07:00
Teknium
4b1cf77770 chore: add davetist to AUTHOR_MAP 2026-04-16 05:53:18 -07:00
Teknium
330ed12fb1 chore: add nosleepcassette to AUTHOR_MAP 2026-04-16 02:22:19 -07:00
Xowiek
77435c4f13 fix(gateway): use profile-aware Hermes paths in runtime hints 2026-04-15 17:52:03 -07:00
Teknium
a6ad8ace29 chore: add handsdiff to AUTHOR_MAP 2026-04-15 17:26:31 -07:00
Teknium
620c296b1d fix: discord mock setup and AUTHOR_MAP for channel_prompts tests
Move _ensure_discord_mock() from module level to _make_adapter() so it
doesn't poison sys.modules for other discord test files. Use
types.ModuleType instead of MagicMock for the mock module to avoid
auto-generated __file__ attribute confusing hasattr checks.

Add BrennerSpear to AUTHOR_MAP.
2026-04-15 16:31:28 -07:00
MestreY0d4-Uninter
f4724803b4 fix(runtime): surface malformed proxy env and base URL before client init
When proxy env vars (HTTP_PROXY, HTTPS_PROXY, ALL_PROXY) contain
malformed URLs — e.g. 'http://127.0.0.1:6153export' from a broken
shell config — the OpenAI/httpx client throws a cryptic 'Invalid port'
error that doesn't identify the offending variable.

Add _validate_proxy_env_urls() and _validate_base_url() in
auxiliary_client.py, called from resolve_provider_client() and
_create_openai_client() to fail fast with a clear, actionable error
message naming the broken env var or URL.

Closes #6360
Co-authored-by: MestreY0d4-Uninter <MestreY0d4-Uninter@users.noreply.github.com>
2026-04-15 16:10:53 -07:00
Ruzzgar
de3f8bc6ce fix terminal workdir validation for Windows paths 2026-04-15 15:06:51 -07:00
Teknium
eb3d928da6 chore: add counterposition to AUTHOR_MAP 2026-04-15 15:05:32 -07:00
Teknium
ddaadfb9f0 chore: add helix4u to AUTHOR_MAP 2026-04-15 15:04:14 -07:00
MestreY0d4-Uninter
902f1e6ede chore: add MestreY0d4-Uninter to AUTHOR_MAP and .mailmap 2026-04-15 15:03:28 -07:00
Junass1
096260ce78 fix(telegram): authorize update prompt callbacks 2026-04-15 14:54:23 -07:00
Teknium
d1d425e9d0 chore: add ZaynJarvis bytedance email to AUTHOR_MAP 2026-04-15 11:28:45 -07:00
ZaynJarvis
990030c26e feat: add contrib map 2026-04-15 11:28:45 -07:00
Teknium
23b87c8ca8 chore: add zons-zhaozhy to AUTHOR_MAP 2026-04-14 21:01:40 -07:00
Teknium
31d0620663 chore: add simon-marcus to AUTHOR_MAP 2026-04-14 20:51:52 -07:00
Greer Guthrie
498cb7a0fc chore(release): map greer guthrie attribution 2026-04-14 17:19:20 -07:00
Teknium
3ca7417c2a chore: add areu01or00 to AUTHOR_MAP 2026-04-14 16:55:48 -07:00
Teknium
9bbf7659e9 chore: add Roy-oss1 to AUTHOR_MAP 2026-04-14 14:22:11 -07:00
Teknium
8a002d4efc chore: add ChimingLiu to AUTHOR_MAP 2026-04-14 10:22:11 -07:00
Teknium
35424f8fc1 chore: add bennytimz to AUTHOR_MAP 2026-04-13 23:03:08 -07:00
Teknium
5719c1f391
fix: add 75 contributor email→username mappings + .mailmap (#9358)
Audit of all external contributor PRs revealed 97 commit emails
not mapped in AUTHOR_MAP, meaning contributors weren't properly
credited in release notes. Cross-referenced via:
- GitHub API email search (9 resolved before rate limit)
- Salvage PR body mentions (@username in descriptions)
- Git noreply email cross-reference (same person, both emails)
- GH contributor list username matching

Also adds .mailmap for git shortlog/log display consistency.

Remaining 22 unmapped emails need GH API resolution when rate
limit resets — the contributor_audit.py script will flag them.

Addresses ColourfulWhite's report about missing contributor tags.
2026-04-13 21:10:39 -07:00
Teknium
def8b959b8
fix: add contributor audit script + fix missed contributors (#9264)
Three problems fixed:

1. bobashopcashier missing from v0.9.0 contributor list despite
   authoring the gateway drain PR (#7290, salvaged into #7503).
   Their email (kennyx102@gmail.com) was missing from AUTHOR_MAP.

2. release.py only scanned git commit authors, missing Co-authored-by
   trailers. Now parse_coauthors() extracts trailers from commit bodies.

3. No mechanism to detect contributors from salvaged PRs (where original
   author only appears in PR description, not git log).

Changes:
- scripts/release.py: add kennyx102@gmail.com to AUTHOR_MAP, enhance
  get_commits() to parse Co-authored-by trailers, filter AI assistants
  (Claude, Copilot, Cursor Agent) from co-author lists
- scripts/contributor_audit.py: new script that cross-references git
  authors, co-author trailers, and salvaged PR descriptions. Reports
  unknown emails and contributors missing from release notes.
- RELEASE_v0.9.0.md: add bobashopcashier to community contributors

Usage:
  python scripts/contributor_audit.py --since-tag v2026.4.8
  python scripts/contributor_audit.py --since-tag v2026.4.8 --release-file RELEASE_v0.9.0.md
2026-04-13 16:31:27 -07:00
Teknium
d0ffb111c2
refactor: codebase-wide lint cleanup — unused imports, dead code, and inefficient patterns (#5821)
Comprehensive cleanup across 80 files based on automated (ruff, pyflakes, vulture)
and manual analysis of the entire codebase.

Changes by category:

Unused imports removed (~95 across 55 files):
- Removed genuinely unused imports from all major subsystems
- agent/, hermes_cli/, tools/, gateway/, plugins/, cron/
- Includes imports in try/except blocks that were truly unused
  (vs availability checks which were left alone)

Unused variables removed (~25):
- Removed dead variables: connected, inner, channels, last_exc,
  source, new_server_names, verify, pconfig, default_terminal,
  result, pending_handled, temperature, loop
- Dropped unused argparse subparser assignments in hermes_cli/main.py
  (12 instances of add_parser() where result was never used)

Dead code removed:
- run_agent.py: Removed dead ternary (None if False else None) and
  surrounding unreachable branch in identity fallback
- run_agent.py: Removed write-only attribute _last_reported_tool
- hermes_cli/providers.py: Removed dead @property decorator on
  module-level function (decorator has no effect outside a class)
- gateway/run.py: Removed unused MCP config load before reconnect
- gateway/platforms/slack.py: Removed dead SessionSource construction

Undefined name bugs fixed (would cause NameError at runtime):
- batch_runner.py: Added missing logger = logging.getLogger(__name__)
- tools/environments/daytona.py: Added missing Dict and Path imports

Unnecessary global statements removed (14):
- tools/terminal_tool.py: 5 functions declared global for dicts
  they only mutated via .pop()/[key]=value (no rebinding)
- tools/browser_tool.py: cleanup thread loop only reads flag
- tools/rl_training_tool.py: 4 functions only do dict mutations
- tools/mcp_oauth.py: only reads the global
- hermes_time.py: only reads cached values

Inefficient patterns fixed:
- startswith/endswith tuple form: 15 instances of
  x.startswith('a') or x.startswith('b') consolidated to
  x.startswith(('a', 'b'))
- len(x)==0 / len(x)>0: 13 instances replaced with pythonic
  truthiness checks (not x / bool(x))
- in dict.keys(): 5 instances simplified to in dict
- Redefined unused name: removed duplicate _strip_mdv2 import in
  send_message_tool.py

Other fixes:
- hermes_cli/doctor.py: Replaced undefined logger.debug() with pass
- hermes_cli/config.py: Consolidated chained .endswith() calls

Test results: 3934 passed, 17 failed (all pre-existing on main),
19 skipped. Zero regressions.
2026-04-07 10:25:31 -07:00
Teknium
e64b047663
chore: prepare Hermes for Homebrew packaging (#4099)
Co-authored-by: Yabuku-xD <78594762+Yabuku-xD@users.noreply.github.com>
2026-03-30 17:34:43 -07:00
teknium1
323ca70846 feat: add versioning infrastructure and release script
- Fix version mismatch: __init__.py had 'v1.0.0', pyproject.toml had '0.1.0'
  Now both use '0.1.0' (no v prefix — added in display code only)
- Add __release_date__ for CalVer date tracking alongside SemVer version
- Fix double-v bug in cmd_version (was printing 'vv1.0.0')
- Update banner title to show 'Hermes Agent v0.1.0 (2026.3.12)' format
- Update cli.py banner to match new format
- Add scripts/release.py: full release automation tool
  - Generates categorized changelogs from git history
  - Maps git authors to GitHub @mentions (70+ contributors)
  - Supports dry-run preview and --publish mode
  - Creates annotated CalVer git tags + GitHub Releases
  - Bumps semver in source files automatically
  - Usage: python scripts/release.py --bump minor --publish
- Add .release_notes.md to .gitignore

Versioning scheme: CalVer tags (v2026.3.12) + SemVer display (v0.1.0)
2026-03-12 01:35:47 -07:00