2026-03-12 01:35:47 -07:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
"""Hermes Agent Release Script
|
|
|
|
|
|
|
|
|
|
Generates changelogs and creates GitHub releases with CalVer tags.
|
|
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
# Preview changelog (dry run)
|
|
|
|
|
python scripts/release.py
|
|
|
|
|
|
|
|
|
|
# Preview with semver bump
|
|
|
|
|
python scripts/release.py --bump minor
|
|
|
|
|
|
|
|
|
|
# Create the release
|
|
|
|
|
python scripts/release.py --bump minor --publish
|
|
|
|
|
|
|
|
|
|
# First release (no previous tag)
|
|
|
|
|
python scripts/release.py --bump minor --publish --first-release
|
|
|
|
|
|
|
|
|
|
# Override CalVer date (e.g. for a belated release)
|
|
|
|
|
python scripts/release.py --bump minor --publish --date 2026.3.15
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import argparse
|
2026-05-14 20:15:37 -07:00
|
|
|
import json
|
2026-03-12 01:35:47 -07:00
|
|
|
import re
|
2026-03-30 17:34:43 -07:00
|
|
|
import shutil
|
2026-03-12 01:35:47 -07:00
|
|
|
import subprocess
|
|
|
|
|
import sys
|
|
|
|
|
from collections import defaultdict
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
|
|
|
VERSION_FILE = REPO_ROOT / "hermes_cli" / "__init__.py"
|
|
|
|
|
PYPROJECT_FILE = REPO_ROOT / "pyproject.toml"
|
|
|
|
|
|
2026-05-14 22:05:39 -07:00
|
|
|
# ACP Registry manifest must stay version-locked with pyproject.toml.
|
|
|
|
|
# tests/acp/test_registry_manifest.py enforces this lockstep so the release
|
|
|
|
|
# bump touches both files atomically.
|
2026-05-14 20:15:37 -07:00
|
|
|
ACP_REGISTRY_MANIFEST = REPO_ROOT / "acp_registry" / "agent.json"
|
|
|
|
|
|
2026-03-12 01:35:47 -07:00
|
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
|
|
|
# Git email → GitHub username mapping
|
|
|
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
# Auto-extracted from noreply emails + manual overrides
|
|
|
|
|
AUTHOR_MAP = {
|
2026-05-25 04:50:41 -07:00
|
|
|
"9592417+adam91holt@users.noreply.github.com": "adam91holt",
|
fix(agent): fallback immediately on provider content-policy blocks (#33883)
* fix(agent): fallback immediately on provider content-policy blocks
Provider safety-filter refusals (e.g. OpenAI Codex 'flagged for possible
cybersecurity risk', OpenAI moderation 'violates our usage policies',
Anthropic safety-system rejections, Azure content_filter) are
deterministic decisions about a specific prompt. Retrying the same
prompt up to api_max_retries times just reproduces the same refusal and
burns paid attempts before surfacing the generic 'API failed after 3
retries — <provider message>' to Telegram / cron with no indication that
the failure came from the model provider rather than Hermes itself.
Classify these as a new FailoverReason.content_policy_blocked
(non-retryable, should_fallback=True) and route them through the
existing is_client_error path so the loop:
- skips the 3x retry backoff
- activates a configured fallback model immediately
- emits a clear provider-safety message to the user (not the generic
'Non-retryable error (HTTP None)') and surfaces actionable guidance
when no fallback is configured (rephrase, narrow context, or set
fallback_model in hermes config)
- returns a final_response that explicitly tells the user this came
from the model provider, so gateway delivery is unambiguous and
cron last_status reflects the safety block rather than a vague
'agent reported failure'
Patterns are intentionally narrow — verbatim refusal phrasings keyed to
specific provider safety pipelines, not generic words like 'policy' or
'violation' that would collide with billing / format / auth errors.
Regression guards in test_18028_content_policy_blocked.py verify
billing 402s, generic 400s, and OpenRouter account-level
provider_policy_blocked remain distinct classifications.
Salvaged from #18164 onto current main (file restructure: loop logic
moved from run_agent.py to agent/conversation_loop.py, _emit_status →
_buffer_status), broadened patterns beyond the original OpenAI Codex
cybersecurity case to cover OpenAI moderation, Anthropic safety system,
and Azure content_filter; added user-actionable guidance and a clear
final_response so cron/gateway surfaces the policy block instead of a
generic non-retryable error, and added a regression-guard test module
mirroring the is_client_error predicate.
Addresses #18028.
Co-authored-by: Kuan-Chieh Huang <kchuang1015@users.noreply.github.com>
* chore: add kchuang1015 to AUTHOR_MAP
---------
Co-authored-by: Kuan-Chieh Huang <kchuang1015@users.noreply.github.com>
2026-05-28 07:28:24 -07:00
|
|
|
"kchuang1015@users.noreply.github.com": "kchuang1015",
|
2026-05-26 14:16:29 -07:00
|
|
|
"45688690+fujinice@users.noreply.github.com": "fujinice",
|
2026-05-26 19:35:52 -07:00
|
|
|
"276689385+carltonawong@users.noreply.github.com": "carltonawong",
|
2026-05-27 01:45:53 -07:00
|
|
|
"195255660+EvilHumphrey@users.noreply.github.com": "EvilHumphrey",
|
2026-05-27 01:57:37 -07:00
|
|
|
"270604154+superearn-fisher@users.noreply.github.com": "superearn-fisher",
|
2026-05-27 02:16:56 -07:00
|
|
|
"3540493+kpadilha@users.noreply.github.com": "kpadilha",
|
2026-05-27 02:31:34 -07:00
|
|
|
"40378218+chaconne67@users.noreply.github.com": "chaconne67",
|
2026-05-28 05:45:28 +00:00
|
|
|
"Pluviobyte@users.noreply.github.com": "Pluviobyte",
|
2026-05-27 11:09:24 -07:00
|
|
|
"sanghyuk_seo@nexcubecorp.com": "sanghyuk-seo-nexcube",
|
2026-05-27 11:21:07 -07:00
|
|
|
"subrtt@gmail.com": "Brixyy",
|
2026-05-26 20:40:17 -07:00
|
|
|
"wangpuv@hotmail.com": "wangpuv",
|
2026-05-26 20:03:46 -07:00
|
|
|
"202622897+ticketclosed-wontfix@users.noreply.github.com": "ticketclosed-wontfix",
|
fix(codex-responses): gracefully recover from invalid_encrypted_content (salvage #10144) (#33035)
* fix(codex-responses): gracefully recover from invalid_encrypted_content (salvage #10144)
When an OpenAI-compatible Responses API surface accepts an initial
request but later rejects the replayed `codex_reasoning_items`
encrypted blob with HTTP 400 `invalid_encrypted_content`, the
session previously got stuck retrying the same poisoned payload.
Recovery: classify the error as a dedicated FailoverReason, and on the
first hit disable encrypted reasoning replay for the rest of the
session, strip cached items from message history, and retry once.
Changes:
* error_classifier: add FailoverReason.invalid_encrypted_content
branch in _classify_400 (before context_overflow so the messages
that mention 'encrypted content … could not be verified' don't trip
context heuristics), in _classify_by_error_code, and extend
_extract_error_code to peek inside wrapped JSON in error.message and
ignore the bare '400' as a code.
* agent_init: initialize `_codex_reasoning_replay_enabled = True` on
every agent.
* run_agent: add AIAgent._disable_codex_reasoning_replay() helper
that flips the flag and pops cached items.
* codex_responses_adapter: thread a `replay_encrypted_reasoning`
kwarg through _chat_messages_to_responses_input so that when the
flag is False we don't replay codex_reasoning_items.
* transports/codex.py: read `replay_encrypted_reasoning` from params,
thread it into the adapter, and gate the
`include=['reasoning.encrypted_content']` request hint on it.
* chat_completion_helpers: pass the agent's replay flag through to
the transport.
* conversation_loop: in the retry loop, add an
invalid_encrypted_content recovery branch that fires once per
session, only when api_mode == codex_responses, only when replay is
still enabled, and only when at least one assistant message in
history actually carries cached reasoning items (otherwise the 400
has nothing to do with our cache and the normal retry path handles
it).
Tests:
* test_error_classifier: new wrapped-JSON _extract_error_code case;
new TestClassifyApiError cases proving the 400 is retryable with
no fallback, that the broad message match doesn't catch a generic
'parsed' message, and that the error code match is
case-insensitive.
* test_run_agent_codex_responses: end-to-end test of the recovery
branch firing once and disabling replay, plus a sibling test that
proves the branch does *not* fire (and the flag stays True) when
history has no cached reasoning items.
Salvages PR #10144 onto the post-refactor module layout
(error_classifier / codex_responses_adapter / transports/codex /
conversation_loop / agent_init) since the original diff was written
against the pre-refactor monolithic run_agent.py.
* chore(release): map victorGPT in AUTHOR_MAP for #10144 salvage
---------
Co-authored-by: victorGPT <wuxuebin1993@gmail.com>
2026-05-26 22:01:17 -07:00
|
|
|
"wuxuebin1993@gmail.com": "victorGPT",
|
2026-03-12 01:35:47 -07:00
|
|
|
# teknium (multiple emails)
|
|
|
|
|
"teknium1@gmail.com": "teknium1",
|
2026-05-24 04:08:45 -07:00
|
|
|
"kenyon1977@gmail.com": "kenyonxu",
|
2026-05-21 23:26:34 -07:00
|
|
|
"cipherframe@users.noreply.github.com": "CipherFrame",
|
2026-05-27 11:38:25 -07:00
|
|
|
"donovan-yohan@users.noreply.github.com": "donovan-yohan",
|
2026-05-24 23:06:08 -07:00
|
|
|
"121752779+jacevys@users.noreply.github.com": "jacevys",
|
2026-05-20 22:59:14 -07:00
|
|
|
"me@promplate.dev": "CNSeniorious000",
|
2026-05-21 13:00:12 -07:00
|
|
|
"yichengqiao21@gmail.com": "YarrowQiao",
|
fix(security): derive <VENDOR>_API_KEY from host as final credential fallback
After #28660's host-gating fix, users with provider=custom and base_url
pointed at a commercial endpoint (DeepSeek, Groq, Mistral, …) hit
no-key-required even when they had the vendor-named env var set
(DEEPSEEK_API_KEY, GROQ_API_KEY, …). The issue author flagged this as
'what users intuitively expect'.
Adds _host_derived_api_key() to derive an env var name from the base URL
host using the *registrable* label (second-to-last). Appended to all three
api_key_candidates chains (_resolve_named_custom_runtime direct-alias path,
named-custom path, _resolve_openrouter_runtime non-openrouter branch).
Lookalike resistance: api.deepseek.com.attacker.test resolves to vendor
label 'attacker', NOT 'deepseek' — DEEPSEEK_API_KEY stays put. IPs and
loopback yield no vendor label. Already-handled vendors (OPENAI/OPENROUTER/
OLLAMA) are filtered to prevent bypass of the explicit host-gated paths.
Adds 6 tests covering positive paths (DeepSeek, Groq), the lookalike attack,
loopback rejection, the already-handled-vendor filter, and direct helper
unit tests.
Also adds erhnysr to AUTHOR_MAP.
2026-05-20 20:05:50 -07:00
|
|
|
"erhanyasarx@gmail.com": "erhnysr",
|
2026-05-13 21:56:48 -07:00
|
|
|
"30366221+WorldWriter@users.noreply.github.com": "WorldWriter",
|
|
|
|
|
"dafeng@DafengdeMacBook-Pro.local": "WorldWriter",
|
2026-05-24 19:41:23 -07:00
|
|
|
"schepers.zander1@gmail.com": "Strontvod",
|
2026-05-25 00:45:12 -07:00
|
|
|
"ed@bebop.crew": "someaka",
|
2026-05-14 16:03:41 -07:00
|
|
|
"anadi.jaggia@gmail.com": "Jaggia",
|
2026-05-26 15:19:55 -07:00
|
|
|
"steve@steveonjava.com": "steveonjava",
|
2026-05-28 02:59:03 +05:30
|
|
|
"steveonjava@gmail.com": "steveonjava",
|
2026-05-28 11:52:04 +05:30
|
|
|
"squiddy@2rook.ai": "MoonRay305",
|
2026-05-13 22:04:49 -07:00
|
|
|
"32201324+simpolism@users.noreply.github.com": "simpolism",
|
|
|
|
|
"simpolism@gmail.com": "simpolism",
|
2026-05-13 19:56:31 -04:00
|
|
|
"jake@nousresearch.com": "simpolism",
|
2026-05-13 13:27:20 -07:00
|
|
|
"mgongzai@gmail.com": "vKongv",
|
2026-05-07 05:13:43 -07:00
|
|
|
"0x.badfriend@gmail.com": "discodirector",
|
2026-05-07 05:16:07 -07:00
|
|
|
"altriatree@gmail.com": "TruaShamu",
|
2026-05-21 19:16:35 -07:00
|
|
|
"contact-me@stark-x.cn": "Stark-X",
|
feat(tui): mouse_tracking DEC mode presets (salvage of #26681) (#30084)
* feat(tui): make display.mouse_tracking pick which DEC modes to enable
Previously the boolean flag was all-or-nothing across modes 1000+1002+1003+1006.
Inside tmux, mode 1003 (any-motion) makes every mouse cross of the prompt row
fire a clipboard probe that surfaces as "No image in clipboard" — sometimes
dozens in a row. Disabling tracking entirely killed scroll-wheel scrolling too,
since tmux's own scrollback is preempted by the alt-screen TUI.
`display.mouse_tracking` (and `/mouse <preset>`) now accepts `off | wheel |
buttons | all` in addition to the legacy booleans. `wheel` is 1000+1006:
scroll wheel + click only, no drag, no hover — the tmux-friendly subset.
`buttons` adds 1002 for drag-to-select. `all` (= legacy `true`) keeps the
hover-driven UI (scrollbar paginate-on-hover, link mouseenter, etc.).
* fix(tui): repaint + sync mouse mode when display.mouse_tracking changes
Two interacting bugs left the TUI blank when `display.mouse_tracking`
switched at runtime (config edit, /mouse <preset>):
1. AlternateScreen's effect re-runs on every `mouseTracking` change,
tearing down and re-entering the alt screen. After re-entry, ink's
frame buffers are reset by `resetFramesForAltScreen()` but nothing
schedules the follow-up render — the alt screen sits blank until
some other state change happens to trigger one. Add a
`scheduleRender()` in `setAltScreenActive`'s active=true branch so
the freshly-entered alt screen gets a full repaint immediately.
2. `setAltScreenActive` early-returns when `active` hasn't changed,
which silently drops a `mouseTracking` change if the cleanup→setup
pair somehow leaves `altScreenActive` already true. Call
`setAltScreenMouseTracking` explicitly from the AlternateScreen
effect so the in-memory mode and terminal DECSET sequence stay in
sync regardless of how `setAltScreenActive` resolved (the call is a
no-op when the mode is unchanged).
* fix(tui): address copilot review #4341269705
- tui_gateway/server.py: drop the never-referenced _MOUSE_TRACKING_MODES
frozenset (comment #3284802434). _MOUSE_TRACKING_ALIASES already
centralizes the canonical preset set via its values; the separate
constant added no behavior.
- tests/test_tui_gateway_server.py: update the existing
test_config_mouse_uses_documented_key_with_legacy_fallback to assert
the new preset strings ('all'/'off' instead of 'on'/'off',
display.mouse_tracking persisted as 'all' instead of True) and add
test_config_mouse_accepts_preset_strings_and_aliases covering /mouse
set with wheel/click/unknown (comment #3284802453). The on/off legacy
config.set return shape was an implementation detail of the boolean
flag, not a stable API — the slash command, gateway help text, and
docs all advertise the preset values now.
- ui-tui/packages/hermes-ink/src/ink/ink.tsx: schedule a render at the
end of reenterAltScreen() (comment #3284802461). Mirrors the same fix
in setAltScreenActive() from ece0a2f4c — without it, SIGCONT/resize
self-heal/stdin-gap re-entry leaves the alt screen blank because
every caller returns early after invoking us.
* fix(tui): address copilot review #4341308478 round 2
- ui-tui/src/config/env.ts (comment #3284837577): the precedence
comment was misleading. Actual behavior on origin/main is
HERMES_TUI_MOUSE_TRACKING (explicit override) > Termux default >
HERMES_TUI_DISABLE_MOUSE legacy kill-switch. This is preserved from
main; the only change here was the wrong comment that claimed
DISABLE_MOUSE kept kill-switch semantics. Rewrote the comment block
to document the actual precedence ladder.
- tui_gateway/server.py /mouse set (comment #3284837607): replaced
'str(value or "").strip().lower()' with the explicit None idiom
already used for /indicator, so programmatic callers can pass 0 /
False and have them route through _MOUSE_TRACKING_ALIASES → 'off'
instead of collapsing to '' and triggering the toggle path.
- ui-tui/packages/hermes-ink/src/ink/components/AlternateScreen.tsx
(comment #3284837620): always prepend DISABLE_MOUSE_TRACKING before
enableMouseTrackingFor(...) on mount. Otherwise selecting
'wheel'/'buttons' from a state where DEC 1003 was already asserted
(crash, another app, debugger) would silently leave hover on. Also
unconditionally DISABLE on unmount so a crash mid-mount can't leak
DEC modes back to the host shell.
* chore(release): map nat@nthrow.io to @nthrow for #26681 salvage
* fix(tui): drop redundant setAltScreenMouseTracking in AlternateScreen
Copilot review #4341356637 (comment #3284880417). The explicit
setAltScreenMouseTracking(mouseTracking) after setAltScreenActive(true,
mouseTracking) was defensive paranoia added in the previous fix commit
that's not actually reachable in practice:
- React's cleanup always runs before the next setup, so on any prop
change (mouseTracking or writeRaw) the cleanup sets active=false
first. Setup then sees active was false and applies the new mode
via setAltScreenActive without early-returning.
- On the impossible 'active stayed true' path, the writeRaw above has
already sent DISABLE_MOUSE_TRACKING + enableMouseTrackingFor(newMode)
to the terminal, so the in-memory mode would lag but the visible
state is already correct.
Removing the redundant call means a single DEC sequence per mount.
If the 'active stayed true' path ever manifests in practice, the
right fix is in setAltScreenActive (track mode regardless of the
active early-return), not here.
* fix(tui): always DISABLE before enableMouseTrackingFor in ink.tsx
Copilot review #4341379994 (comments #3284900825, #3284900840,
#3284900852). Three remaining call sites in ink.tsx still re-enabled
mouse tracking without first sending DISABLE_MOUSE_TRACKING:
- handleResize alt-screen recovery (line ~577)
- reassertTerminalModes stdin-gap re-assertion (line ~1351)
- reenterAltScreen SIGCONT/resize/stdin-gap self-heal (line ~1408)
For 'wheel'/'buttons' presets, omitting DISABLE leaves any externally-
asserted DEC 1003 (other apps, prior crash, tmux state) still active
and the hover-free preset silently has hover on. DISABLE_MOUSE_TRACKING
is idempotent and safe to send unconditionally — it resets all four
modes. Matches the pattern already in setAltScreenMouseTracking and
the AlternateScreen mount path.
* fix(tui): always DISABLE before enableMouseTrackingFor in exitAlternateScreen
Copilot review #4341452823 (comment #3284959762). exitAlternateScreen()
was the last call site in ink.tsx still re-enabling mouse tracking
without DISABLE first. Editors (vim/nvim/less) and tmux can leave
DEC 1003 hover asserted across the handoff back; without DISABLE,
'wheel'/'buttons' presets silently kept hover on after the editor
quit. Now all five enableMouseTrackingFor() call sites in ink.tsx
prepend DISABLE_MOUSE_TRACKING — handleResize, reassertTerminalModes,
reenterAltScreen, setAltScreenMouseTracking, exitAlternateScreen.
* fix(tui): add defensive default to enableMouseTrackingFor switch
Copilot review #4341485231 (comment #3284979323). TS exhaustive switch
returns string per the type system, but a JS caller / corrupted config
/ hot-reload-in-dev could reach the function with an unknown value at
runtime. Without a default, that path returns undefined which then
concatenates as the literal string 'undefined' into the terminal byte
stream — visibly garbling output. Treat unknown as 'off' (no DEC
sequences) so the worst case is silent input loss rather than a
wrecked screen.
---------
Co-authored-by: Nat Thrower <nat@nthrow.io>
2026-05-21 20:25:52 -05:00
|
|
|
"nat@nthrow.io": "nthrow",
|
2026-04-30 23:09:47 -07:00
|
|
|
"m@mobrienv.dev": "mikeyobrien",
|
2026-05-18 14:31:10 -07:00
|
|
|
"saeed919@pm.me": "falasi",
|
2026-05-22 01:21:27 -07:00
|
|
|
"chrisdlc119@outlook.com": "chdlc",
|
2026-05-20 22:57:25 -07:00
|
|
|
"omar@techdeveloper.site": "nycomar",
|
2026-04-28 01:14:15 -07:00
|
|
|
"qiyin.zuo@pcitc.com": "qiyin-code",
|
2026-05-15 01:38:30 -07:00
|
|
|
"mr.aashiz@gmail.com": "aashizpoudel",
|
2026-05-28 01:43:20 -07:00
|
|
|
"adityargadgil@gmail.com": "AdityaRajeshGadgil",
|
2026-05-16 02:27:41 -07:00
|
|
|
"70629228+shaun0927@users.noreply.github.com": "shaun0927",
|
2026-05-24 04:38:03 -07:00
|
|
|
"soju06@users.noreply.github.com": "Soju06",
|
|
|
|
|
"34199905+Soju06@users.noreply.github.com": "Soju06",
|
2026-05-15 21:55:01 -07:00
|
|
|
"98262967+Bihruze@users.noreply.github.com": "Bihruze",
|
2026-05-21 19:23:14 -07:00
|
|
|
"189280367+Lempkey@users.noreply.github.com": "Lempkey",
|
2026-05-24 04:47:20 -07:00
|
|
|
"34853915+m0n3r0@users.noreply.github.com": "m0n3r0",
|
2026-05-24 15:48:13 -07:00
|
|
|
"leeseoki@makestar.com": "leeseoki0",
|
2026-05-24 17:46:19 -07:00
|
|
|
"kronexoi13@gmail.com": "kronexoi",
|
2026-05-24 17:57:50 -07:00
|
|
|
"hua.zhong@kingsmith.com": "vgocoder",
|
2026-05-25 01:09:10 -07:00
|
|
|
"hermes@marian.local": "Schrotti77",
|
2026-05-29 02:10:12 +05:30
|
|
|
"david@memorilabs.ai": "devwdave",
|
|
|
|
|
"dave@devwdave.com": "devwdave",
|
2026-05-25 01:14:50 -07:00
|
|
|
"1920071390@campus.ouj.ac.jp": "zapabob",
|
2026-05-25 01:55:21 -07:00
|
|
|
"gaia@gaia.local": "jfuenmayor",
|
|
|
|
|
"jiahuigu@users.noreply.github.com": "Jiahui-Gu",
|
|
|
|
|
"openhands@all-hands.dev": "YLChen-007",
|
feat(skills): add optional openhands skill — closes #477
Adds an optional autonomous-ai-agents skill that delegates coding tasks
to the OpenHands CLI (https://github.com/All-Hands-AI/OpenHands). Sits
alongside claude-code / codex / opencode and is the model-agnostic
option in that family — any LiteLLM-supported provider works.
This is a ground-truth rewrite of #19325 by @xzessmedia (Tim Koepsel).
The original PR's SKILL.md was drafted by the OpenHands agent itself and
hallucinated several flags that don't exist in the real CLI (\`--model\`,
\`--max-iterations\`, \`--workspace\`, \`--sandbox docker\`), pointed at
the wrong PyPI package (\`openhands-ai\`, which is the legacy V0 SDK),
and claimed native Windows support that the upstream docs explicitly
disclaim. Rather than cherry-pick and rewrite half the lines under
contributor authorship, the SKILL.md was rebuilt against a verified
install (\`uv tool install openhands --python 3.12\`) and a real
end-to-end \`--headless --json\` run against openrouter/openai/gpt-4o-mini.
Authorship credited via the \`author:\` frontmatter field and an
AUTHOR_MAP entry in scripts/release.py.
Changes:
- optional-skills/autonomous-ai-agents/openhands/SKILL.md (new)
- website/docs/user-guide/skills/optional/autonomous-ai-agents/autonomous-ai-agents-openhands.md (auto-gen)
- website/docs/reference/optional-skills-catalog.md (one new row)
- website/sidebars.ts (one new entry under Optional → Autonomous AI Agents)
- scripts/release.py (AUTHOR_MAP entry for xzessmedia)
Pitfalls documented in the SKILL came from running the tool, not from
the upstream README: LiteLLM bedrock/sagemaker stderr noise on every
invocation, banner spam (\`OPENHANDS_SUPPRESS_BANNER=1\` required),
\`--override-with-envs\` mandatory or the CLI ignores LLM_* env vars
entirely, the dashed-vs-undashed Conversation ID footgun for \`--resume\`,
LiteLLM model-slug double-prefix when going through OpenRouter.
2026-05-25 14:32:34 -07:00
|
|
|
"3153586+xzessmedia@users.noreply.github.com": "xzessmedia",
|
2026-05-25 01:55:21 -07:00
|
|
|
"AdamPlatin123@outlook.com": "AdamPlatin123",
|
|
|
|
|
"32711803+waefrebeorn@users.noreply.github.com": "waefrebeorn",
|
2026-05-25 03:38:11 -07:00
|
|
|
"32869278+dusterbloom@users.noreply.github.com": "dusterbloom",
|
2026-05-25 03:40:15 -07:00
|
|
|
"liuhao1024@users.noreply.github.com": "liuhao1024",
|
2026-05-25 06:14:09 -07:00
|
|
|
"kylekahraman@users.noreply.github.com": "kylekahraman",
|
|
|
|
|
"130975919+kylekahraman@users.noreply.github.com": "kylekahraman",
|
2026-05-25 05:15:19 -07:00
|
|
|
"dsr-restyn@users.noreply.github.com": "dsr-restyn",
|
|
|
|
|
"210765158+WuKongAI-CMU@users.noreply.github.com": "WuKongAI-CMU",
|
|
|
|
|
"lichriszhang@gmail.com": "codeblackhole1024",
|
2026-05-21 19:23:14 -07:00
|
|
|
"leovillalbajr@gmail.com": "Lempkey",
|
2026-05-15 01:46:46 -07:00
|
|
|
"nidhi2894@gmail.com": "nidhi-singh02",
|
2026-05-15 01:38:30 -07:00
|
|
|
"30312689+aashizpoudel@users.noreply.github.com": "aashizpoudel",
|
2026-05-05 17:02:01 -07:00
|
|
|
"oleksii.lisikh@gmail.com": "olisikh",
|
fix(async): close unscheduled coroutines in all threadsafe bridges (#26584)
Wraps every sync->async coroutine-scheduling site in the codebase with a
new agent.async_utils.safe_schedule_threadsafe() helper that closes the
coroutine on scheduling failure (closed loop, shutdown race, etc.)
instead of leaking it as 'coroutine was never awaited' RuntimeWarnings
plus reference leaks.
22 production call sites migrated across the codebase:
- acp_adapter/events.py, acp_adapter/permissions.py
- agent/lsp/manager.py
- cron/scheduler.py (media + text delivery paths)
- gateway/platforms/feishu.py (5 sites, via existing _submit_on_loop helper
which now delegates to safe_schedule_threadsafe)
- gateway/run.py (10 sites: telegram rename, agent:step hook, status
callback, interim+bg-review, clarify send, exec-approval button+text,
temp-bubble cleanup, channel-directory refresh)
- plugins/memory/hindsight, plugins/platforms/google_chat
- tools/browser_supervisor.py (3), browser_cdp_tool.py,
computer_use/cua_backend.py, slash_confirm.py
- tools/environments/modal.py (_AsyncWorker)
- tools/mcp_tool.py (2 + 8 _run_on_mcp_loop callers converted to
factory-style so the coroutine is never constructed on a dead loop)
- tui_gateway/ws.py
Tests: new tests/agent/test_async_utils.py covers helper behavior under
live loop, dead loop, None loop, and scheduling exceptions. Regression
tests added at three PR-original sites (acp events, acp permissions,
mcp loop runner) mirroring contributor's intent.
Live-tested end-to-end:
- Helper stress test: 1500 schedules across live/dead/race scenarios,
zero leaked coroutines
- Race exercised: 5000 schedules with loop killed mid-flight, 100 ok /
4900 None returns, zero leaks
- hermes chat -q with terminal tool call (exercises step_callback bridge)
- MCP probe against failing subprocess servers + factory path
- Real gateway daemon boot + SIGINT shutdown across multiple platform
adapter inits
- WSTransport 100 live + 50 dead-loop writes
- Cron delivery path live + dead loop
Salvages PR #2657 — adopts contributor's intent over a much wider site
list and a single centralized helper instead of inline try/except at
each site. 3 of the original PR's 6 sites no longer exist on main
(environments/patches.py deleted, DingTalk refactored to native async);
the equivalent fix lives in tools/environments/modal.py instead.
Co-authored-by: JithendraNara <jithendranaidunara@gmail.com>
2026-05-15 14:00:01 -07:00
|
|
|
"jithendranaidunara@gmail.com": "JithendraNara",
|
2026-05-14 20:14:13 -07:00
|
|
|
"jeremy@geocaching.com": "outdoorsea",
|
2026-05-23 23:00:35 -07:00
|
|
|
"54763683+thedavidmurray@users.noreply.github.com": "thedavidmurray",
|
2026-04-30 04:58:45 -07:00
|
|
|
"leone.parise@gmail.com": "leoneparise",
|
2026-05-13 22:56:13 -07:00
|
|
|
"mr@shu.io": "mrshu",
|
2026-05-14 20:15:37 -07:00
|
|
|
"adam.manning@gmail.com": "am423",
|
2026-05-08 04:20:00 -07:00
|
|
|
"buraysandro9@gmail.com": "ygd58",
|
2026-05-15 01:33:16 -07:00
|
|
|
"108427749+buntingszn@users.noreply.github.com": "buntingszn",
|
test(novita): cache pricing, add provider test coverage, AUTHOR_MAP entry
Follow-up to Alex-wuhu's NovitaAI provider commit. Adds:
- _pricing_cache hit/write in _fetch_novita_pricing (was missing — every
pricing fetch was re-hitting the network), mirroring the
fetch_ai_gateway_pricing pattern. force_refresh now also propagates
from get_pricing_for_provider.
- TestNovitaProvider in tests/hermes_cli/test_api_key_providers.py
covering profile load, alias resolution, registry auto-registration,
model list parity between main.py and models.py, _URL_TO_PROVIDER,
_PROVIDER_PREFIXES, context_size in _CONTEXT_LENGTH_KEYS, pricing
unit conversion, and pricing cache behavior.
- AUTHOR_MAP entry for yanglongwei06@gmail.com → @Alex-yang00.
2026-05-14 12:05:52 +05:30
|
|
|
"yanglongwei06@gmail.com": "Alex-yang00",
|
2026-05-28 03:42:04 -07:00
|
|
|
"yanghongda@jackyun.com": "yangguangjin",
|
2026-03-12 01:35:47 -07:00
|
|
|
"teknium@nousresearch.com": "teknium1",
|
2026-05-20 22:10:44 -07:00
|
|
|
"markuscontasul@gmail.com": "Glucksberg",
|
2026-05-23 16:16:46 -07:00
|
|
|
"80581902+Glucksberg@users.noreply.github.com": "Glucksberg",
|
2026-05-07 05:03:10 -07:00
|
|
|
"piyushvp1@gmail.com": "thelumiereguy",
|
2026-05-23 23:11:37 -07:00
|
|
|
"pnascimento9596@gmail.com": "pnascimento9596",
|
2026-05-18 10:47:39 -07:00
|
|
|
"dskwelmcy@163.com": "dskwe",
|
2026-05-11 10:56:37 -07:00
|
|
|
"421774554@qq.com": "wuli666",
|
2026-05-15 16:39:18 -07:00
|
|
|
"twebefy@gmail.com": "tw2818",
|
2026-05-07 05:03:10 -07:00
|
|
|
"harish.kukreja@gmail.com": "counterposition",
|
2026-05-14 22:30:12 -07:00
|
|
|
"korkyzer@gmail.com": "Korkyzer",
|
2026-05-11 09:58:39 -07:00
|
|
|
"1046611633@qq.com": "zhengyn0001",
|
2026-05-13 08:46:01 -07:00
|
|
|
"1095245867@qq.com": "littlewwwhite",
|
2026-05-12 11:50:33 -07:00
|
|
|
"db@project-aeon.com": "db-aeon",
|
2026-05-11 16:50:39 -07:00
|
|
|
"ahmed@abadr.net": "ahmedbadr3",
|
2026-05-15 01:27:31 -07:00
|
|
|
"63822243+CoinTheHat@users.noreply.github.com": "CoinTheHat",
|
2026-05-06 05:06:31 -07:00
|
|
|
"cleo@edaphic.xyz": "curiouscleo",
|
2026-05-07 07:02:05 -07:00
|
|
|
"hirokazu.ogawa@kwansei.ac.jp": "hrkzogw",
|
2026-05-08 17:00:32 -07:00
|
|
|
"datapod.k@gmail.com": "dandacompany",
|
2026-05-10 19:40:43 -07:00
|
|
|
"treydong.zh@gmail.com": "TreyDong",
|
2026-05-14 16:00:12 -07:00
|
|
|
"phil.thomas@gametime.co": "explainanalyze",
|
2026-05-12 11:52:44 -07:00
|
|
|
"kyanam.preetham@gmail.com": "pkyanam",
|
2026-05-14 15:11:28 -07:00
|
|
|
"zhizhong.xu@shopee.com": "1000Delta",
|
|
|
|
|
"30397170+1000Delta@users.noreply.github.com": "1000Delta",
|
fix(cli): clamp scrollback box widths + suppress status bar after resize (#25975)
When the terminal shrinks, already-printed box-drawing rules (response,
reasoning, streaming TTS, background-task Panels) reflow into multiple
narrower rows — visible as duplicated horizontal separators / ghost
lines in scrollback. Similarly, prompt_toolkit redraws a fresh status
bar on SIGWINCH on top of one the terminal just reflowed, producing
double-bar artifacts on column shrink.
Two surgical changes:
1. Decorative scrollback boxes now use a new
`HermesCLI._scrollback_box_width()` helper that clamps to
`max(32, min(width, 56))`. The live TUI footer is unaffected and still
uses the full width. Covers: streaming response box (open + close),
reasoning box (open + close, both streaming and post-stream paths),
streaming-TTS box close, final-response Rich Panel, and the
background-task Rich Panel.
2. `_recover_after_resize()` now also sets a new
`_status_bar_suppressed_after_resize` flag so the dynamic status bar
and both input separator rules stay hidden until the next user input.
The flag is cleared in the process loop the moment the user submits
their next prompt, restoring chrome cleanly.
Tests:
- New `test_input_rules_hide_after_resize_until_next_input` covers the
flag's effect on rule heights.
- New `test_scrollback_box_width_caps_to_resize_safe_value` covers the
helper at floor / cap / mid-range / overflow.
- Existing resize-recovery test extended to assert the flag flips.
Refs: #18449 #19280 #22976
Salvage of #24403.
Co-authored-by: Szymonclawd <szymonclawd@mac.home>
2026-05-14 15:22:44 -07:00
|
|
|
"szymonclawd@mac.home": "szymonclawd",
|
|
|
|
|
"257759490+szymonclawd@users.noreply.github.com": "szymonclawd",
|
2026-05-16 14:46:54 +05:30
|
|
|
"101180447+worlldz@users.noreply.github.com": "worlldz",
|
2026-05-14 15:25:34 -07:00
|
|
|
"zhanganzhe@tenclass.com": "luoyuctl",
|
|
|
|
|
"51604064+luoyuctl@users.noreply.github.com": "luoyuctl",
|
2026-03-12 01:35:47 -07:00
|
|
|
"127238744+teknium1@users.noreply.github.com": "teknium1",
|
2026-05-15 01:40:07 -07:00
|
|
|
"tolle.lege+github@gmail.com": "InB4DevOps",
|
|
|
|
|
"73686890+InB4DevOps@users.noreply.github.com": "InB4DevOps",
|
2026-05-12 16:32:44 -07:00
|
|
|
"147827411+EloquentBrush@users.noreply.github.com": "AhmetArif0",
|
2026-05-14 09:34:10 -07:00
|
|
|
"97489706+purzbeats@users.noreply.github.com": "purzbeats",
|
2026-05-10 22:05:11 -07:00
|
|
|
"hugosequier@gmail.com": "Hugo-SEQUIER",
|
2026-05-19 14:14:22 -07:00
|
|
|
"kylejeong21@gmail.com": "Kylejeong2",
|
2026-05-07 04:53:34 -07:00
|
|
|
"128259593+Gutslabs@users.noreply.github.com": "Gutslabs",
|
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
|
|
|
"50326054+nocturnum91@users.noreply.github.com": "nocturnum91",
|
2026-05-18 17:29:26 +00:00
|
|
|
"52470719+gianfrancopiana@users.noreply.github.com": "gianfrancopiana",
|
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 07:23:03 -07:00
|
|
|
"223003280+Abd0r@users.noreply.github.com": "Abd0r",
|
2026-05-10 14:12:31 -07:00
|
|
|
"HuangYuChuh@users.noreply.github.com": "HuangYuChuh",
|
2026-05-10 15:16:04 -07:00
|
|
|
"aaronwong1989@gmail.com": "hrygo",
|
|
|
|
|
"26729613+hrygo@users.noreply.github.com": "hrygo",
|
2026-05-10 22:01:18 -07:00
|
|
|
"erenkar950@gmail.com": "eren-karakus0",
|
2026-05-10 16:17:48 -07:00
|
|
|
"aubrey@freeman-wisco.com": "Freeman-Consulting",
|
2026-05-10 16:25:33 -07:00
|
|
|
"don.rhm@gmail.com": "rahimsais",
|
|
|
|
|
"40222899+rahimsais@users.noreply.github.com": "rahimsais",
|
2026-05-10 19:12:52 -07:00
|
|
|
"alfred@Alfreds-Mac-mini.local": "NivOO5",
|
|
|
|
|
"231191380+NivOO5@users.noreply.github.com": "NivOO5",
|
2026-05-10 21:59:14 -07:00
|
|
|
"jameshuang@gmail.com": "kjames2001",
|
|
|
|
|
"62420081+kjames2001@users.noreply.github.com": "kjames2001",
|
2026-05-10 22:18:14 -07:00
|
|
|
"132184373+wilsen0@users.noreply.github.com": "wilsen0",
|
2026-05-08 16:25:27 -07:00
|
|
|
"ra2157218@gmail.com": "Abd0r",
|
2026-05-14 08:02:18 -07:00
|
|
|
"oswaldb22@users.noreply.github.com": "oswaldb22",
|
2026-05-07 06:25:06 -07:00
|
|
|
"abdielv@proton.me": "AJV20",
|
2026-05-07 06:27:35 -07:00
|
|
|
"mason@growagainorchids.com": "masonjames",
|
2026-05-15 01:42:35 -07:00
|
|
|
"108541149+amethystani@users.noreply.github.com": "amethystani",
|
2026-05-07 17:19:47 -07:00
|
|
|
"ytchen0719@gmail.com": "liquidchen",
|
2026-05-07 06:32:16 -07:00
|
|
|
"am@studio1.tailb672fe.ts.net": "subtract0",
|
feat(gateway): per-platform admin/user split for slash commands (salvage of #4443) (#23373)
* feat(gateway): per-platform admin/user split for slash commands
Adds an opt-in two-list access control on top of the existing per-platform
`allow_from` allowlists, scoped to slash commands only:
- allow_admin_from — full slash command access
- user_allowed_commands — what non-admins may run
- group_allow_admin_from — same, group/channel scope
- group_user_allowed_commands
When `allow_admin_from` is unset for a scope, gating is disabled and every
allowed user keeps full access (backward compat). Plain chat is unaffected.
`/help` and `/whoami` are always reachable so users can see what they
can run.
Gate runs at the slash command dispatch site in gateway/run.py and uses
`is_gateway_known_command()`, so it covers built-in AND plugin-registered
commands through the live registry without per-feature wiring.
Adds `/whoami` showing platform, scope, tier, and runnable commands.
Salvage of PR #4443's permission tier work, scoped down. The full tier
system, tool filtering, audit log, usage tracking, rate limiting,
`/promote` flow, and persistent SQLite stores are not included here —
those can be re-expanded later if needed.
Co-authored-by: ReqX <mike@grossmann.at>
* fix(gateway): close running-agent fast-path bypass + add coverage and central docs
The slash command access gate was only applied at the cold dispatch site
(line ~5921). When an agent was already running, the running-agent
fast-path block (line ~5574) dispatched /restart, /stop, /new, /steer,
/model, /approve, /deny, /agents, /background, /kanban, /goal, /yolo,
/verbose, /footer, /help, /commands, /profile, /update directly
without going through the gate — letting non-admins bypass gating just
because an agent happens to be busy.
Refactored the gate into _check_slash_access() and called from BOTH
paths. /status remains intentionally pre-gate so users can always see
session state.
Also added 18 more dispatch tests covering:
- Running-agent fast-path: blocks non-admin, allows admin, /status
always works
- Alias canonicalization (gate uses canonical name, not user alias)
- Unknown / unregistered commands pass through (don't false-positive)
- DM admin scope-locked when group has its own admin list
- Multi-platform isolation (Discord gated, Telegram unrestricted)
Docs: added Slash Command Access Control section to the central
messaging index page + /whoami row in the chat commands table.
Co-authored-by: ReqX <mike@grossmann.at>
---------
Co-authored-by: ReqX <mike@grossmann.at>
2026-05-10 12:33:54 -07:00
|
|
|
"mike@grossmann.at": "ReqX",
|
2026-05-07 07:16:38 -07:00
|
|
|
"axmaiqiu@gmail.com": "qWaitCrypto",
|
2026-05-09 14:48:13 -07:00
|
|
|
"44045911+kidonng@users.noreply.github.com": "kidonng",
|
2026-05-09 14:48:54 -07:00
|
|
|
"daniellsmarta@gmail.com": "DanielLSM",
|
2026-05-09 14:49:36 -07:00
|
|
|
"264291321+v1b3coder@users.noreply.github.com": "v1b3coder",
|
2026-05-09 14:50:53 -07:00
|
|
|
"silverchris@foxmail.com": "ming1523",
|
2026-05-09 13:14:03 -07:00
|
|
|
"maksesipov@gmail.com": "Qwinty",
|
2026-05-09 13:14:46 -07:00
|
|
|
"denisamania@gmail.com": "CalmProton",
|
2026-05-09 13:19:56 -07:00
|
|
|
"308068+mbac@users.noreply.github.com": "mbac",
|
2026-05-12 01:45:40 +05:30
|
|
|
"nicoechaniz@altermundi.net": "nicoechaniz",
|
2026-05-09 13:23:39 -07:00
|
|
|
"ninso112@proton.me": "Ninso112",
|
2026-05-09 08:58:11 -07:00
|
|
|
"wesleysimplicio@live.com": "wesleysimplicio",
|
2026-05-09 09:00:24 -07:00
|
|
|
"matthew.dean.cater@gmail.com": "SiliconID",
|
2026-05-09 11:09:50 -07:00
|
|
|
"xieniu@proton.me": "xieNniu",
|
2026-05-09 09:08:17 -07:00
|
|
|
"rw8143a@american.edu": "wali-reheman",
|
2026-05-09 02:18:35 -07:00
|
|
|
"egitimviscara@gmail.com": "uzunkuyruk",
|
2026-05-09 02:33:49 -07:00
|
|
|
"zhekinmaksim@gmail.com": "Zhekinmaksim",
|
2026-05-09 02:47:14 -07:00
|
|
|
"obafemiferanmi1999@gmail.com": "KvnGz",
|
2026-05-03 01:44:17 -07:00
|
|
|
"159539633+MottledShadow@users.noreply.github.com": "MottledShadow",
|
2026-04-30 19:45:41 -07:00
|
|
|
"aludwin+gh@gmail.com": "adamludwin",
|
fix(tools): wrap bare scalars in single-element list for array-typed args
Open-weight models (DeepSeek, Qwen, GLM) sometimes emit tool calls like
`{"urls": "https://a.com"}` when the tool schema declares
`type: array`. The call was JSON-valid but semantically wrong, and
`coerce_tool_args` would pass the bare string through — the tool then
failed with a confusing type error.
`coerce_tool_args` now wraps non-list, non-null values in a
single-element list when the schema declares `array`. Strings still go
through `_coerce_value` first so JSON-encoded arrays
(`'["a","b"]'`) parse correctly and nullable `"null"` still
becomes `None`. `None` itself is preserved — tools with sensible
defaults already handle it, and we don't want to silently mask a
deliberate null.
Salvaged from #19652 (NikolayGusev-astra) — the broader validate-then-
repair layer had several issues (duplicated existing coercion,
mis-classified `old_string` as a path field, prepended non-JSON
prefixes to tool results that break downstream JSON parsing, hardcoded
offset/limit defaults unsuitable for non-read_file tools). The one
genuinely new capability is wrapping bare scalars, which is implemented
here directly inside the existing coercion path.
Co-authored-by: Nikolay Gusev <ngusev@astralinux.ru>
2026-05-04 04:58:35 -07:00
|
|
|
"ngusev@astralinux.ru": "NikolayGusev-astra",
|
2026-05-06 04:08:02 -07:00
|
|
|
"liuguangyong201@hellobike.com": "liuguangyong93",
|
2026-04-29 04:15:40 -07:00
|
|
|
"2093036+exiao@users.noreply.github.com": "exiao",
|
2026-05-10 00:19:19 +05:30
|
|
|
"20nik.nosov21@gmail.com": "nik1t7n",
|
2026-05-07 05:16:50 -07:00
|
|
|
"thunderggnn@gmail.com": "ggnnggez",
|
|
|
|
|
"haozhe4547@gmail.com": "ehz0ah",
|
2026-05-18 21:02:11 -07:00
|
|
|
"eloklam2002@gmail.com": "eloklam",
|
2026-05-07 05:03:16 -07:00
|
|
|
"kevyan1998@gmail.com": "kyan12",
|
2026-04-29 04:54:26 -07:00
|
|
|
"rylen.anil@gmail.com": "rylena",
|
2026-04-30 20:23:30 -07:00
|
|
|
"godnanijatin@gmail.com": "jatingodnani",
|
2026-05-06 03:54:19 -07:00
|
|
|
"252811164+adybag14-cyber@users.noreply.github.com": "adybag14-cyber",
|
2026-04-29 04:56:32 -07:00
|
|
|
"14046872+tmimmanuel@users.noreply.github.com": "tmimmanuel",
|
2026-05-07 06:47:48 -07:00
|
|
|
"112875006+donramon77@users.noreply.github.com": "donramon77",
|
2026-04-30 22:49:55 -07:00
|
|
|
"657290301@qq.com": "IMHaoyan",
|
2026-04-28 04:58:23 -07:00
|
|
|
"revar@users.noreply.github.com": "revaraver",
|
2026-05-05 08:27:52 -07:00
|
|
|
"dengtaoyuan@dengtaoyuandeMac-mini.local": "dengtaoyuan450-a11y",
|
2026-05-05 08:35:59 -07:00
|
|
|
"ysfalweshcan@gmail.com": "Junass1",
|
2026-05-05 08:37:09 -07:00
|
|
|
"bartokmagic@proton.me": "Bartok9",
|
2026-05-18 21:53:35 -07:00
|
|
|
"bartok9@users.noreply.github.com": "Bartok9",
|
2026-05-18 21:58:41 -07:00
|
|
|
"erhanyasarx@gmail.com": "erhnysr", # PR #25198 salvage (tool-progress flood-control)
|
2026-05-18 22:01:25 -07:00
|
|
|
"cryptobyz.airdrop@gmail.com": "CryptoByz", # PR #25630 salvage (polling conflict Stage 1+2)
|
2026-05-18 22:03:06 -07:00
|
|
|
"fabioxxx@gmail.com": "fabiosiqueira", # PR #27212 salvage (bg-process notif anchor)
|
2026-05-18 22:14:38 -07:00
|
|
|
"lordfalcon.exe@gmail.com": "falconexe", # PR #24511 salvage (sticky-IP reset)
|
2026-05-18 22:19:45 -07:00
|
|
|
"fonhal@gmail.com": "fonhal", # PR #27865/#27861 salvage (mention entities / typing fallback)
|
2026-05-18 22:27:35 -07:00
|
|
|
"zyrixtrex@gmail.com": "Zyrixtrex", # PR #26754 salvage (avoid duplicate text after auto-TTS)
|
2026-05-18 22:28:16 -07:00
|
|
|
"264138787+nftpoetrist@users.noreply.github.com": "nftpoetrist", # PR #25856 salvage (escape slash-confirm preview)
|
2026-05-18 22:28:58 -07:00
|
|
|
"197455947+samahn0601@users.noreply.github.com": "samahn0601", # PR #27887 salvage (retry wrapped connect timeouts)
|
2026-05-18 22:29:40 -07:00
|
|
|
"gonzes7@gmail.com": "aqilaziz", # PR #26406 salvage (preserve native audio outside Telegram)
|
2026-05-18 22:30:23 -07:00
|
|
|
"karthikeyann@users.noreply.github.com": "karthikeyann", # PR #26609 salvage (DM-topic routing pin)
|
2026-05-18 22:31:55 -07:00
|
|
|
"rino.alpin@gmail.com": "kunci115", # PR #27098 salvage (thread-not-found retry)
|
2026-05-24 15:18:59 -07:00
|
|
|
"hayka-pacha@users.noreply.github.com": "hayka-pacha", # PR #25270 salvage (registry-aware mcp_ prefix strip)
|
2026-05-18 22:34:43 -07:00
|
|
|
"237601532+chromalinx@users.noreply.github.com": "chromalinx", # PR #27014 salvage (commands for groups+DM)
|
2026-05-18 22:35:23 -07:00
|
|
|
"booker1207@gmail.com": "booker1207", # PR #25132 salvage (gate profile bots by allowed topics)
|
2026-05-18 22:37:23 -07:00
|
|
|
"kiranvk2011@gmail.com": "kiranvk-2011", # PR #24815 salvage (image documents → vision)
|
2026-05-18 22:38:02 -07:00
|
|
|
"kosmonaut-t@centrum.cz": "rak135", # PR #25960 salvage (Windows /restart)
|
2026-05-18 22:40:38 -07:00
|
|
|
"bot.chi.online@gmail.com": "B0Tch1", # PR #27634 salvage (disable_topic_auto_rename)
|
2026-05-18 22:42:23 -07:00
|
|
|
"1037461232@qq.com": "jackjin1997", # PR #27239 salvage (restore DM topic thread_id after split)
|
2026-05-18 22:43:09 -07:00
|
|
|
"soynchuux@gmail.com": "soynchux", # PR #27806 salvage (chat-scoped auth without user_id)
|
2026-05-18 22:45:00 -07:00
|
|
|
"psikonetik@gmail.com": "el-analista", # PR #25368 salvage (cron topic fallback report)
|
2026-05-18 22:45:53 -07:00
|
|
|
"75435655+khungate@users.noreply.github.com": "khungate", # PR #25829 salvage (gmail-triage gt: callbacks)
|
2026-05-18 22:48:37 -07:00
|
|
|
"stevehq26-bot@users.noreply.github.com": "stevehq26-bot", # PR #28015 salvage (quick-command-only menus)
|
2026-05-18 22:51:30 -07:00
|
|
|
"seaverb@icloud.com": "brndnsvr", # PR #25327 salvage (channel post updates)
|
2026-05-18 22:52:55 -07:00
|
|
|
"oracle@jarviss-mbp.home": "houenyang-momo", # PR #24014 salvage (quiet noisy errors)
|
2026-05-18 22:54:10 -07:00
|
|
|
"57119977+OCWC22@users.noreply.github.com": "OCWC22", # PR #24581 salvage (multi-bot exclusive mentions)
|
2026-05-18 22:56:17 -07:00
|
|
|
"ai-hana-ai@users.noreply.github.com": "ai-hana-ai", # PR #23928 salvage (ignore_root_dm)
|
2026-05-18 22:57:50 -07:00
|
|
|
"mx.indigo.karasu@gmail.com": "indigokarasu", # PR #26636 salvage (pin user message)
|
2026-05-18 22:59:35 -07:00
|
|
|
"516972+alber70g@users.noreply.github.com": "alber70g", # PR #25280 salvage (skip-STT + 2GB cap)
|
2026-05-18 22:25:48 -07:00
|
|
|
"282919977+eliteworkstation94-ai@users.noreply.github.com": "eliteworkstation94-ai", # PR #28157 salvage (group reply session splits)
|
2026-05-07 15:21:12 -07:00
|
|
|
"androidhtml@yandex.com": "hllqkb",
|
2026-05-05 08:38:32 -07:00
|
|
|
"25840394+Bongulielmi@users.noreply.github.com": "Bongulielmi",
|
2026-05-05 08:40:47 -07:00
|
|
|
"jonathan.troyer@overmatch.com": "JTroyerOvermatch",
|
2026-05-05 08:42:22 -07:00
|
|
|
"harryykyle1@gmail.com": "hharry11",
|
2026-05-05 08:43:32 -07:00
|
|
|
"wysie@users.noreply.github.com": "wysie",
|
2026-05-25 14:31:46 -07:00
|
|
|
"ronhi@buildabear1.localdomain": "RonHillDev", # PR #29523 salvage (machine-local commit email)
|
2026-05-25 23:24:34 -07:00
|
|
|
"hello@nami4d.tech": "Nami4D", # PR #28490 salvage
|
2026-05-05 08:46:24 -07:00
|
|
|
"jkausel@gmail.com": "jkausel-ai",
|
2026-05-05 08:48:04 -07:00
|
|
|
"e.silacandmr@gmail.com": "Es1la",
|
2026-05-07 04:51:48 -07:00
|
|
|
"51599529+stephen0110@users.noreply.github.com": "stephen0110",
|
2026-05-07 04:54:38 -07:00
|
|
|
"265632032+sonic-netizen@users.noreply.github.com": "sonic-netizen",
|
2026-05-07 04:59:45 -07:00
|
|
|
"82531659+mwnickerson@users.noreply.github.com": "mwnickerson",
|
2026-05-07 05:26:11 -07:00
|
|
|
"sandrohub013@gmail.com": "SandroHub013",
|
2026-05-07 07:35:03 -07:00
|
|
|
"maciekczech@users.noreply.github.com": "maciekczech",
|
2026-05-05 08:48:57 -07:00
|
|
|
"154585401+LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
2026-05-14 15:14:04 -07:00
|
|
|
"cine.dreamer.one@gmail.com": "LeonSGP43",
|
2026-05-27 12:46:07 -04:00
|
|
|
"david@nutricraft.ca": "cyb0rgk1tty",
|
|
|
|
|
"chris+dora@cmullins.io": "cmullins70",
|
2026-05-05 08:56:40 -07:00
|
|
|
"zjtan1@gmail.com": "zeejaytan",
|
2026-05-05 08:57:39 -07:00
|
|
|
"asslaenn5@gmail.com": "Aslaaen",
|
2026-05-05 09:02:16 -07:00
|
|
|
"trae.anderson17@icloud.com": "Tkander1715",
|
2026-05-05 05:21:04 -07:00
|
|
|
"beardthelion@users.noreply.github.com": "beardthelion",
|
2026-05-27 01:39:06 -07:00
|
|
|
"orkunozturk@gmail.com": "orcool",
|
2026-05-05 05:29:49 -07:00
|
|
|
"tangyuanjc@JCdeAIfenshendeMac-mini.local": "tangyuanjc",
|
2026-05-05 05:32:18 -07:00
|
|
|
"leon@agentlinker.ai": "agentlinker",
|
2026-05-05 05:33:23 -07:00
|
|
|
"santoshhumagain1887@gmail.com": "npmisantosh",
|
2026-05-12 15:03:00 -07:00
|
|
|
"39641663+luarss@users.noreply.github.com": "luarss",
|
2026-05-12 15:04:37 -07:00
|
|
|
"16263913+zccyman@users.noreply.github.com": "zccyman",
|
2026-05-17 16:26:00 -07:00
|
|
|
"zccyman@users.noreply.github.com": "zccyman", # PR #26998 (auxiliary fallback chain)
|
2026-05-12 15:04:37 -07:00
|
|
|
"ahmetosrak@Ahmet-MacBook-Air.local": "Osraka",
|
|
|
|
|
"98612432+Osraka@users.noreply.github.com": "Osraka",
|
2026-05-12 16:34:12 -07:00
|
|
|
"112634774+ryptotalent@users.noreply.github.com": "ryptotalent",
|
2026-05-12 16:36:01 -07:00
|
|
|
"270097726+hookinglau@users.noreply.github.com": "hookinglau",
|
2026-05-12 16:37:54 -07:00
|
|
|
"5029547+AllynSheep@users.noreply.github.com": "AllynSheep",
|
|
|
|
|
"allyn0306@gmail.com": "AllynSheep",
|
2026-05-12 16:39:51 -07:00
|
|
|
"46887634+aqilaziz@users.noreply.github.com": "aqilaziz",
|
|
|
|
|
"gonzes7@gmail.com": "aqilaziz",
|
2026-05-12 16:42:25 -07:00
|
|
|
"6966326+laoli-no1@users.noreply.github.com": "laoli-no1",
|
|
|
|
|
"laoli_no1@163.com": "laoli-no1",
|
2026-05-12 16:43:56 -07:00
|
|
|
"39730900+NorethSea@users.noreply.github.com": "NorethSea",
|
|
|
|
|
"963979204@qq.com": "NorethSea",
|
2026-05-12 16:44:59 -07:00
|
|
|
"2283389+JamesX88@users.noreply.github.com": "JamesX88",
|
|
|
|
|
"JamesX88@users.noreply.github.com": "JamesX88",
|
2026-05-05 05:35:18 -07:00
|
|
|
"novax635@gmail.com": "novax635",
|
2026-05-05 05:37:42 -07:00
|
|
|
"krionex1@gmail.com": "Krionex",
|
2026-05-05 05:39:13 -07:00
|
|
|
"rxdxxxx@users.noreply.github.com": "rxdxxxx",
|
2026-05-05 05:40:04 -07:00
|
|
|
"ma.haohao2@xydigit.com": "MaHaoHao-ch",
|
2026-05-05 04:09:21 -07:00
|
|
|
"29756950+revaraver@users.noreply.github.com": "revaraver",
|
2026-05-05 04:14:40 -07:00
|
|
|
"nexus@eptic.me": "TheEpTic",
|
2026-05-05 04:16:12 -07:00
|
|
|
"74554762+wmagev@users.noreply.github.com": "wmagev",
|
2026-05-05 04:18:28 -07:00
|
|
|
"ashermorse@icloud.com": "ashermorse",
|
2026-05-05 04:40:12 -07:00
|
|
|
"happy5318@users.noreply.github.com": "happy5318",
|
2026-05-07 06:24:35 -07:00
|
|
|
"anatoliygranichenko@gmail.com": "wabrent",
|
2026-05-07 05:58:38 -07:00
|
|
|
"cash.williams@acquia.com": "CashWilliams",
|
2026-05-05 04:22:59 -07:00
|
|
|
"chengoak@users.noreply.github.com": "chengoak",
|
2026-05-05 04:24:10 -07:00
|
|
|
"mrhanoi@outlook.com": "qxxaa",
|
2026-05-06 13:30:34 -07:00
|
|
|
"guillaume.meyer@outlook.com": "guillaumemeyer",
|
2026-05-03 05:34:07 -07:00
|
|
|
"emelyanenko.kirill@gmail.com": "EmelyanenkoK",
|
2026-05-05 05:34:47 -07:00
|
|
|
"lazycat.manatee@gmail.com": "manateelazycat",
|
2026-05-05 13:26:03 -07:00
|
|
|
"bzarnitz13@gmail.com": "Beandon13",
|
2026-05-05 13:31:32 -07:00
|
|
|
"tony@tonysimons.dev": "asimons81",
|
2026-05-05 13:42:53 -07:00
|
|
|
"jetha@google.com": "jethac",
|
2026-05-05 13:43:58 -07:00
|
|
|
"jani@0xhoneyjar.xyz": "deep-name",
|
feat(gateway): add LINE Messaging API platform plugin (#23197)
* feat(gateway): add LINE Messaging API platform plugin
Adds LINE as a bundled platform plugin under `plugins/platforms/line/`,
synthesized from the strongest pieces of seven open community PRs. The
adapter requires zero core edits — `Platform("line")` is auto-discovered
via the bundled-plugin scan in `gateway/config.py`, and all hooks
(setup, env-enablement, cron delivery, standalone send) are wired
through `register_platform()` kwargs the way IRC and Teams do it.
Highlights merged into one plugin:
- **Reply token preferred, Push fallback.** Try the free reply token
first (single-use, ~60s TTL); fall back to metered Push when the
token is absent, expired, or rejected. (PR #21023)
- **Slow-LLM Template Buttons postback.** When the LLM is still running
past `LINE_SLOW_RESPONSE_THRESHOLD` (default 45s), the adapter burns
the original reply token to send a "Get answer" button bubble. The
user taps it to fetch the cached answer via a fresh reply token —
also free. State machine: PENDING → READY → DELIVERED, ERROR for
cancelled runs (orphan resolves to `LINE_INTERRUPTED_TEXT` after
/stop). Set threshold to 0 to disable. (PR #18153)
- **Three-allowlist gating** — separate user / group / room allowlists
with `LINE_ALLOW_ALL_USERS=true` dev-only escape hatch. (PR #18153)
- **Markdown URL preservation.** Strip bold/italic/code-fence/heading
markers (LINE renders them literally) but keep `[label](url)` →
`label (url)` so URLs stay tappable. (PR #18153)
- **System-message bypass** for `⚡ Interrupting`, `⏳ Queued`, etc. —
busy-acks reach the user as visible bubbles instead of being
swallowed into the postback cache. (PR #18153)
- **Media via public HTTPS URLs.** LINE doesn't accept binary uploads;
images/audio/video must be HTTPS-reachable. The adapter serves
registered tempfiles under `/line/media/<token>/<filename>` from the
same aiohttp app. Allowed-roots traversal guard covers
`tempfile.gettempdir()`, `/tmp` (→ `/private/tmp` on macOS), and
`HERMES_HOME`. `LINE_PUBLIC_URL` overrides URL construction for
setups behind tunnels/proxies. (PR #8398)
- **5-message-per-call batching.** LINE rejects >5 messages per
Reply/Push; smart-chunker caps text at 4500 chars per bubble.
- **Inbound dedup** via `webhookEventId` LRU. (PR #21023)
- **Self-message filter** via `/v2/bot/info` userId lookup. (PR #21023)
- **Loading-animation indicator** wired to LINE's `chat/loading/start`
endpoint, DM-only (LINE rejects it for groups/rooms). (PR #21023)
- **Out-of-process cron delivery** via `_standalone_send`, so
`deliver: line` cron jobs work even when cron runs detached from
the gateway.
- **Webhook hardening** — 1 MiB body cap, constant-time HMAC-SHA256
signature verification, dedup, scoped lock so two profiles can't
bind the same channel.
Validation
----------
- `scripts/run_tests.sh tests/gateway/test_line_plugin.py` →
73 passed in 1.05s
- `scripts/run_tests.sh tests/gateway/test_line_plugin.py
tests/gateway/test_irc_adapter.py
tests/gateway/test_plugin_platform_interface.py
tests/gateway/test_platform_registry.py
tests/gateway/test_config.py` → 193 passed, 7 skipped
- E2E import + register + signature roundtrip + `Platform("line")`
bundled-plugin discovery verified against current `origin/main`.
Closes the seven open LINE PRs (#18153, #16832, #6676, #21023, #14942,
#14988, #8398) by superseding them with a single plugin-form
implementation that takes the best idea from each.
Co-authored-by: pwlee <32443648+leepoweii@users.noreply.github.com>
Co-authored-by: Jetha Chan <jetha@google.com>
Co-authored-by: Cattia <openclaw@liyangchen.me>
Co-authored-by: perng <charles@perng.com>
Co-authored-by: Soichiro Yoshimura <soichiro0111.dev@gmail.com>
Co-authored-by: David Zhou <77736378+David-0x221Eight@users.noreply.github.com>
Co-authored-by: Yu-ga <74749461+yuga-hashimoto@users.noreply.github.com>
* docs(platforms): document platform-specific slow-LLM UX pattern
Add a 'Platform-Specific Slow-LLM UX' section to the platform-adapter
developer guide covering the _keep_typing override pattern that LINE
uses for its Template Buttons postback flow.
Three subsections:
- Pattern: subclass _keep_typing to layer mid-flight UX (with code)
- Pattern: subclass send to route through a cache instead of sending
- When this pattern is appropriate (vs. always-Push fallback)
Plus a short pointer in gateway/platforms/ADDING_A_PLATFORM.md so
tree-readers find the prose walkthrough on the docsite.
Filed because the LINE plugin (PR #23197) was the first bundled
adapter to need this pattern — every prior plugin (irc, teams,
google_chat) handles slow responses with the default typing-loop and
a regular send_text. Documenting now while the rationale is fresh.
---------
Co-authored-by: pwlee <32443648+leepoweii@users.noreply.github.com>
Co-authored-by: Jetha Chan <jetha@google.com>
Co-authored-by: Cattia <openclaw@liyangchen.me>
Co-authored-by: perng <charles@perng.com>
Co-authored-by: Soichiro Yoshimura <soichiro0111.dev@gmail.com>
Co-authored-by: David Zhou <77736378+David-0x221Eight@users.noreply.github.com>
Co-authored-by: Yu-ga <74749461+yuga-hashimoto@users.noreply.github.com>
2026-05-10 06:40:46 -07:00
|
|
|
# LINE messaging plugin (synthesis PR)
|
|
|
|
|
"32443648+leepoweii@users.noreply.github.com": "leepoweii",
|
|
|
|
|
"openclaw@liyangchen.me": "liyoungc",
|
|
|
|
|
"charles@perng.com": "perng",
|
|
|
|
|
"soichiro0111.dev@gmail.com": "soichiyo",
|
|
|
|
|
"0xde@pieverse.io": "David-0x221Eight",
|
|
|
|
|
"77736378+David-0x221Eight@users.noreply.github.com": "David-0x221Eight",
|
|
|
|
|
"74749461+yuga-hashimoto@users.noreply.github.com": "yuga-hashimoto",
|
2026-05-05 13:48:17 -07:00
|
|
|
"xiangyong@zspace.cn": "CES4751",
|
2026-05-05 13:51:42 -07:00
|
|
|
"harish.kukreja@gmail.com": "counterposition",
|
2026-05-15 01:49:40 -07:00
|
|
|
"nidhi2894@gmail.com": "nidhi-singh02",
|
2026-05-05 13:52:36 -07:00
|
|
|
"35294173+Fearvox@users.noreply.github.com": "Fearvox",
|
2026-05-05 13:54:26 -07:00
|
|
|
"hypnus.yuan@gmail.com": "Hypnus-Yuan",
|
2026-05-05 13:55:10 -07:00
|
|
|
"15558128926@qq.com": "xsfX20",
|
2026-05-05 14:11:05 -07:00
|
|
|
"binhnt.ht.92@gmail.com": "binhnt92",
|
2026-05-05 14:11:58 -07:00
|
|
|
"johnny@Jons-MBA-M4.local": "acesjohnny",
|
2026-05-05 14:12:38 -07:00
|
|
|
"1581133593@qq.com": "liu-collab",
|
2026-04-18 02:09:06 +08:00
|
|
|
"haidaoe@proton.me": "haidao1919",
|
2026-05-05 14:14:55 -07:00
|
|
|
"50561768+zhanggttry@users.noreply.github.com": "zhanggttry",
|
2026-05-05 14:16:23 -07:00
|
|
|
"formulahendry@gmail.com": "formulahendry",
|
2026-05-05 15:12:37 -07:00
|
|
|
"93757150+bogerman1@users.noreply.github.com": "bogerman1",
|
2026-05-05 17:23:11 -07:00
|
|
|
"132852777+rob-maron@users.noreply.github.com": "rob-maron",
|
2026-04-27 21:16:57 -07:00
|
|
|
# Matrix parity salvage batch (April 2026)
|
|
|
|
|
"sr@samirusani": "samrusani",
|
|
|
|
|
"angelclaw@AngelMacBook.local": "angel12",
|
|
|
|
|
"charles@cryptoassetrecovery.com": "charles-brooks",
|
2026-04-30 10:49:07 -07:00
|
|
|
# DeepSeek v4 + Kimi thinking-mode reasoning_content salvage (April 2026)
|
|
|
|
|
"luwinyang@deepseek.com": "lsdsjy",
|
|
|
|
|
"season.saw@gmail.com": "season179",
|
2026-04-27 21:16:57 -07:00
|
|
|
"heathley@Heathley-MacBook-Air.local": "heathley",
|
2026-05-09 02:31:34 -07:00
|
|
|
"maliyldzhn@gmail.com": "heathley",
|
2026-04-29 21:06:55 -07:00
|
|
|
"vlad19@gmail.com": "dandaka",
|
2026-04-27 21:16:57 -07:00
|
|
|
"adamrummer@gmail.com": "cyclingwithelephants",
|
2026-05-07 05:04:37 -07:00
|
|
|
# Temporary tool-progress cleanup salvage (May 2026)
|
|
|
|
|
"Mrcharlesiv@gmail.com": "mrcharlesiv",
|
2026-04-27 21:16:57 -07:00
|
|
|
"nbot@liizfq.top": "liizfq",
|
2026-04-27 08:35:13 -07:00
|
|
|
"274096618+hermes-agent-dhabibi@users.noreply.github.com": "dhabibi",
|
2026-04-28 06:42:45 -07:00
|
|
|
"dejie.guo@gmail.com": "JayGwod",
|
2026-05-03 16:54:06 -07:00
|
|
|
"133716830+0xKingBack@users.noreply.github.com": "0xKingBack",
|
2026-05-03 17:09:33 -07:00
|
|
|
"daixin1204@gmail.com": "SimbaKingjoe",
|
feat(gateway): native send_multiple_images for Telegram, Discord, Slack, Mattermost, Email
Ports PR #17888's send_multiple_images ABC to every gateway platform that
has a native multi-attachment API, so images arrive as a single bundled
message instead of N separate ones.
Native overrides:
- Telegram: send_media_group (10 photos per album, chunks over); animated
GIFs peeled off and routed through send_animation (albums don't support
animations)
- Discord: channel.send(files=[...]) (10 attachments per message, chunks
over); URL images downloaded into BytesIO so they render inline; forum
channels use create_thread with files=[...]
- Slack: files_upload_v2(file_uploads=[...]) (10 per call, chunks over);
respects thread_ts; records thread participation
- Mattermost: single post with file_ids list (5 per post — Mattermost cap,
chunks over)
- Email: single SMTP message with multiple MIME attachments (no chunk cap,
SMTP size governs); remote URLs remain linked in body (parity with
existing send_image)
All platforms fall back to the base per-image loop on any failure, so a
single bad image in a batch never loses the rest.
Matrix, WhatsApp, and single-attachment platforms (BlueBubbles, Feishu,
WeCom, WeChat, DingTalk) continue to use the base default loop — their
server APIs only accept one attachment per message anyway.
Tests: adds tests/gateway/test_send_multiple_images.py with 19 targeted
tests covering base default loop, chunking, animation peel-off, fallback
paths, and empty-batch no-ops across all five new overrides.
Co-authored-by: Maxence Groine <maxence@groine.fr>
2026-04-30 03:39:06 -07:00
|
|
|
"maxence@groine.fr": "MaxyMoos",
|
2026-05-03 08:16:17 -07:00
|
|
|
"61830395+leprincep35700@users.noreply.github.com": "leprincep35700",
|
2026-04-30 02:33:23 -07:00
|
|
|
# OpenViking viking_read salvage (April 2026)
|
|
|
|
|
"hitesh@gmail.com": "htsh",
|
|
|
|
|
"pty819@outlook.com": "pty819",
|
|
|
|
|
"pty819@users.noreply.github.com": "pty819",
|
2026-05-13 22:01:41 -07:00
|
|
|
"14341805+pty819@users.noreply.github.com": "pty819",
|
2026-04-30 02:33:23 -07:00
|
|
|
"517024110@qq.com": "chennest",
|
2026-04-30 10:31:38 -07:00
|
|
|
# Curator fixes (Apr 30 2026)
|
|
|
|
|
"yuxiangl490@gmail.com": "y0shua1ee",
|
|
|
|
|
"manmit0x@gmail.com": "0xDevNinja",
|
2026-05-05 04:31:44 -07:00
|
|
|
"stevekelly622@gmail.com": "steezkelly",
|
2026-05-15 05:03:43 -07:00
|
|
|
"brian@dralth.com": "btorresgil",
|
2026-05-05 15:06:01 -07:00
|
|
|
"momowind@gmail.com": "momowind",
|
|
|
|
|
"clockwork-codex@users.noreply.github.com": "misery-hl",
|
|
|
|
|
"207811921+misery-hl@users.noreply.github.com": "misery-hl",
|
2026-05-09 17:02:37 +05:30
|
|
|
"20nik.nosov21@gmail.com": "nik1t7n",
|
|
|
|
|
"90299797+nik1t7n@users.noreply.github.com": "nik1t7n",
|
2026-05-05 15:20:22 -07:00
|
|
|
"suncokret@protonmail.com": "suncokret12",
|
|
|
|
|
"mio.imoto.ai@gmail.com": "mioimotoai-lgtm",
|
2026-04-30 01:03:49 -07:00
|
|
|
"aamirjawaid@microsoft.com": "heyitsaamir",
|
2026-04-26 19:01:13 -07:00
|
|
|
"johnnncenaaa77@gmail.com": "johnncenae",
|
2026-04-28 01:49:31 -07:00
|
|
|
"thomasjhon6666@gmail.com": "ThomassJonax",
|
2026-04-26 08:24:25 -07:00
|
|
|
"focusflow.app.help@gmail.com": "yes999zc",
|
2026-04-30 04:30:00 -07:00
|
|
|
"rob@atlas.lan": "rmoen",
|
2026-05-01 09:08:18 +05:30
|
|
|
# Slack ephemeral slash-ack salvage (May 2026)
|
|
|
|
|
"probepark@users.noreply.github.com": "probepark",
|
2026-05-02 02:19:58 +05:30
|
|
|
# Slack batch salvage (May 2026)
|
|
|
|
|
"280484231+prive-fe-bot@users.noreply.github.com": "priveperfumes",
|
|
|
|
|
"amr@ghanem.sa": "amroessam",
|
|
|
|
|
"paperlantern.agent@gmail.com": "Hinotoi-agent",
|
|
|
|
|
"valda@underscore.jp": "valda",
|
2026-04-29 04:56:33 -07:00
|
|
|
"162235745+0z1-ghb@users.noreply.github.com": "0z1-ghb",
|
2026-04-28 01:30:10 -07:00
|
|
|
"yes999zc@163.com": "yes999zc",
|
2026-04-23 02:36:27 -07:00
|
|
|
"343873859@qq.com": "DrStrangerUJN",
|
2026-04-29 14:17:42 -07:00
|
|
|
"252818347@qq.com": "hejuntt1014",
|
2026-04-24 05:15:06 -07:00
|
|
|
"uzmpsk.dilekakbas@gmail.com": "dlkakbs",
|
2026-04-28 05:00:26 -07:00
|
|
|
"beliefanx@gmail.com": "BeliefanX",
|
fix(profiles): keep validate_profile_name strict; callers normalize first
Follow-up to @changchun989's cherry-pick: reverts the validate-via-
normalize change so validate_profile_name remains a strict regex check
on the input AS-GIVEN. Callers that accept mixed-case user input
(dashboard UI, CLI args, import flows) call normalize_profile_name()
first, then validate the result. This keeps validate honest about
what the on-disk directory name must look like — e.g. ' jules '
(trailing whitespace) is now rejected instead of silently trimmed
and accepted.
- validate_profile_name: strict lowercase/regex check again, 'UPPER'
back in the invalid-names parametrize
- 8 call sites in profiles.py (create_profile, delete_profile,
set_active_profile, export_profile, import_profile, rename_profile,
resolve_profile_env, plus the clone_from branch): swap the
normalize-then-validate order
- scripts/release.py: add changchun989@proton.me -> changchun989 to
AUTHOR_MAP so CI doesn't block on the unmapped contributor email
All kanban + profile tests pass (268 across test_profiles.py +
test_kanban_db.py + test_kanban_core_functionality.py, plus 73 in
test_kanban_tools.py + test_kanban_dashboard_plugin.py).
Closes #18498.
2026-05-04 04:44:00 -07:00
|
|
|
"changchun989@proton.me": "changchun989",
|
2026-04-23 15:07:16 -07:00
|
|
|
"jefferson@heimdallstrategy.com": "Mind-Dragon",
|
2026-04-29 12:09:06 -07:00
|
|
|
"44753291+Nanako0129@users.noreply.github.com": "Nanako0129",
|
2026-04-28 01:42:33 -07:00
|
|
|
"steve.westerhouse@origami-analytics.com": "westers",
|
2026-04-29 08:17:50 -07:00
|
|
|
"yeyitech@users.noreply.github.com": "yeyitech",
|
2026-04-29 08:23:14 -07:00
|
|
|
"260878550+beenherebefore@users.noreply.github.com": "beenherebefore",
|
2026-04-29 10:29:59 -07:00
|
|
|
"79389617+txbxxx@users.noreply.github.com": "txbxxx",
|
2026-04-29 08:07:59 -07:00
|
|
|
"liuhao03@bilibili.com": "liuhao1024",
|
2026-04-23 15:12:30 -07:00
|
|
|
"130918800+devorun@users.noreply.github.com": "devorun",
|
2026-04-28 01:27:55 -07:00
|
|
|
"surat.s@itm.kmutnb.ac.th": "beesrsj2500",
|
|
|
|
|
"beesr@bee.localdomain": "beesrsj2500",
|
2026-04-30 20:37:46 -07:00
|
|
|
"mind-dragon@nous.research": "Mind-Dragon",
|
|
|
|
|
"juntingpublic@gmail.com": "JustinUssuri",
|
2026-04-28 04:49:35 -07:00
|
|
|
"mtf201013@gmail.com": "ma-pony",
|
2026-04-26 18:36:54 -07:00
|
|
|
"sonoyuncudmr@gmail.com": "Sonoyunchu",
|
2026-04-29 21:05:00 -07:00
|
|
|
"43525405+yatesjalex@users.noreply.github.com": "yatesjalex",
|
2026-04-23 15:14:47 -07:00
|
|
|
"maks.mir@yahoo.com": "say8hi",
|
2026-04-28 18:51:03 +05:30
|
|
|
"27719690+Mirac1eSky@users.noreply.github.com": "Mirac1eSky",
|
2026-04-24 21:23:14 +07:00
|
|
|
"web3blind@users.noreply.github.com": "web3blind",
|
2026-04-24 15:18:09 -07:00
|
|
|
"julia@alexland.us": "alexg0bot",
|
2026-04-27 06:38:30 -07:00
|
|
|
"christian@scheid.tech": "scheidti",
|
2026-04-30 23:08:46 -07:00
|
|
|
# Moonshot schema anyOf+enum salvage (May 2026)
|
|
|
|
|
"git@local.invalid": "hendrixfreire",
|
2026-04-24 16:02:58 -07:00
|
|
|
"1060770+benjaminsehl@users.noreply.github.com": "benjaminsehl",
|
2026-04-25 18:22:49 -07:00
|
|
|
"nerijusn76@gmail.com": "Nerijusas",
|
2026-05-06 11:02:50 +05:30
|
|
|
# Compaction salvage batch (May 2026)
|
|
|
|
|
"MacroAnarchy@users.noreply.github.com": "MacroAnarchy",
|
2026-04-26 18:13:30 -07:00
|
|
|
"itonov@proton.me": "Ito-69",
|
2026-04-26 18:40:02 -07:00
|
|
|
"glesstech@gmail.com": "georgeglessner",
|
2026-04-26 12:54:20 -07:00
|
|
|
"maxim.smetanin@gmail.com": "maxims-oss",
|
2026-05-10 10:40:31 +05:30
|
|
|
# Codex Spark restoration salvage (May 2026)
|
|
|
|
|
"olegwn@gmail.com": "nederev",
|
|
|
|
|
"vesper@askclaw.dev": "askclaw-vesper",
|
2026-04-28 01:20:02 -07:00
|
|
|
"nazirulhafiy@gmail.com": "nazirulhafiy",
|
2026-04-26 21:27:31 -07:00
|
|
|
"CREWorx@users.noreply.github.com": "BadTechBandit",
|
2026-04-26 18:57:45 -07:00
|
|
|
"yoimexex@gmail.com": "Yoimex",
|
2026-04-26 21:43:58 -07:00
|
|
|
"6548898+romanornr@users.noreply.github.com": "romanornr",
|
2026-04-27 04:57:39 -07:00
|
|
|
"foxion37@gmail.com": "foxion37",
|
2026-04-27 07:41:42 -07:00
|
|
|
"bloodcarter@gmail.com": "bloodcarter",
|
2026-04-28 18:28:49 -07:00
|
|
|
"scott@scotttrinh.com": "scotttrinh",
|
2026-04-30 19:52:58 -07:00
|
|
|
"quocanh261997@gmail.com": "quocanh261997",
|
2026-05-19 23:09:12 -07:00
|
|
|
"savanne.kham@protonmail.com": "savanne-kham", # PR #28958 salvage (strip tool_name for strict providers)
|
2026-03-12 01:35:47 -07:00
|
|
|
# contributors (from noreply pattern)
|
2026-04-23 03:06:05 -07:00
|
|
|
"david.vv@icloud.com": "davidvv",
|
2026-04-21 19:42:36 -07:00
|
|
|
"wangqiang@wangqiangdeMac-mini.local": "xiaoqiang243",
|
2026-04-17 18:56:06 -07:00
|
|
|
"snreynolds2506@gmail.com": "snreynolds",
|
2026-03-12 01:35:47 -07:00
|
|
|
"35742124+0xbyt4@users.noreply.github.com": "0xbyt4",
|
2026-04-20 11:55:50 -07:00
|
|
|
"71184274+MassiveMassimo@users.noreply.github.com": "MassiveMassimo",
|
|
|
|
|
"massivemassimo@users.noreply.github.com": "MassiveMassimo",
|
2026-03-12 01:35:47 -07:00
|
|
|
"82637225+kshitijk4poor@users.noreply.github.com": "kshitijk4poor",
|
2026-04-22 03:35:51 -07:00
|
|
|
"keifergu@tencent.com": "keifergu",
|
2026-04-16 09:22:04 -07:00
|
|
|
"kshitijk4poor@users.noreply.github.com": "kshitijk4poor",
|
2026-04-29 21:38:50 -04:00
|
|
|
"SHL0MS@users.noreply.github.com": "SHL0MS",
|
2026-04-22 05:23:59 -07:00
|
|
|
"abner.the.foreman@agentmail.to": "Abnertheforeman",
|
2026-04-29 08:25:27 -07:00
|
|
|
"adam.manning@pro-serveinc.com": "amanning3390",
|
2026-04-24 14:26:30 -07:00
|
|
|
"thomasgeorgevii09@gmail.com": "tochukwuada",
|
2026-04-30 03:27:46 -07:00
|
|
|
"sb@wmc.sh": "zicochaos",
|
2026-04-22 05:51:12 -07:00
|
|
|
"harryykyle1@gmail.com": "hharry11",
|
2026-04-18 14:37:21 -07:00
|
|
|
"kshitijk4poor@gmail.com": "kshitijk4poor",
|
2026-04-26 19:06:13 -07:00
|
|
|
"1294707+Tosko4@users.noreply.github.com": "Tosko4",
|
2026-04-24 03:01:43 -07:00
|
|
|
"keira.voss94@gmail.com": "keiravoss94",
|
2026-03-12 01:35:47 -07:00
|
|
|
"16443023+stablegenius49@users.noreply.github.com": "stablegenius49",
|
2026-04-25 18:38:56 -07:00
|
|
|
"fqsy1416@gmail.com": "EKKOLearnAI",
|
2026-04-26 10:28:19 -07:00
|
|
|
"octo-patch@github.com": "octo-patch",
|
2026-04-26 10:44:22 -07:00
|
|
|
"math0r-be@github.com": "math0r-be",
|
2026-04-24 16:42:15 -07:00
|
|
|
"simbamax99@gmail.com": "simbam99",
|
2026-04-25 18:02:13 -07:00
|
|
|
"iris@growthpillars.co": "irispillars",
|
2026-03-12 01:35:47 -07:00
|
|
|
"185121704+stablegenius49@users.noreply.github.com": "stablegenius49",
|
|
|
|
|
"101283333+batuhankocyigit@users.noreply.github.com": "batuhankocyigit",
|
2026-04-22 14:45:18 -07:00
|
|
|
"255305877+ismell0992-afk@users.noreply.github.com": "ismell0992-afk",
|
2026-04-24 15:15:41 -07:00
|
|
|
"cyprian@ironin.pl": "iRonin",
|
2026-04-17 06:26:17 -07:00
|
|
|
"valdi.jorge@gmail.com": "jvcl",
|
2026-04-24 14:56:14 -07:00
|
|
|
"q19dcp@gmail.com": "aj-nt",
|
2026-04-24 15:21:41 -07:00
|
|
|
"ebukau84@gmail.com": "UgwujaGeorge",
|
2026-04-21 00:52:03 -07:00
|
|
|
"francip@gmail.com": "francip",
|
2026-04-21 01:46:59 -07:00
|
|
|
"omni@comelse.com": "omnissiah-comelse",
|
2026-04-20 20:49:39 -07:00
|
|
|
"oussama.redcode@gmail.com": "mavrickdeveloper",
|
2026-03-12 01:35:47 -07:00
|
|
|
"126368201+vilkasdev@users.noreply.github.com": "vilkasdev",
|
|
|
|
|
"137614867+cutepawss@users.noreply.github.com": "cutepawss",
|
|
|
|
|
"96793918+memosr@users.noreply.github.com": "memosr",
|
2026-04-29 21:06:00 -07:00
|
|
|
"mehmet.sr35@gmail.com": "memosr",
|
2026-04-16 20:36:59 -07:00
|
|
|
"milkoor@users.noreply.github.com": "milkoor",
|
2026-04-16 21:40:35 -07:00
|
|
|
"xuerui911@gmail.com": "Fatty911",
|
2026-03-12 01:35:47 -07:00
|
|
|
"131039422+SHL0MS@users.noreply.github.com": "SHL0MS",
|
|
|
|
|
"77628552+raulvidis@users.noreply.github.com": "raulvidis",
|
|
|
|
|
"145567217+Aum08Desai@users.noreply.github.com": "Aum08Desai",
|
|
|
|
|
"256820943+kshitij-eliza@users.noreply.github.com": "kshitij-eliza",
|
2026-04-24 04:47:04 -07:00
|
|
|
"jiechengwu@pony.ai": "Jason2031",
|
2026-03-12 01:35:47 -07:00
|
|
|
"44278268+shitcoinsherpa@users.noreply.github.com": "shitcoinsherpa",
|
|
|
|
|
"104278804+Sertug17@users.noreply.github.com": "Sertug17",
|
|
|
|
|
"112503481+caentzminger@users.noreply.github.com": "caentzminger",
|
|
|
|
|
"258577966+voidborne-d@users.noreply.github.com": "voidborne-d",
|
2026-04-28 01:15:46 -07:00
|
|
|
"3820588+ddupont808@users.noreply.github.com": "ddupont808",
|
2026-04-25 18:23:36 -07:00
|
|
|
"liusway405@gmail.com": "voidborne-d",
|
2026-04-25 04:45:27 -07:00
|
|
|
"xydarcher@uestc.edu.cn": "Readon",
|
2026-04-20 05:04:26 -07:00
|
|
|
"sir_even@icloud.com": "sirEven",
|
|
|
|
|
"36056348+sirEven@users.noreply.github.com": "sirEven",
|
2026-03-12 01:35:47 -07:00
|
|
|
"70424851+insecurejezza@users.noreply.github.com": "insecurejezza",
|
2026-04-30 20:19:03 -07:00
|
|
|
"jezzahehn@gmail.com": "JezzaHehn",
|
2026-05-07 05:44:53 -07:00
|
|
|
"barnacleboy.jezzahehn@agentmail.to": "JezzaHehn",
|
2026-04-19 11:48:14 -07:00
|
|
|
"254021826+dodo-reach@users.noreply.github.com": "dodo-reach",
|
2026-03-12 01:35:47 -07:00
|
|
|
"259807879+Bartok9@users.noreply.github.com": "Bartok9",
|
2026-04-28 01:26:11 -07:00
|
|
|
"270082434+crayfish-ai@users.noreply.github.com": "crayfish-ai",
|
2026-04-15 15:07:11 -07:00
|
|
|
"241404605+MestreY0d4-Uninter@users.noreply.github.com": "MestreY0d4-Uninter",
|
2026-04-14 14:19:49 -07:00
|
|
|
"268667990+Roy-oss1@users.noreply.github.com": "Roy-oss1",
|
2026-04-15 22:37:46 -07:00
|
|
|
"27917469+nosleepcassette@users.noreply.github.com": "nosleepcassette",
|
2026-04-14 17:19:55 +00:00
|
|
|
"241404605+MestreY0d4-Uninter@users.noreply.github.com": "MestreY0d4-Uninter",
|
2026-04-16 05:51:37 -07:00
|
|
|
"109555139+davetist@users.noreply.github.com": "davetist",
|
2026-04-17 05:40:44 -07:00
|
|
|
"39405770+yyq4193@users.noreply.github.com": "yyq4193",
|
2026-04-17 04:09:47 -07:00
|
|
|
"Asunfly@users.noreply.github.com": "Asunfly",
|
2026-04-18 12:35:00 -07:00
|
|
|
"2500400+honghua@users.noreply.github.com": "honghua",
|
2026-04-20 05:10:02 -07:00
|
|
|
"462836+jplew@users.noreply.github.com": "jplew",
|
2026-04-18 18:52:41 -07:00
|
|
|
"nish3451@users.noreply.github.com": "nish3451",
|
2026-04-19 05:19:51 -07:00
|
|
|
"Mibayy@users.noreply.github.com": "Mibayy",
|
2026-04-20 05:15:35 -07:00
|
|
|
"mibayy@users.noreply.github.com": "Mibayy",
|
2026-05-10 22:24:50 -07:00
|
|
|
"mibay@clawhub.io": "Mibayy",
|
2026-05-15 01:33:59 -07:00
|
|
|
"louismichalot@hotmail.com": "Mibayy",
|
2026-04-19 15:34:02 +05:30
|
|
|
"135070653+sgaofen@users.noreply.github.com": "sgaofen",
|
2026-04-26 11:46:01 -07:00
|
|
|
"lzy.dev@gmail.com": "zhiyanliu",
|
2026-04-26 12:19:02 -07:00
|
|
|
"me@janstepanovsky.cz": "hhhonzik",
|
2026-04-26 12:28:05 -07:00
|
|
|
"139848623+hhuang91@users.noreply.github.com": "hhuang91",
|
2026-04-26 12:34:14 -07:00
|
|
|
"s.ozaki@ebinou.net": "Satoshi-agi",
|
|
|
|
|
"10774721+kunlabs@users.noreply.github.com": "kunlabs",
|
2026-04-26 13:02:31 -07:00
|
|
|
"110560187+Wang-tianhao@users.noreply.github.com": "Wang-tianhao",
|
2026-04-26 18:16:28 -07:00
|
|
|
"170458616+ghostmfr@users.noreply.github.com": "ghostmfr",
|
2026-04-26 18:25:16 -07:00
|
|
|
"1848670+mewwts@users.noreply.github.com": "mewwts",
|
2026-04-26 18:33:09 -07:00
|
|
|
"1930707+haru398801@users.noreply.github.com": "haru398801",
|
|
|
|
|
"rapabelias@gmail.com": "badgerbees",
|
|
|
|
|
"xnb888@proton.me": "xnbi",
|
2026-04-26 21:04:47 -07:00
|
|
|
"xiahu889889@proton.me": "xiahu88988",
|
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
|
|
|
"nocoo@users.noreply.github.com": "nocoo",
|
|
|
|
|
"30841158+n-WN@users.noreply.github.com": "n-WN",
|
2026-04-22 15:25:58 +08:00
|
|
|
"tsuijinglei@gmail.com": "hiddenpuppy",
|
2026-04-26 08:39:12 -07:00
|
|
|
"buraysandro9@gmail.com": "ygd58",
|
2026-04-22 18:46:21 +05:30
|
|
|
"jerome@clawwork.ai": "HiddenPuppy",
|
2026-04-24 16:05:05 -07:00
|
|
|
"jerome.benoit@sap.com": "jerome-benoit",
|
2026-04-23 02:54:26 -07:00
|
|
|
"wysie@users.noreply.github.com": "Wysie",
|
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
|
|
|
"leoyuan0099@gmail.com": "keyuyuan",
|
|
|
|
|
"bxzt2006@163.com": "Only-Code-A",
|
|
|
|
|
"i@troy-y.org": "TroyMitchell911",
|
|
|
|
|
"mygamez@163.com": "zhongyueming1121",
|
|
|
|
|
"hansnow@users.noreply.github.com": "hansnow",
|
2026-04-21 05:45:50 -07:00
|
|
|
"134848055+UNLINEARITY@users.noreply.github.com": "UNLINEARITY",
|
2026-04-21 13:29:50 -07:00
|
|
|
"ben.burtenshaw@gmail.com": "burtenshaw",
|
2026-04-22 21:15:24 +05:30
|
|
|
"roopaknijhara@gmail.com": "rnijhara",
|
2026-04-23 04:49:41 -07:00
|
|
|
"josephzcan@gmail.com": "j0sephz",
|
2026-03-12 01:35:47 -07:00
|
|
|
# contributors (manual mapping from git names)
|
2026-04-15 13:03:31 +00:00
|
|
|
"ahmedsherif95@gmail.com": "asheriif",
|
2026-04-23 03:24:38 -07:00
|
|
|
"dyxushuai@gmail.com": "dyxushuai",
|
|
|
|
|
"33860762+etcircle@users.noreply.github.com": "etcircle",
|
2026-04-17 19:03:37 -07:00
|
|
|
"liujinkun@bytedance.com": "liujinkun2025",
|
2026-03-12 01:35:47 -07:00
|
|
|
"dmayhem93@gmail.com": "dmahan93",
|
2026-04-21 00:36:12 -07:00
|
|
|
"fr@tecompanytea.com": "ifrederico",
|
2026-04-20 13:11:03 -07:00
|
|
|
"cdanis@gmail.com": "cdanis",
|
2026-03-12 01:35:47 -07:00
|
|
|
"samherring99@gmail.com": "samherring99",
|
|
|
|
|
"desaiaum08@gmail.com": "Aum08Desai",
|
|
|
|
|
"shannon.sands.1979@gmail.com": "shannonsands",
|
|
|
|
|
"shannon@nousresearch.com": "shannonsands",
|
2026-04-21 00:44:45 -07:00
|
|
|
"abdi.moya@gmail.com": "AxDSan",
|
2026-03-12 01:35:47 -07:00
|
|
|
"eri@plasticlabs.ai": "Erosika",
|
|
|
|
|
"hjcpuro@gmail.com": "hjc-puro",
|
|
|
|
|
"xaydinoktay@gmail.com": "aydnOktay",
|
|
|
|
|
"abdullahfarukozden@gmail.com": "Farukest",
|
|
|
|
|
"lovre.pesut@gmail.com": "rovle",
|
2026-04-21 05:23:36 -07:00
|
|
|
"xjtumj@gmail.com": "mengjian-github",
|
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:38:16 -07:00
|
|
|
"kevinskysunny@gmail.com": "kevinskysunny",
|
2026-04-17 04:20:25 -07:00
|
|
|
"xiewenxuan462@gmail.com": "yule975",
|
2026-04-17 05:04:01 -07:00
|
|
|
"yiweimeng.dlut@hotmail.com": "meng93",
|
2026-03-12 01:35:47 -07:00
|
|
|
"hakanerten02@hotmail.com": "teyrebaz33",
|
2026-04-20 02:15:25 -07:00
|
|
|
"linux2010@users.noreply.github.com": "Linux2010",
|
|
|
|
|
"elmatadorgh@users.noreply.github.com": "elmatadorgh",
|
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
|
|
|
"coktinbaran5@gmail.com": "elmatadorgh",
|
2026-04-20 03:06:14 -07:00
|
|
|
"alexazzjjtt@163.com": "alexzhu0",
|
2026-04-20 04:14:14 -07:00
|
|
|
"1180176+Swift42@users.noreply.github.com": "Swift42",
|
2026-04-15 02:56:31 +03:00
|
|
|
"ruzzgarcn@gmail.com": "Ruzzgar",
|
2026-04-20 20:53:07 -07:00
|
|
|
"yukipukikedy@gmail.com": "Yukipukii1",
|
2026-03-12 01:35:47 -07:00
|
|
|
"alireza78.crypto@gmail.com": "alireza78a",
|
chore: release v0.15.0 (2026.5.28) (#34008)
* chore: release v0.15.0 (2026.5.28)
The Velocity Release. Run_agent.py refactor (16k→3.8k LOC, -76%),
kanban grows into a multi-agent platform (104 PRs), cold-start perf wave
continues (-240ms / -47% per-turn function calls / -195ms per tool call),
session_search rebuilt (4500x faster, no LLM), promptware defense lands,
Bitwarden Secrets Manager integration, two new image_gen providers
(Krea 2, FAL plugin port), Nous-approved MCP catalog, OpenHands skill,
ntfy as 23rd messaging platform, deep xAI integration round.
15 P0 + 65 P1 closures. 747 PRs, 1,302 commits, 321 contributors.
* chore(release): bump acp_registry/agent.json to 0.15.0 (sync with pyproject)
2026-05-28 10:45:33 -07:00
|
|
|
"brooklyn.bb.nicholson@gmail.com": "OutThisLife",
|
2026-04-20 02:42:04 -07:00
|
|
|
"withapurpose37@gmail.com": "StefanIsMe",
|
2026-04-15 14:59:35 -07:00
|
|
|
"4317663+helix4u@users.noreply.github.com": "helix4u",
|
2026-04-21 14:27:07 -07:00
|
|
|
"ifkellx@users.noreply.github.com": "Ifkellx",
|
2026-04-15 15:05:11 -07:00
|
|
|
"331214+counterposition@users.noreply.github.com": "counterposition",
|
2026-04-15 16:12:31 -07:00
|
|
|
"blspear@gmail.com": "BrennerSpear",
|
2026-04-17 19:12:48 -07:00
|
|
|
"akhater@gmail.com": "akhater",
|
2026-04-22 18:12:49 -07:00
|
|
|
"Cos_Admin@PTG-COS.lodluvup4uaudnm3ycd14giyug.xx.internal.cloudapp.net": "akhater",
|
2026-04-15 17:10:02 -07:00
|
|
|
"239876380+handsdiff@users.noreply.github.com": "handsdiff",
|
2026-04-19 16:45:50 -07:00
|
|
|
"hesapacicam112@gmail.com": "etherman-os",
|
|
|
|
|
"mark.ramsell@rivermounts.com": "mark-ramsell",
|
2026-04-19 18:53:34 -07:00
|
|
|
"taeng02@icloud.com": "taeng0204",
|
2026-03-12 01:35:47 -07:00
|
|
|
"gpickett00@gmail.com": "gpickett00",
|
|
|
|
|
"mcosma@gmail.com": "wakamex",
|
|
|
|
|
"clawdia.nash@proton.me": "clawdia-nash",
|
|
|
|
|
"pickett.austin@gmail.com": "austinpickett",
|
2026-04-15 20:21:34 +07:00
|
|
|
"dangtc94@gmail.com": "dieutx",
|
2026-03-12 01:35:47 -07:00
|
|
|
"jaisehgal11299@gmail.com": "jaisup",
|
|
|
|
|
"percydikec@gmail.com": "PercyDikec",
|
2026-04-17 18:41:52 +01:00
|
|
|
"noonou7@gmail.com": "HenkDz",
|
docs(azure-foundry): add provider guide, env vars, release AUTHOR_MAP
- New website/docs/guides/azure-foundry.md covering both OpenAI-style
and Anthropic-style endpoints, auto-detection behaviour, gpt-5.x
routing, /v1 stripping, api-version query forwarding, and the
provider: anthropic + Azure URL alternative setup.
- environment-variables.md picks up AZURE_FOUNDRY_API_KEY,
AZURE_FOUNDRY_BASE_URL, AZURE_ANTHROPIC_KEY.
- cli-commands.md includes azure-foundry in the provider choices list.
- configuration.md lists azure-foundry among auxiliary-task providers.
- sidebars.ts wires the new guide into the Guides section.
- scripts/release.py AUTHOR_MAP entries for TechPrototyper,
HangGlidersRule (noreply), and pein892 so the contributor-attribution
CI check does not reject the salvage.
2026-04-25 18:41:28 -07:00
|
|
|
# Azure Foundry salvage (PRs #9029, #4599, #10086, #8766)
|
|
|
|
|
"tech@smartlogics.net": "TechPrototyper",
|
|
|
|
|
"637186+HangGlidersRule@users.noreply.github.com": "HangGlidersRule",
|
|
|
|
|
"pein892@gmail.com": "pein892",
|
2026-03-12 01:35:47 -07:00
|
|
|
"dean.kerr@gmail.com": "deankerr",
|
|
|
|
|
"socrates1024@gmail.com": "socrates1024",
|
2026-04-20 00:44:48 -07:00
|
|
|
"seanalt555@gmail.com": "Salt-555",
|
2026-03-12 01:35:47 -07:00
|
|
|
"satelerd@gmail.com": "satelerd",
|
2026-04-23 16:19:17 -07:00
|
|
|
"dan@danlynn.com": "danklynn",
|
2026-04-23 16:42:16 -07:00
|
|
|
"mattmaximo@hotmail.com": "MattMaximo",
|
2026-04-24 14:18:15 -04:00
|
|
|
"MatthewRHardwick@gmail.com": "mrhwick",
|
2026-04-24 04:52:51 -07:00
|
|
|
"149063006+j3ffffff@users.noreply.github.com": "j3ffffff",
|
|
|
|
|
"A-FdL-Prog@users.noreply.github.com": "A-FdL-Prog",
|
2026-04-24 05:08:19 -07:00
|
|
|
"l0hde@users.noreply.github.com": "l0hde",
|
|
|
|
|
"difujia@users.noreply.github.com": "difujia",
|
2026-04-24 05:19:06 -07:00
|
|
|
"vominh1919@gmail.com": "vominh1919",
|
|
|
|
|
"yue.gu2023@gmail.com": "YueLich",
|
|
|
|
|
"51783311+andyylin@users.noreply.github.com": "andyylin",
|
|
|
|
|
"me@jakubkrcmar.cz": "jakubkrcmar",
|
|
|
|
|
"prasadus92@gmail.com": "prasadus92",
|
|
|
|
|
"michael@make.software": "mssteuer",
|
|
|
|
|
"der@konsi.org": "konsisumer",
|
2026-04-24 05:28:03 -07:00
|
|
|
"abogale2@gmail.com": "amanuel2",
|
|
|
|
|
"alexazzjjtt@163.com": "alexzhu0",
|
|
|
|
|
"pub_forgreatagent@antgroup.com": "AntAISecurityLab",
|
|
|
|
|
"252620095+briandevans@users.noreply.github.com": "briandevans",
|
2026-04-24 05:35:01 -07:00
|
|
|
"danielrpike9@gmail.com": "Bartok9",
|
|
|
|
|
"skozyuk@cruxexperts.com": "CruxExperts",
|
|
|
|
|
"154585401+LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
2026-04-29 05:08:26 -07:00
|
|
|
"12250313+Kailigithub@users.noreply.github.com": "Kailigithub",
|
2026-04-24 05:35:01 -07:00
|
|
|
"mgparkprint@gmail.com": "vlwkaos",
|
2026-04-30 20:38:27 -07:00
|
|
|
"1317078257maroon@gmail.com": "Oxidane-bot",
|
2026-04-24 05:35:01 -07:00
|
|
|
"tranquil_flow@protonmail.com": "Tranquil-Flow",
|
fix(codex): surface actionable hint when stale-call detector fires on known silent-reject pattern
The ChatGPT Codex backend (chatgpt.com/backend-api/codex) has historically
silently dropped certain model requests: the connection is accepted but no
stream events are emitted and no error is raised. PR #31967 lowered the
implicit stale-call default from 300s to 90s so fallbacks kick in faster,
but users still see an opaque "No response from provider for 90s
(non-streaming, ...)" message that gives no path forward.
This patch adds a narrow heuristic — gpt-5.5 family on the Codex backend
via codex_responses api_mode — that substitutes the generic timeout
message with actionable text naming the gpt-5.4-codex workaround and
pointing at #21444 for symptom history.
Changes:
- run_agent.py — new ``AIAgent._codex_silent_hang_hint(model=...)`` method.
Returns ``None`` for any request that does not match all three guards
(codex_responses api_mode, openai-codex provider or chatgpt.com Codex
base URL, gpt-5.5-family model name with word-boundary regex anchoring
to avoid false-positives on e.g. ``gpt-5.50``).
- agent/chat_completion_helpers.py — the non-stream stale-call site
consults the hint via ``getattr(...)`` so the call site stays robust
if the helper is ever removed or stubbed in tests. Hint is appended to
both the ``_emit_status`` warning and the ``TimeoutError`` message so
the user sees it in their terminal AND it lands in any retry-loop
diagnostics.
- tests/run_agent/test_codex_silent_hang_hint.py — 10 regression tests
covering positive cases (bare gpt-5.5, vendor-prefixed openai/gpt-5.5,
gpt-5.5-codex SKU, model=None fallback to self.model) and negative
cases (gpt-5.4-codex workaround, gpt-5.50 false-positive guard,
non-codex api_mode, non-codex provider, empty/None model, unrelated
models on Codex).
Does NOT fix the backend-side issue (that's an upstream OpenAI/ChatGPT
problem we cannot patch from here). Only converts an opaque timeout into
text that names the workaround so users do not have to dig through logs
or wait for a forum post to learn what to do.
Closes #22046
2026-05-25 03:54:07 -07:00
|
|
|
"66773372+Tranquil-Flow@users.noreply.github.com": "Tranquil-Flow",
|
2026-04-28 22:16:52 -07:00
|
|
|
"LyleLengyel@gmail.com": "mcndjxlefnd",
|
2026-04-24 05:47:31 -07:00
|
|
|
"wangshengyang2004@163.com": "Wangshengyang2004",
|
|
|
|
|
"hasan.ali13381@gmail.com": "H-Ali13381",
|
|
|
|
|
"xienb@proton.me": "XieNBi",
|
2026-04-24 07:12:34 -07:00
|
|
|
"139681654+maymuneth@users.noreply.github.com": "maymuneth",
|
|
|
|
|
"zengwei@nightq.cn": "nightq",
|
|
|
|
|
"1434494126@qq.com": "5park1e",
|
|
|
|
|
"158153005+5park1e@users.noreply.github.com": "5park1e",
|
|
|
|
|
"innocarpe@gmail.com": "innocarpe",
|
2026-04-24 07:24:59 -07:00
|
|
|
"noreply@ked.com": "qike-ms",
|
|
|
|
|
"andrekurait@gmail.com": "AndreKurait",
|
|
|
|
|
"bsgdigital@users.noreply.github.com": "bsgdigital",
|
2026-03-12 01:35:47 -07:00
|
|
|
"numman.ali@gmail.com": "nummanali",
|
2026-04-23 15:11:52 -07:00
|
|
|
"rohithsaimidigudla@gmail.com": "whitehatjr1001",
|
2026-03-12 01:35:47 -07:00
|
|
|
"0xNyk@users.noreply.github.com": "0xNyk",
|
|
|
|
|
"0xnykcd@googlemail.com": "0xNyk",
|
|
|
|
|
"buraysandro9@gmail.com": "buray",
|
|
|
|
|
"contact@jomar.fr": "joshmartinelle",
|
|
|
|
|
"camilo@tekelala.com": "tekelala",
|
|
|
|
|
"vincentcharlebois@gmail.com": "vincentcharlebois",
|
|
|
|
|
"aryan@synvoid.com": "aryansingh",
|
2026-05-07 11:20:15 -07:00
|
|
|
"johnsonblake1@gmail.com": "voteblake",
|
2026-04-17 19:17:34 -07:00
|
|
|
"hcn518@gmail.com": "pedh",
|
2026-04-20 02:08:03 -07:00
|
|
|
"haileymarshall005@gmail.com": "haileymarshall",
|
2026-05-07 17:35:17 -07:00
|
|
|
"bennet.yr.wang@gmail.com": "BennetYrWang",
|
2026-04-14 15:45:09 -05:00
|
|
|
"greer.guthrie@gmail.com": "g-guthrie",
|
2026-04-13 16:31:27 -07:00
|
|
|
"kennyx102@gmail.com": "bobashopcashier",
|
2026-05-04 18:51:05 +05:30
|
|
|
"77253505+bobashopcashier@users.noreply.github.com": "bobashopcashier",
|
2026-05-04 19:19:50 +05:30
|
|
|
"25355950+megastary@users.noreply.github.com": "megastary", # PR #18325
|
2026-04-14 16:55:25 -07:00
|
|
|
"shokatalishaikh95@gmail.com": "areu01or00",
|
2026-03-12 01:35:47 -07:00
|
|
|
"bryan@intertwinesys.com": "bryanyoung",
|
|
|
|
|
"christo.mitov@gmail.com": "christomitov",
|
|
|
|
|
"hermes@nousresearch.com": "NousResearch",
|
2026-04-24 03:00:43 -07:00
|
|
|
"reginaldasr@gmail.com": "ReginaldasR",
|
2026-04-24 03:15:15 -07:00
|
|
|
"ntconguit@gmail.com": "0xharryriddle",
|
2026-04-24 03:19:56 -07:00
|
|
|
"agent@wildcat.local": "ericnicolaides",
|
2026-04-24 04:52:36 -07:00
|
|
|
"georgex8001@gmail.com": "georgex8001",
|
2026-04-24 05:33:03 -07:00
|
|
|
"stefan@dimagents.ai": "dimitrovi",
|
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
|
|
|
"hermes@noushq.ai": "benbarclay",
|
2026-04-14 10:17:33 -07:00
|
|
|
"chinmingcock@gmail.com": "ChimingLiu",
|
2026-04-30 20:18:24 -07:00
|
|
|
"allard.quek@singtel.com": "AllardQuek",
|
2026-03-12 01:35:47 -07:00
|
|
|
"openclaw@sparklab.ai": "openclaw",
|
|
|
|
|
"semihcvlk53@gmail.com": "Himess",
|
|
|
|
|
"erenkar950@gmail.com": "erenkarakus",
|
|
|
|
|
"adavyasharma@gmail.com": "adavyas",
|
|
|
|
|
"acaayush1111@gmail.com": "aayushchaudhary",
|
|
|
|
|
"jason@outland.art": "jasonoutland",
|
2026-04-22 15:01:50 -07:00
|
|
|
"73175452+Magaav@users.noreply.github.com": "Magaav",
|
2026-03-12 01:35:47 -07:00
|
|
|
"mrflu1918@proton.me": "SPANISHFLU",
|
|
|
|
|
"morganemoss@gmai.com": "mormio",
|
|
|
|
|
"kopjop926@gmail.com": "cesareth",
|
|
|
|
|
"fuleinist@gmail.com": "fuleinist",
|
|
|
|
|
"jack.47@gmail.com": "JackTheGit",
|
2026-05-18 19:30:38 -07:00
|
|
|
"jack@jackyang.com": "0xjackyang",
|
2026-03-12 01:35:47 -07:00
|
|
|
"dalvidjr2022@gmail.com": "Jr-kenny",
|
|
|
|
|
"m@statecraft.systems": "mbierling",
|
2026-04-19 20:32:30 -07:00
|
|
|
"balyan.sid@gmail.com": "alt-glitch",
|
feat(comfyui): add hardware check + auto-gate local install on verdict
Layers a programmatic hardware-feasibility check on top of the v4 skill
so the agent doesn't silently push users toward a local install they
can't actually run. The official comfy-cli supports --nvidia / --amd /
--m-series / --cpu, but has no guard against "4 GB laptop GPU on SDXL"
or "Intel Mac falling back to CPU" — both route to comfy-cli paths in
the original table and then fail on first workflow.
- scripts/hardware_check.py: detect OS/arch/GPU (NVIDIA nvidia-smi,
AMD rocm-smi, Apple M1+ via arm64+sysctl, Intel Arc via clinfo),
VRAM, system/unified RAM. Emits JSON
{verdict: ok|marginal|cloud, recommended_install_path, comfy_cli_flag}
with practical thresholds: discrete GPU >=6 GB VRAM minimum,
Apple Silicon >=16 GB unified memory minimum, Intel Mac -> cloud,
no accelerator -> cloud. comfy_cli_flag maps directly to
`comfy install` so the agent can stitch the whole flow together.
- scripts/comfyui_setup.sh: runs hardware_check.py first when no
explicit flag is passed. If verdict=cloud, refuses to install
locally, prints Comfy Cloud URL + an override command, exits 2.
Otherwise auto-selects the right --nvidia/--amd/--m-series flag
for `comfy install`. Surfaces marginal-verdict notes to the user.
- SKILL.md Setup & Onboarding: adds mandatory Step 0 "Check If This
Machine Can Run ComfyUI Locally" ahead of the Path A-E selection.
Documents the verdict thresholds inline, ties verdict + comfy_cli_flag
to the install paths, and updates the path-choice table so
"verdict: cloud" is the first row. Quick-Start "Detect Environment"
block extended to include the hardware check. Verification
checklist gains a hardware-check gate.
- Frontmatter setup.help rewritten to point at hardware_check.py
first. Version bumped 4.0.0 -> 4.1.0.
2026-04-29 12:38:09 -07:00
|
|
|
"52913345+alt-glitch@users.noreply.github.com": "alt-glitch",
|
2026-05-07 06:35:43 -07:00
|
|
|
"oluwadareab12@gmail.com": "oluwadareab12",
|
2026-04-14 20:47:57 -07:00
|
|
|
"simon@simonmarcus.org": "simon-marcus",
|
2026-04-15 22:27:36 +03:00
|
|
|
"xowiekk@gmail.com": "Xowiek",
|
2026-04-14 20:55:34 -07:00
|
|
|
"1243352777@qq.com": "zons-zhaozhy",
|
2026-04-20 20:53:10 -07:00
|
|
|
"e.silacandmr@gmail.com": "Es1la",
|
2026-05-07 04:51:48 -07:00
|
|
|
"51599529+stephen0110@users.noreply.github.com": "stephen0110",
|
2026-05-07 04:54:38 -07:00
|
|
|
"265632032+sonic-netizen@users.noreply.github.com": "sonic-netizen",
|
2026-05-07 04:59:45 -07:00
|
|
|
"82531659+mwnickerson@users.noreply.github.com": "mwnickerson",
|
2026-05-07 05:26:11 -07:00
|
|
|
"sandrohub013@gmail.com": "SandroHub013",
|
2026-05-07 07:35:03 -07:00
|
|
|
"maciekczech@users.noreply.github.com": "maciekczech",
|
2026-05-02 01:39:51 -07:00
|
|
|
"h3057183414@gmail.com": "CoreyNoDream",
|
2026-05-02 01:58:06 -07:00
|
|
|
"franksong2702@gmail.com": "franksong2702",
|
2026-05-02 02:06:00 -07:00
|
|
|
"673088860@qq.com": "ambition0802",
|
2026-05-02 02:23:05 -07:00
|
|
|
"beibei1988@proton.me": "beibi9966",
|
2026-04-13 21:10:39 -07:00
|
|
|
# ── bulk addition: 75 emails resolved via API, PR salvage bodies, noreply
|
|
|
|
|
# crossref, and GH contributor list matching (April 2026 audit) ──
|
2026-05-22 19:55:58 -07:00
|
|
|
"1115117931@qq.com": "aaronlab",
|
2026-04-13 21:10:39 -07:00
|
|
|
"1506751656@qq.com": "hqhq1025",
|
|
|
|
|
"364939526@qq.com": "luyao618",
|
2026-04-20 04:55:21 -07:00
|
|
|
"hgk324@gmail.com": "houziershi",
|
2026-04-20 04:58:59 -07:00
|
|
|
"176644217+PStarH@users.noreply.github.com": "PStarH",
|
2026-04-20 05:06:04 -07:00
|
|
|
"51058514+Sanjays2402@users.noreply.github.com": "Sanjays2402",
|
2026-04-30 03:09:30 -07:00
|
|
|
"16577466+andy825@user.noreply.gitee.com": "Andy283",
|
2026-04-19 11:23:04 -07:00
|
|
|
"906014227@qq.com": "bingo906",
|
2026-04-13 21:10:39 -07:00
|
|
|
"aaronwong1999@icloud.com": "AaronWong1999",
|
|
|
|
|
"agents@kylefrench.dev": "DeployFaith",
|
|
|
|
|
"angelos@oikos.lan.home.malaiwah.com": "angelos",
|
|
|
|
|
"aptx4561@gmail.com": "cokemine",
|
|
|
|
|
"arilotter@gmail.com": "ethernet8023",
|
|
|
|
|
"ben@nousresearch.com": "benbarclay",
|
|
|
|
|
"birdiegyal@gmail.com": "yyovil",
|
|
|
|
|
"boschi1997@gmail.com": "nicoloboschi",
|
|
|
|
|
"chef.ya@gmail.com": "cherifya",
|
|
|
|
|
"chlqhdtn98@gmail.com": "BongSuCHOI",
|
|
|
|
|
"coffeemjj@gmail.com": "Cafexss",
|
|
|
|
|
"dalianmao0107@gmail.com": "dalianmao000",
|
|
|
|
|
"der@konsi.org": "konsisumer",
|
|
|
|
|
"dgrieco@redhat.com": "DomGrieco",
|
|
|
|
|
"dhicham.pro@gmail.com": "spideystreet",
|
|
|
|
|
"dipp.who@gmail.com": "dippwho",
|
|
|
|
|
"don.rhm@gmail.com": "donrhmexe",
|
|
|
|
|
"dorukardahan@hotmail.com": "dorukardahan",
|
|
|
|
|
"dsocolobsky@gmail.com": "dsocolobsky",
|
2026-04-20 14:05:15 -07:00
|
|
|
"dylan.socolobsky@lambdaclass.com": "dsocolobsky",
|
|
|
|
|
"ignacio.avecilla@lambdaclass.com": "IAvecilla",
|
2026-04-13 21:10:39 -07:00
|
|
|
"duerzy@gmail.com": "duerzy",
|
|
|
|
|
"emozilla@nousresearch.com": "emozilla",
|
|
|
|
|
"fancydirty@gmail.com": "fancydirty",
|
2026-04-19 05:44:44 -07:00
|
|
|
"farion1231@gmail.com": "farion1231",
|
2026-04-13 21:10:39 -07:00
|
|
|
"floptopbot33@gmail.com": "flobo3",
|
|
|
|
|
"fontana.pedro93@gmail.com": "pefontana",
|
|
|
|
|
"francis.x.fitzpatrick@gmail.com": "fxfitz",
|
|
|
|
|
"frank@helmschrott.de": "Helmi",
|
|
|
|
|
"gaixg94@gmail.com": "gaixianggeng",
|
|
|
|
|
"geoff.wellman@gmail.com": "geoffwellman",
|
|
|
|
|
"han.shan@live.cn": "jamesarch",
|
|
|
|
|
"haolong@microsoft.com": "LongOddCode",
|
2026-05-18 09:42:57 -07:00
|
|
|
"glennc@microsoft.com": "glennc",
|
2026-04-13 21:10:39 -07:00
|
|
|
"hata1234@gmail.com": "hata1234",
|
|
|
|
|
"hmbown@gmail.com": "Hmbown",
|
|
|
|
|
"iacobs@m0n5t3r.info": "m0n5t3r",
|
|
|
|
|
"jiayuw794@gmail.com": "JiayuuWang",
|
2026-05-20 03:25:45 -07:00
|
|
|
"jonny@nousresearch.com": "yoniebans",
|
2026-05-13 22:19:44 -07:00
|
|
|
"jake@nousresearch.com": "simpolism",
|
2026-04-13 21:10:39 -07:00
|
|
|
"juan.ovalle@mistral.ai": "jjovalle99",
|
|
|
|
|
"julien.talbot@ergonomia.re": "Julientalbot",
|
|
|
|
|
"kagura.chen28@gmail.com": "kagura-agent",
|
2026-04-17 05:40:44 -07:00
|
|
|
"1342088860@qq.com": "youngDoo",
|
2026-04-13 21:10:39 -07:00
|
|
|
"kamil@gwozdz.me": "kamil-gwozdz",
|
2026-04-20 12:02:40 +05:30
|
|
|
"skmishra1991@gmail.com": "bugkill3r",
|
2026-04-13 21:10:39 -07:00
|
|
|
"karamusti912@gmail.com": "MustafaKara7",
|
|
|
|
|
"kira@ariaki.me": "kira-ariaki",
|
2026-05-15 01:24:44 -07:00
|
|
|
"kira.ops@proton.me": "KiraKatana",
|
2026-04-13 21:10:39 -07:00
|
|
|
"knopki@duck.com": "knopki",
|
|
|
|
|
"limars874@gmail.com": "limars874",
|
|
|
|
|
"lisicheng168@gmail.com": "lesterli",
|
|
|
|
|
"mingjwan@microsoft.com": "MagicRay1217",
|
2026-04-16 05:58:52 -07:00
|
|
|
"orangeko@gmail.com": "GenKoKo",
|
2026-04-16 06:47:42 -07:00
|
|
|
"82095453+iacker@users.noreply.github.com": "iacker",
|
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
|
|
|
"sontianye@users.noreply.github.com": "sontianye",
|
|
|
|
|
"jackjin1997@users.noreply.github.com": "jackjin1997",
|
2026-04-19 23:59:16 +08:00
|
|
|
"1037461232@qq.com": "jackjin1997",
|
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
|
|
|
"danieldoderlein@users.noreply.github.com": "danieldoderlein",
|
|
|
|
|
"lrawnsley@users.noreply.github.com": "lrawnsley",
|
|
|
|
|
"taeuk178@users.noreply.github.com": "taeuk178",
|
|
|
|
|
"ogzerber@users.noreply.github.com": "ogzerber",
|
|
|
|
|
"cola-runner@users.noreply.github.com": "cola-runner",
|
|
|
|
|
"ygd58@users.noreply.github.com": "ygd58",
|
2026-04-30 20:26:27 -07:00
|
|
|
"45554392+warabe1122@users.noreply.github.com": "warabe1122",
|
|
|
|
|
"187001140+willy-scr@users.noreply.github.com": "willy-scr",
|
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
|
|
|
"vominh1919@users.noreply.github.com": "vominh1919",
|
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:56:22 -07:00
|
|
|
"iamagenius00@users.noreply.github.com": "iamagenius00",
|
2026-04-20 00:36:18 -07:00
|
|
|
"9219265+cresslank@users.noreply.github.com": "cresslank",
|
2026-04-16 23:17:20 +05:30
|
|
|
"trevmanthony@gmail.com": "trevthefoolish",
|
|
|
|
|
"ziliangpeng@users.noreply.github.com": "ziliangpeng",
|
2026-05-21 07:17:06 +00:00
|
|
|
"ziliangdotme@gmail.com": "ziliangpeng",
|
2026-04-16 23:17:20 +05:30
|
|
|
"centripetal-star@users.noreply.github.com": "centripetal-star",
|
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
|
|
|
"LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
2026-04-19 11:01:26 +05:30
|
|
|
"154585401+LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
2026-05-04 02:18:25 -07:00
|
|
|
"cine.dreamer.one@gmail.com": "LeonSGP43",
|
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
|
|
|
"Lubrsy706@users.noreply.github.com": "Lubrsy706",
|
2026-04-13 21:10:39 -07:00
|
|
|
"niyant@spicefi.xyz": "spniyant",
|
|
|
|
|
"olafthiele@gmail.com": "olafthiele",
|
|
|
|
|
"oncuevtv@gmail.com": "sprmn24",
|
|
|
|
|
"programming@olafthiele.com": "olafthiele",
|
|
|
|
|
"r2668940489@gmail.com": "r266-tech",
|
|
|
|
|
"s5460703@gmail.com": "BlackishGreen33",
|
|
|
|
|
"saul.jj.wu@gmail.com": "SaulJWu",
|
|
|
|
|
"shenhaocheng19990111@gmail.com": "hcshen0111",
|
|
|
|
|
"sjtuwbh@gmail.com": "Cygra",
|
|
|
|
|
"srhtsrht17@gmail.com": "Sertug17",
|
|
|
|
|
"stephenschoettler@gmail.com": "stephenschoettler",
|
|
|
|
|
"tanishq231003@gmail.com": "yyovil",
|
2026-04-23 00:12:25 +05:30
|
|
|
"taosiyuan163@153.com": "taosiyuan163",
|
2026-04-13 21:10:39 -07:00
|
|
|
"tesseracttars@gmail.com": "tesseracttars-creator",
|
|
|
|
|
"tianliangjay@gmail.com": "xingkongliang",
|
2026-04-30 20:38:27 -07:00
|
|
|
"1317078257maroon@gmail.com": "Oxidane-bot",
|
2026-04-13 21:10:39 -07:00
|
|
|
"tranquil_flow@protonmail.com": "Tranquil-Flow",
|
2026-04-28 22:16:52 -07:00
|
|
|
"LyleLengyel@gmail.com": "mcndjxlefnd",
|
2026-04-13 21:10:39 -07:00
|
|
|
"unayung@gmail.com": "Unayung",
|
|
|
|
|
"vorvul.danylo@gmail.com": "WorldInnovationsDepartment",
|
|
|
|
|
"win4r@outlook.com": "win4r",
|
|
|
|
|
"xush@xush.org": "KUSH42",
|
|
|
|
|
"yangzhi.see@gmail.com": "SeeYangZhi",
|
|
|
|
|
"yongtenglei@gmail.com": "yongtenglei",
|
|
|
|
|
"young@YoungdeMacBook-Pro.local": "YoungYang963",
|
2026-04-15 04:09:14 +03:00
|
|
|
"ysfalweshcan@gmail.com": "Junass1",
|
2026-04-13 21:10:39 -07:00
|
|
|
"ysfwaxlycan@gmail.com": "WAXLYY",
|
|
|
|
|
"yusufalweshdemir@gmail.com": "Dusk1e",
|
|
|
|
|
"zhouboli@gmail.com": "zhouboli",
|
|
|
|
|
"zqiao@microsoft.com": "tomqiaozc",
|
|
|
|
|
"zzn+pa@zzn.im": "xinbenlv",
|
2026-04-15 02:33:56 +08:00
|
|
|
"zaynjarvis@gmail.com": "ZaynJarvis",
|
2026-04-15 11:08:14 -07:00
|
|
|
"zhiheng.liu@bytedance.com": "ZaynJarvis",
|
2026-04-26 18:50:49 -07:00
|
|
|
"izhaolongfei@gmail.com": "loongfay",
|
|
|
|
|
"296659110@qq.com": "lrt4836",
|
|
|
|
|
"fe.daniel91@gmail.com": "beforeload",
|
|
|
|
|
"libo1106@foxmail.com": "libo1106",
|
|
|
|
|
"295367131@qq.com": "295367131",
|
|
|
|
|
"295367132@qq.com": "IxAres",
|
|
|
|
|
"danieldliu@tencent.com": "danieldliu",
|
|
|
|
|
"loongzhao@tencent.com": "loongzhao",
|
|
|
|
|
"Bartok9@users.noreply.github.com": "Bartok9",
|
|
|
|
|
"LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
|
|
|
|
"kshitijk4poor@users.noreply.github.com": "kshitijk4poor",
|
2026-04-16 16:49:42 -07:00
|
|
|
"mbelleau@Michels-MacBook-Pro.local": "malaiwah",
|
2026-04-17 00:52:43 -07:00
|
|
|
"michel.belleau@malaiwah.com": "malaiwah",
|
2026-04-17 05:41:31 -07:00
|
|
|
"gnanasekaran.sekareee@gmail.com": "gnanam1990",
|
2026-04-17 05:47:53 -07:00
|
|
|
"jz.pentest@gmail.com": "0xyg3n",
|
2026-05-03 16:13:58 +05:30
|
|
|
"7093928+0xyg3n@users.noreply.github.com": "0xyg3n",
|
2026-05-03 16:17:09 +05:30
|
|
|
"nftpoetrist@gmail.com": "nftpoetrist", # PR #18982
|
2026-05-03 16:18:47 +05:30
|
|
|
"millerc79@users.noreply.github.com": "millerc79", # PR #19033
|
2026-05-03 16:19:37 +05:30
|
|
|
"hermes@example.com": "shellybotmoyer", # PR #18915 (bot-committed)
|
2026-05-04 02:38:24 -07:00
|
|
|
"exx@example.com": "exxmen", # PR #19555
|
2026-04-17 06:38:28 -07:00
|
|
|
"hypnosis.mda@gmail.com": "Hypn0sis",
|
|
|
|
|
"ywt000818@gmail.com": "OwenYWT",
|
2026-04-16 20:22:52 -07:00
|
|
|
"dhandhalyabhavik@gmail.com": "v1k22",
|
2026-04-17 00:55:07 -07:00
|
|
|
"rucchizhao@zhaochenfeideMacBook-Pro.local": "RucchiZ",
|
2026-04-20 20:49:49 -07:00
|
|
|
"tannerfokkens@Mac.attlocal.net": "tannerfokkens-maker",
|
2026-04-17 04:20:14 -07:00
|
|
|
"lehaolin98@outlook.com": "LehaoLin",
|
2026-04-17 04:31:17 -07:00
|
|
|
"yuewang1@microsoft.com": "imink",
|
|
|
|
|
"1736355688@qq.com": "hedgeho9X",
|
|
|
|
|
"bernylinville@devopsthink.org": "bernylinville",
|
2026-04-17 05:40:56 -07:00
|
|
|
"brian@bde.io": "briandevans",
|
|
|
|
|
"hubin_ll@qq.com": "LLQWQ",
|
2026-04-17 06:42:20 -07:00
|
|
|
"memosr_email@gmail.com": "memosr",
|
2026-04-24 03:29:46 -07:00
|
|
|
"jperlow@gmail.com": "perlowja",
|
2026-04-30 23:17:56 -07:00
|
|
|
"jasonpette1783@gmail.com": "web-dev0521",
|
2026-05-05 03:57:16 -07:00
|
|
|
"bjianhang@gmail.com": "bjianhang",
|
2026-04-24 03:29:46 -07:00
|
|
|
"tangyuanjc@JCdeAIfenshendeMac-mini.local": "tangyuanjc",
|
|
|
|
|
"harryplusplus@gmail.com": "harryplusplus",
|
2026-04-17 06:42:20 -07:00
|
|
|
"anthhub@163.com": "anthhub",
|
2026-05-14 07:42:24 -07:00
|
|
|
"vmphuongit@gmail.com": "phuongvm",
|
2026-04-30 20:23:31 -07:00
|
|
|
"allard.quek@singtel.com": "AllardQuek",
|
2026-04-17 06:42:20 -07:00
|
|
|
"shenuu@gmail.com": "shenuu",
|
|
|
|
|
"xiayh17@gmail.com": "xiayh0107",
|
2026-04-18 02:24:35 +08:00
|
|
|
"zhujianxyz@gmail.com": "opriz",
|
2026-05-07 07:04:11 -07:00
|
|
|
"tuancanhnguyen706@gmail.com": "xxxigm",
|
2026-05-23 02:34:23 -07:00
|
|
|
"larcombe.n@gmail.com": "NickLarcombe",
|
2026-05-19 00:13:45 -07:00
|
|
|
"54813621+xxxigm@users.noreply.github.com": "xxxigm",
|
2026-04-17 13:09:14 -07:00
|
|
|
"asurla@nvidia.com": "anniesurla",
|
2026-05-15 14:00:13 -07:00
|
|
|
"kchantharuan@nvidia.com": "nv-kasikritc",
|
2026-04-17 20:31:47 +08:00
|
|
|
"limkuan24@gmail.com": "WideLee",
|
2026-04-17 21:27:43 -07:00
|
|
|
"aviralarora002@gmail.com": "AviArora02-commits",
|
2026-04-19 22:04:09 -07:00
|
|
|
"draixagent@gmail.com": "draix",
|
2026-04-18 12:27:22 -07:00
|
|
|
"junminliu@gmail.com": "JimLiu",
|
2026-04-18 22:46:36 +05:30
|
|
|
"jarvischer@gmail.com": "maxchernin",
|
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 22:49:30 +05:30
|
|
|
"levantam.98.2324@gmail.com": "LVT382009",
|
2026-04-19 11:38:42 -07:00
|
|
|
"zhurongcheng@rcrai.com": "heykb",
|
2026-04-20 02:33:28 -07:00
|
|
|
"withapurpose37@gmail.com": "StefanIsMe",
|
2026-04-20 01:55:11 -07:00
|
|
|
"261797239+lumenradley@users.noreply.github.com": "lumenradley",
|
2026-04-20 02:42:28 -07:00
|
|
|
"166376523+sjz-ks@users.noreply.github.com": "sjz-ks",
|
2026-04-20 02:46:12 -07:00
|
|
|
"haileymarshall005@gmail.com": "haileymarshall",
|
2026-04-20 12:24:15 -07:00
|
|
|
"aniruddhaadak80@users.noreply.github.com": "aniruddhaadak80",
|
2026-04-20 11:02:24 -07:00
|
|
|
"zheng.jerilyn@gmail.com": "jerilynzheng",
|
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 20:58:01 -07:00
|
|
|
"asslaenn5@gmail.com": "Aslaaen",
|
2026-04-21 02:06:45 -07:00
|
|
|
"shalompmc0505@naver.com": "pinion05",
|
2026-04-20 12:54:48 +09:00
|
|
|
"105142614+VTRiot@users.noreply.github.com": "VTRiot",
|
2026-04-22 11:20:16 +08:00
|
|
|
"vivien000812@gmail.com": "iamagenius00",
|
2026-04-22 16:32:53 -07:00
|
|
|
"89228157+Feranmi10@users.noreply.github.com": "Feranmi10",
|
2026-04-25 18:37:59 -07:00
|
|
|
"oluwadareferanmi11@gmail.com": "Feranmi10",
|
2026-04-22 17:23:29 -07:00
|
|
|
"simon@gtcl.us": "simon-gtcl",
|
2026-04-22 17:24:02 -07:00
|
|
|
"suzukaze.haduki@gmail.com": "houko",
|
2026-04-22 17:24:55 -07:00
|
|
|
"cliff@cigii.com": "cgarwood82",
|
2026-04-22 17:25:22 -07:00
|
|
|
"anna@oa.ke": "anna-oake",
|
2026-04-22 17:27:09 -07:00
|
|
|
"jaffarkeikei@gmail.com": "jaffarkeikei",
|
2026-04-22 17:33:56 -07:00
|
|
|
"hxp@hxp.plus": "hxp-plus",
|
2026-04-22 17:34:21 -07:00
|
|
|
"3580442280@qq.com": "Tianworld",
|
2026-04-22 17:35:45 -07:00
|
|
|
"wujianxu91@gmail.com": "wujhsu",
|
2026-04-22 17:36:25 -07:00
|
|
|
"zhrh120@gmail.com": "niyoh120",
|
2026-04-22 17:37:04 -07:00
|
|
|
"vrinek@hey.com": "vrinek",
|
2026-04-22 17:43:21 -07:00
|
|
|
"268198004+xandersbell@users.noreply.github.com": "xandersbell",
|
2026-04-22 17:43:50 -07:00
|
|
|
"somme4096@gmail.com": "Somme4096",
|
2026-04-22 17:44:32 -07:00
|
|
|
"brian@tiuxo.com": "brianclemens",
|
2026-04-22 17:45:08 -07:00
|
|
|
"25944632+yudaiyan@users.noreply.github.com": "yudaiyan",
|
2026-04-22 17:45:46 -07:00
|
|
|
"chayton@sina.com": "ycbai",
|
2026-04-22 17:53:36 -07:00
|
|
|
"longsizhuo@gmail.com": "longsizhuo",
|
2026-04-22 17:54:15 -07:00
|
|
|
"chenb19870707@gmail.com": "ms-alan",
|
2026-05-14 15:48:18 -07:00
|
|
|
"agorgianitisj@hotmail.com": "johnisag",
|
2026-05-14 15:59:00 -07:00
|
|
|
"phil.thomas@gametime.co": "explainanalyze",
|
2026-04-22 17:55:14 -07:00
|
|
|
"276886827+WuTianyi123@users.noreply.github.com": "WuTianyi123",
|
2026-04-22 17:56:03 -07:00
|
|
|
"22549957+li0near@users.noreply.github.com": "li0near",
|
2026-05-09 22:36:49 -07:00
|
|
|
"guoyu801@gmail.com": "li0near",
|
2026-05-09 22:48:56 -07:00
|
|
|
"ty@tmrtn.com": "tymrtn",
|
2026-05-09 23:05:18 -07:00
|
|
|
"elitovsky@zenproject.net": "kallidean",
|
2026-05-10 07:14:20 -07:00
|
|
|
"5463986+baocin@users.noreply.github.com": "baocin",
|
2026-05-10 07:34:26 -07:00
|
|
|
"107296821+princepal9120@users.noreply.github.com": "princepal9120",
|
2026-05-10 09:12:30 -07:00
|
|
|
"gufo0125@gmail.com": "guglielmofonda",
|
refactor(kanban-orchestrator): drop hardcoded specialist roster, add Step-0 profile discovery
The skill enumerated 8 specialist profile names (researcher, analyst,
writer, reviewer, backend-eng, frontend-eng, ops, pm) as "the standard
roster" and told orchestrators to "assume these exist." Almost no real
Hermes setup matches that fleet — single-profile setups, Docker-worker
setups, and curated-team setups all violate it — so following the skill
literally produced cards assigned to non-existent profiles, which the
dispatcher silently failed to spawn (no autocorrect, no fallback, just
sits in `ready` forever).
Changes:
- Drop the standard-specialist-roster table.
- Add a "Profiles are user-configured — not a fixed roster" section at
the top with a Step 0 that prescribes `hermes profile list` (or asking
the user) before fanning out. Cache the result in working memory.
- Rewrite the worked task-graph example with placeholder names
(<profile-A>, <profile-B>, <profile-C>) so the structure is still
teachable but doesn't invite copy-paste of role names that may not
exist.
- Reframe the "If no specialist fits" anti-temptation rule: don't
invent profile names; ask the user.
- Add a "Inventing profile names that doesn't exist" entry to Pitfalls.
- Bump skill version 2.0.0 → 3.0.0 (semantic break: previous behavior
promised a roster the skill no longer enumerates).
- Update website/docs/user-guide/features/kanban.md to drop the
matching "(researcher, writer, analyst, backend-eng, reviewer, ops)"
line and explain the discovery prompt instead.
- Re-run website/scripts/generate-skill-docs.py to refresh the
auto-generated skill page + catalog.
Closes #21131 in spirit — addresses the same hardcoded-names footgun
@yehuosi flagged, with a different shape than their PR (delete the
roster rather than replace each name with placeholder, since the
roster table was the load-bearing footgun and the worked example is
salvageable with placeholder profile names).
Co-authored-by: yehuosi <yehuosi@users.noreply.github.com>
2026-05-10 12:58:33 -07:00
|
|
|
"102474490+yehuosi@users.noreply.github.com": "yehuosi",
|
|
|
|
|
"yehuosi@users.noreply.github.com": "yehuosi",
|
2026-05-10 14:27:13 -07:00
|
|
|
"31932854+jelrod27@users.noreply.github.com": "jelrod27",
|
2026-05-10 15:22:27 -07:00
|
|
|
"11262660+konsisumer@users.noreply.github.com": "konsisumer",
|
2026-04-22 17:57:03 -07:00
|
|
|
"23434080+sicnuyudidi@users.noreply.github.com": "sicnuyudidi",
|
2026-04-22 18:14:41 -07:00
|
|
|
"haimu0x0@proton.me": "haimu0x",
|
2026-04-22 18:15:18 -07:00
|
|
|
"abdelmajidnidnasser1@gmail.com": "NIDNASSER-Abdelmajid",
|
2026-04-22 18:16:00 -07:00
|
|
|
"projectadmin@wit.id": "projectadmin-dev",
|
2026-04-22 18:16:38 -07:00
|
|
|
"mrigankamondal10@gmail.com": "Dev-Mriganka",
|
2026-04-22 18:17:16 -07:00
|
|
|
"132275809+shushuzn@users.noreply.github.com": "shushuzn",
|
2026-04-22 18:43:58 -07:00
|
|
|
"ibrahimozsarac@gmail.com": "iborazzi",
|
2026-04-22 18:44:34 -07:00
|
|
|
"130149563+A-afflatus@users.noreply.github.com": "A-afflatus",
|
2026-04-22 19:59:01 -07:00
|
|
|
"huangkwell@163.com": "huangke19",
|
2026-04-22 20:00:19 -07:00
|
|
|
"tanishq@exa.ai": "10ishq",
|
2026-04-22 20:01:47 -07:00
|
|
|
"363708+christopherwoodall@users.noreply.github.com": "christopherwoodall",
|
2026-04-22 20:02:34 -07:00
|
|
|
"zhang9w0v5@qq.com": "zhang9w0v5",
|
2026-04-22 20:03:27 -07:00
|
|
|
"fuleinist@outlook.com": "fuleinist",
|
2026-04-22 21:15:18 -07:00
|
|
|
"43494187+Llugaes@users.noreply.github.com": "Llugaes",
|
2026-04-22 21:16:05 -07:00
|
|
|
"fengtianyu88@users.noreply.github.com": "fengtianyu88",
|
2026-04-22 21:16:51 -07:00
|
|
|
"l.moncany@gmail.com": "lmoncany",
|
2026-04-22 21:17:25 -07:00
|
|
|
"fatinghenji@users.noreply.github.com": "fatinghenji",
|
2026-04-22 21:18:16 -07:00
|
|
|
"xin.peng.dr@gmail.com": "xinpengdr",
|
2026-04-22 21:27:21 -07:00
|
|
|
"mike@mikewaters.net": "mikewaters",
|
2026-04-22 21:28:04 -07:00
|
|
|
"65117428+WadydX@users.noreply.github.com": "WadydX",
|
2026-04-22 21:28:50 -07:00
|
|
|
"216480837+isaachuangGMICLOUD@users.noreply.github.com": "isaachuangGMICLOUD",
|
2026-05-06 14:23:59 -07:00
|
|
|
"isaac.h@gmicloud.ai": "isaachuangGMICLOUD",
|
2026-04-22 21:29:38 -07:00
|
|
|
"nukuom976228@gmail.com": "hsy5571616",
|
2026-04-22 21:30:19 -07:00
|
|
|
"11462216+Nan93@users.noreply.github.com": "Nan93",
|
2026-04-23 01:59:06 -07:00
|
|
|
"l973401489@126.com": "zhouxiaoya12",
|
2026-04-23 02:00:37 -07:00
|
|
|
"373119611@qq.com": "roytian1217",
|
2026-04-23 02:02:03 -07:00
|
|
|
"brett@brettbrewer.com": "minorgod",
|
2026-04-23 02:04:25 -07:00
|
|
|
"67779267+wenhao7@users.noreply.github.com": "wenhao7",
|
2026-04-23 02:06:02 -07:00
|
|
|
"git@yzx9.xyz": "yzx9",
|
2026-04-23 02:29:41 -07:00
|
|
|
"nilesh@cloudgeni.us": "lvnilesh",
|
2026-04-23 02:32:30 -07:00
|
|
|
"63502660+azhengbot@users.noreply.github.com": "azhengbot",
|
2026-04-23 02:33:52 -07:00
|
|
|
"sharvil.saxena@gmail.com": "sharziki",
|
2026-04-23 02:34:49 -07:00
|
|
|
"yuanhe@minimaxi.com": "RyanLee-Dev",
|
2026-04-23 02:36:52 -07:00
|
|
|
"curtis992250@gmail.com": "TaroballzChen",
|
2026-04-23 03:01:53 -07:00
|
|
|
"92638503+Lind3ey@users.noreply.github.com": "Lind3ey",
|
2026-04-23 03:05:26 -07:00
|
|
|
"1352808998@qq.com": "phpoh",
|
2026-04-23 03:06:37 -07:00
|
|
|
"caliberoviv@gmail.com": "vivganes",
|
2026-04-23 03:08:04 -07:00
|
|
|
"michaelfackerell@gmail.com": "MikeFac",
|
2026-04-23 03:09:44 -07:00
|
|
|
"18024642@qq.com": "GuyCui",
|
2026-04-23 14:05:45 -07:00
|
|
|
"eumael.mkt@gmail.com": "maelrx",
|
chore: release v0.11.0 (2026.4.23) (#14791)
The Interface release — new Ink-based TUI, pluggable transport architecture,
native AWS Bedrock, five new inference paths (NVIDIA NIM, Arcee, Step Plan,
Gemini CLI OAuth, ai-gateway), GPT-5.5 via Codex OAuth, QQBot (17th platform),
expanded plugin surface, dashboard plugin system + live theme switching, /steer
mid-run nudges, shell hooks, webhook direct-delivery, smarter delegation, and
auxiliary models config UI.
Also folds in the v0.10.0 deferred batch (v0.10.0 shipped only the Nous Tool
Gateway). 1,556 commits · 761 PRs · 290 contributors since v0.9.0.
2026-04-23 15:31:59 -07:00
|
|
|
# v0.11.0 additions
|
|
|
|
|
"benbarclay@gmail.com": "benbarclay",
|
|
|
|
|
"lijiawen@umich.edu": "Jiawen-lee",
|
|
|
|
|
"oleksiy@kovyrin.net": "kovyrin",
|
|
|
|
|
"kovyrin.claw@gmail.com": "kovyrin",
|
|
|
|
|
"kaiobarb@gmail.com": "liftaris",
|
|
|
|
|
"me@arihantsethia.com": "arihantsethia",
|
|
|
|
|
"zhuofengwang2003@gmail.com": "coekfung",
|
|
|
|
|
"teknium@noreply.github.com": "teknium1",
|
|
|
|
|
"2114364329@qq.com": "cuyua9",
|
|
|
|
|
"2557058999@qq.com": "Disaster-Terminator",
|
|
|
|
|
"cine.dreamer.one@gmail.com": "LeonSGP43",
|
2026-05-03 16:27:25 +03:00
|
|
|
"zyprothh@gmail.com": "Zyproth",
|
2026-05-03 12:45:23 -07:00
|
|
|
"amitgaur@gmail.com": "amitgaur",
|
2026-05-03 16:49:37 -03:00
|
|
|
"albuquerque.abner@gmail.com": "mrbob-git",
|
2026-05-03 21:26:24 +08:00
|
|
|
"kiala@users.noreply.github.com": "kiala9",
|
|
|
|
|
"alanxchen@gmail.com": "alanxchen85",
|
|
|
|
|
"clawbot@clawbots-Mac-mini.local": "John-tip",
|
|
|
|
|
"der@konsi.org": "konsisumer",
|
|
|
|
|
"cirwel@The-CIRWEL-Group.local": "CIRWEL",
|
|
|
|
|
"molvikar8@gmail.com": "molvikar",
|
|
|
|
|
"nftpoetrist@gmail.com": "nftpoetrist",
|
2026-05-03 12:10:20 -07:00
|
|
|
"dodofun@126.com": "colorcross",
|
|
|
|
|
"1615063567@qq.com": "zhao0112",
|
2026-05-03 03:59:16 +00:00
|
|
|
"ethanguo.2003@gmail.com": "EthanGuo-coder",
|
2026-05-04 01:33:54 -07:00
|
|
|
"dev0jsh@gmail.com": "tmdgusya",
|
|
|
|
|
"leavr@163.com": "leavrcn",
|
|
|
|
|
"17683456+wanazhar@users.noreply.github.com": "wanazhar",
|
|
|
|
|
"26782336+cixuuz@users.noreply.github.com": "cixuuz",
|
|
|
|
|
"aleksandr.pasevin@openzeppelin.com": "pasevin",
|
|
|
|
|
"ubuntu@localhost.localdomain": "holynn-q",
|
|
|
|
|
"holynn@placeholder.local": "holynn-q",
|
|
|
|
|
"agent@hermes.local": "jacdevos",
|
|
|
|
|
"sunsky.lau@gmail.com": "liuhao1024",
|
2026-05-21 23:47:59 -07:00
|
|
|
"fabianoeq@gmail.com": "rodrigoeqnit",
|
2026-05-22 01:20:22 -07:00
|
|
|
"178342791+sgtworkman@users.noreply.github.com": "sgtworkman",
|
2026-05-04 01:33:54 -07:00
|
|
|
"qiuqfang98@qq.com": "keepcalmqqf",
|
|
|
|
|
"261867348+ai-ag2026@users.noreply.github.com": "ai-ag2026",
|
|
|
|
|
"yanzh.su@gmail.com": "YanzhongSu",
|
|
|
|
|
"wanderwang@users.noreply.github.com": "WanderWang",
|
|
|
|
|
"yueheime@gmail.com": "yuehei",
|
2026-05-04 02:28:59 -07:00
|
|
|
"emidomh@gmail.com": "Emidomenge",
|
|
|
|
|
"2642448440@qq.com": "BlackJulySnow",
|
|
|
|
|
"4317663+helix4u@users.noreply.github.com": "helix4u",
|
|
|
|
|
"floptopbot33@gmail.com": "flobo3",
|
|
|
|
|
"dpaluy@users.noreply.github.com": "dpaluy",
|
|
|
|
|
"psikonetik@gmail.com": "el-analista",
|
|
|
|
|
"chenb19870707@gmail.com": "ms-alan",
|
2026-05-14 15:48:18 -07:00
|
|
|
"agorgianitisj@hotmail.com": "johnisag",
|
2026-05-14 15:59:00 -07:00
|
|
|
"phil.thomas@gametime.co": "explainanalyze",
|
2026-05-04 02:28:59 -07:00
|
|
|
"hex-clawd@users.noreply.github.com": "hex-clawd",
|
|
|
|
|
"154585401+LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
|
|
|
|
"barteq@hacknotes.local": "barteqpl",
|
|
|
|
|
"pama0227@gmail.com": "pama0227",
|
|
|
|
|
"52785845+ee-blog@users.noreply.github.com": "ee-blog",
|
|
|
|
|
"simplenamebox@gmail.com": "simplenamebox-ops",
|
|
|
|
|
"balyan.sid@gmail.com": "alt-glitch",
|
|
|
|
|
"xdord@xdorddeMac-mini.local": "foreverxdord",
|
|
|
|
|
"k2767567815@gmail.com": "QifengKuang",
|
2026-05-04 03:07:18 -07:00
|
|
|
"88077783+jjjojoj@users.noreply.github.com": "jjjojoj",
|
|
|
|
|
"valda@underscore.jp": "valda",
|
|
|
|
|
"lling486@163.com": "M3RCUR2Y",
|
|
|
|
|
"buraysandro9@gmail.com": "ygd58",
|
|
|
|
|
"ideathinklab01-source@users.noreply.github.com": "ideathinklab01-source",
|
|
|
|
|
"27987889@qq.com": "zng8418",
|
|
|
|
|
"daniuxie88@proton.me": "DaniuXie",
|
|
|
|
|
"panchanler@gmail.com": "ChanlerDev",
|
|
|
|
|
"252620095+briandevans@users.noreply.github.com": "briandevans",
|
|
|
|
|
"141889580+h0tp-ftw@users.noreply.github.com": "h0tp-ftw",
|
|
|
|
|
"chinadbo@foxmail.com": "chinadbo",
|
|
|
|
|
"82637225+kshitijk4poor@users.noreply.github.com": "kshitijk4poor",
|
|
|
|
|
"xyywtt@gmail.com": "xyiy001",
|
|
|
|
|
"charliekerfoot@gmail.com": "CharlieKerfoot",
|
|
|
|
|
"grey0202@users.noreply.github.com": "Grey0202",
|
2026-05-04 04:40:22 -07:00
|
|
|
"vominh1919@gmail.com": "vominh1919",
|
|
|
|
|
"giwavictor9@gmail.com": "giwaov",
|
|
|
|
|
"yoimexex@gmail.com": "Yoimex",
|
|
|
|
|
"76803960+atongrun@users.noreply.github.com": "atongrun",
|
|
|
|
|
"michaeldanko@icloud.com": "MichaelWDanko",
|
|
|
|
|
"xudavid429@gmail.com": "YX234",
|
|
|
|
|
"kathy@Kathy.local": "julysir",
|
|
|
|
|
"274902531@qq.com": "JanCong",
|
2026-05-04 05:02:59 -07:00
|
|
|
"225304168+e-shizz@users.noreply.github.com": "e-shizz",
|
|
|
|
|
"vincent_hh@users.noreply.github.com": "VinVC",
|
|
|
|
|
"1243352777@qq.com": "zons-zhaozhy",
|
|
|
|
|
"dejie.guo@gmail.com": "JayGwod",
|
|
|
|
|
"52840391+swithek@users.noreply.github.com": "swithek",
|
|
|
|
|
"raipratik0101@gmail.com": "PratikRai0101",
|
|
|
|
|
"code@sasha.id": "sasha-id",
|
|
|
|
|
"chen.yunbo@xydigit.com": "chenyunbo411",
|
|
|
|
|
"openclaw@local": "Asce66",
|
|
|
|
|
"59465365+0xsir0000@users.noreply.github.com": "0xsir0000",
|
|
|
|
|
"lisanhu2014@hotmail.com": "lisanhu",
|
|
|
|
|
"0668001438@zte.com.cn": "chenyunbo411",
|
2026-05-04 12:31:57 -07:00
|
|
|
"steven_chanin@alum.mit.edu": "stevenchanin",
|
|
|
|
|
"fiver@example.com": "halmisen",
|
|
|
|
|
"mayq0422@gmail.com": "yuqianma",
|
2026-05-06 23:13:05 +05:30
|
|
|
"yuqian@zmetasoft.com": "yuqianma",
|
2026-05-04 12:31:57 -07:00
|
|
|
"scott@bubble.local": "bassings",
|
|
|
|
|
"highland0971@users.noreply.github.com": "highland0971",
|
|
|
|
|
"sudolewis@gmail.com": "lewislulu",
|
|
|
|
|
"gaurav2301v@gmail.com": "Gaurav23V",
|
|
|
|
|
"tranquil_flow@protonmail.com": "Tranquil-Flow",
|
|
|
|
|
"albert748@gmail.com": "albert748",
|
|
|
|
|
"ntconguit@gmail.com": "0xharryriddle",
|
|
|
|
|
"lhysdl@gmail.com": "lhysdl",
|
|
|
|
|
"shemol@163.com": "SherlockShemol",
|
2026-05-09 19:29:45 -07:00
|
|
|
"enochlam2002@gmail.com": "eloklam",
|
2026-05-10 20:54:01 -07:00
|
|
|
"eloklam@eloklam-ubuntudesktop.tail21966c.ts.net": "eloklam",
|
2026-05-04 12:31:57 -07:00
|
|
|
"clawdia@fmercurio-macstudio.local": "fmercurio",
|
|
|
|
|
"ricardoporsche001@icloud.com": "Ricardo-M-L",
|
chore: release v0.11.0 (2026.4.23) (#14791)
The Interface release — new Ink-based TUI, pluggable transport architecture,
native AWS Bedrock, five new inference paths (NVIDIA NIM, Arcee, Step Plan,
Gemini CLI OAuth, ai-gateway), GPT-5.5 via Codex OAuth, QQBot (17th platform),
expanded plugin surface, dashboard plugin system + live theme switching, /steer
mid-run nudges, shell hooks, webhook direct-delivery, smarter delegation, and
auxiliary models config UI.
Also folds in the v0.10.0 deferred batch (v0.10.0 shipped only the Nous Tool
Gateway). 1,556 commits · 761 PRs · 290 contributors since v0.9.0.
2026-04-23 15:31:59 -07:00
|
|
|
"leozeli@qq.com": "leozeli",
|
|
|
|
|
"linlehao@cuhk.edu.cn": "LehaoLin",
|
|
|
|
|
"liutong@isacas.ac.cn": "I3eg1nner",
|
|
|
|
|
"peterberthelsen@Peters-MacBook-Air.local": "PeterBerthelsen",
|
|
|
|
|
"root@debian.debian": "lengxii",
|
|
|
|
|
"roque@priveperfumeshn.com": "priveperfumes",
|
|
|
|
|
"shijianzhi@shijianzhideMacBook-Pro.local": "sjz-ks",
|
|
|
|
|
"topcheer@me.com": "topcheer",
|
|
|
|
|
"walli@tencent.com": "walli",
|
|
|
|
|
"zhuofengwang@tencent.com": "Zhuofeng-Wang",
|
2026-04-28 03:41:17 -07:00
|
|
|
"simonweng@tencent.com": "Contentment003111",
|
2026-04-24 03:01:45 -07:00
|
|
|
# April 2026 salvage-PR batch (#14920, #14986, #14966)
|
|
|
|
|
"mrunmayeerane17@gmail.com": "mrunmayee17",
|
|
|
|
|
"69489633+camaragon@users.noreply.github.com": "camaragon",
|
|
|
|
|
"shamork@outlook.com": "shamork",
|
2026-04-24 03:17:17 -07:00
|
|
|
# April 2026 Discord Copilot /model salvage (#15030)
|
|
|
|
|
"cshong2017@outlook.com": "Nicecsh",
|
chore: release v0.11.0 (2026.4.23) (#14791)
The Interface release — new Ink-based TUI, pluggable transport architecture,
native AWS Bedrock, five new inference paths (NVIDIA NIM, Arcee, Step Plan,
Gemini CLI OAuth, ai-gateway), GPT-5.5 via Codex OAuth, QQBot (17th platform),
expanded plugin surface, dashboard plugin system + live theme switching, /steer
mid-run nudges, shell hooks, webhook direct-delivery, smarter delegation, and
auxiliary models config UI.
Also folds in the v0.10.0 deferred batch (v0.10.0 shipped only the Nous Tool
Gateway). 1,556 commits · 761 PRs · 290 contributors since v0.9.0.
2026-04-23 15:31:59 -07:00
|
|
|
# no-github-match — keep as display names
|
|
|
|
|
"clio-agent@sisyphuslabs.ai": "Sisyphus",
|
|
|
|
|
"marco@rutimka.de": "Marco Rutsch",
|
|
|
|
|
"paul@gamma.app": "Paul Bergeron",
|
|
|
|
|
"zhangxicen@example.com": "zhangxicen",
|
|
|
|
|
"codex@openai.invalid": "teknium1",
|
|
|
|
|
"screenmachine@gmail.com": "teknium1",
|
2026-04-24 16:08:17 -07:00
|
|
|
"chenzeshi@live.com": "chen1749144759",
|
2026-04-24 17:54:17 -07:00
|
|
|
"mor.aleksandr@yahoo.com": "MorAlekss",
|
2026-04-28 01:16:20 -07:00
|
|
|
"276649498+ztexydt-cqh@users.noreply.github.com": "ztexydt-cqh",
|
2026-04-25 05:25:41 -07:00
|
|
|
"ash@users.noreply.github.com": "ash",
|
2026-04-27 06:41:30 -07:00
|
|
|
"andrewho.sf@gmail.com": "andrewhosf",
|
2026-04-27 12:47:16 -04:00
|
|
|
# April 2026 Honcho bug-fix consolidation (#15381)
|
|
|
|
|
"HiddenPuppy@users.noreply.github.com": "HiddenPuppy",
|
|
|
|
|
"code@sasha.id": "sasha-id",
|
|
|
|
|
"dontcallmejames@users.noreply.github.com": "dontcallmejames",
|
|
|
|
|
"hekaru.agent@gmail.com": "hekaru-agent",
|
|
|
|
|
"jas9000@gmail.com": "twozle",
|
2026-04-28 03:51:45 -07:00
|
|
|
"r.filgueiras@apheris.com": "rfilgueiras",
|
2026-04-28 04:58:40 -07:00
|
|
|
"leihaibo1992@gmail.com": "Leihb",
|
2026-04-28 23:55:07 +05:30
|
|
|
# ACP streaming fix salvage (PR #9428 + #16273)
|
|
|
|
|
"nfb0408@163.com": "ningfangbin",
|
|
|
|
|
"164839249+Joseph19820124@users.noreply.github.com": "Joseph19820124",
|
2026-04-28 23:27:50 +05:30
|
|
|
"rugved@lmstudio.ai": "rugvedS07",
|
2026-04-30 03:28:17 -07:00
|
|
|
"44333070+Heltman@users.noreply.github.com": "Heltman",
|
2026-04-30 11:31:01 -07:00
|
|
|
# v0.12.0 additions
|
|
|
|
|
"ching@kachingappz.com": "ching-kaching",
|
|
|
|
|
"codezhujr@gmail.com": "Zjianru", # salvage chain: code by codez, PR #15749 author @Zjianru
|
|
|
|
|
"daimon@noreply.github.com": "Siddharth Balyan", # co-author only
|
|
|
|
|
"i@zkl2333.com": "zkl2333",
|
|
|
|
|
"isaachuang@Isaacs-MacBook-Pro.local": "isaachuangGMICLOUD",
|
|
|
|
|
"isaachuang@Mac.localdomain": "isaachuangGMICLOUD", # salvage of PR #11955 → #16663
|
|
|
|
|
"liyuan851277048@icloud.com": "Octopus", # co-author only
|
|
|
|
|
"me+github7604@versun.org": "Versun", # co-author only
|
|
|
|
|
"my.vesper.nine@gmail.com": "kevin-ho", # salvage: PR #15488 author @kevin-ho
|
|
|
|
|
"noreply@paperclip.ing": "Paperclip", # co-author only
|
|
|
|
|
"teknium@hermes-agent": "teknium1",
|
|
|
|
|
"web3blind@gmail.com": "web3blind",
|
|
|
|
|
"ztzheng@163.com": "chengoak", # PR #17467
|
|
|
|
|
"24110240104@m.fudan.edu.cn": "YuShu", # co-author only
|
2026-05-03 15:13:10 +05:30
|
|
|
"charliekerfoot@gmail.com": "CharlieKerfoot", # PR #18951
|
2026-05-03 19:58:44 +02:00
|
|
|
# Debug share upload-time redaction (May 2026)
|
|
|
|
|
"dhuysamen@gmail.com": "GodsBoy", # PR #19318
|
2026-05-07 04:51:20 -07:00
|
|
|
"mrcoferland@gmail.com": "mrcoferland", # PR #19023
|
2026-05-07 05:09:36 -07:00
|
|
|
"chenlinfeng@ruije.com.cn": "noOne-list", # PR #19050
|
2026-05-07 05:10:58 -07:00
|
|
|
"briansu@Mac-mini.attlocal.net": "likejudy", # PR #19052
|
2026-05-07 05:19:58 -07:00
|
|
|
"leosma@gmail.com": "leon7609", # PR #19069
|
2026-05-07 05:24:32 -07:00
|
|
|
"nouseman666@gmail.com": "nouseman666", # PR #19088
|
2026-05-07 05:26:18 -07:00
|
|
|
"ginwu05@gmail.com": "GinWU05", # PR #19093
|
2026-05-07 05:58:00 -07:00
|
|
|
"shashwatgokhe2@gmail.com": "shashwatgokhe", # PR #19196
|
2026-05-07 06:04:18 -07:00
|
|
|
"stevenchou.ai@gmail.com": "stevenchouai", # PR #19221
|
2026-05-07 06:19:46 -07:00
|
|
|
"leo.gong@phizchat.com": "agilejava", # PR #19346
|
2026-05-07 06:21:39 -07:00
|
|
|
"acc001k@pm.me": "acc001k", # PR #19358
|
2026-05-07 06:24:13 -07:00
|
|
|
"kowenhao@users.noreply.github.com": "kowenhaoai", # PR #19376
|
2026-05-07 06:27:34 -07:00
|
|
|
"hedirman@gmail.com": "hedirman", # PR #19410
|
2026-05-07 06:29:15 -07:00
|
|
|
"lucianopacheco@gmail.com": "LucianoSP", # PR #19412
|
2026-05-07 06:30:56 -07:00
|
|
|
"paultian.research@gmail.com": "paul-tian", # PR #19423
|
2026-05-07 06:37:12 -07:00
|
|
|
"info@glesperance.com": "glesperance", # PR #19443
|
2026-05-07 05:46:51 -07:00
|
|
|
"lxl694522264@gmail.com": "EvilDrag0n", # PR #20651
|
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
|
|
|
# v0.13.0 additions
|
|
|
|
|
"clode@clo5de.info": "jackey8616", # via PR salvage
|
|
|
|
|
"james.russo@heygen.com": "jrusso1020", # via PR salvage
|
|
|
|
|
"leon@sgp43.com": "LeonSGP43", # PR #18739 salvage of #14570
|
|
|
|
|
"miniding@miniding.home": "Foolafroos", # PR #20329 French locale
|
|
|
|
|
"montbra@gmail.com": "Montbra", # PR #20897 salvage of #16189 (TUI voice PTT)
|
|
|
|
|
"promptsiren@gmail.com": "firefly", # PR #18123 salvage of #16660 (ContextVars)
|
|
|
|
|
"wtyopenclaw@gmail.com": "WuTianyi123", # PR #20275 salvage of #13723 (feishu markdown)
|
2026-05-08 07:01:15 -07:00
|
|
|
"zhicheng.han@mathematik.uni-goettingen.de": "hanzckernel", # PR #20311 (api-server approval events)
|
2026-05-09 13:08:15 +05:30
|
|
|
"agentsmithlaor@gmail.com": "oferlaor", # PR #22356 salvage (cron origin sender identity)
|
2026-05-09 01:39:16 -07:00
|
|
|
"jhin.lee@unity3d.com": "leehack", # PR #22053 salvage (telegram DM topic reply fallback)
|
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
|
|
|
# pander: empty email, salvaged via PR #19665 from #16126 by @ms-alan
|
2026-05-02 01:45:37 -04:00
|
|
|
"ayman.a.kamal@hotmail.com": "A-kamal", # PR #18678 (xAI image resolution fix)
|
2026-05-11 18:02:51 +05:30
|
|
|
# Kanban bug-fix batch salvage (May 2026)
|
|
|
|
|
"frowte3k@gmail.com": "Frowtek", # salvage of #23206 (gateway --board auto-subscribe)
|
|
|
|
|
"sylw3st3rr@gmail.com": "Sylw3ster", # salvage of #23252 (HERMES_KANBAN_BOARD restore)
|
|
|
|
|
"hello@dominikh.com": "dmnkhorvath", # salvage of #23358 (kanban worker send_message)
|
|
|
|
|
"413011+smwbev@users.noreply.github.com": "smwbev", # salvage of #23659 (aria-label colLabel)
|
|
|
|
|
"58116817+TurgutKural@users.noreply.github.com": "TurgutKural", # salvage of #23356 (HERMES_HOME inject)
|
2026-05-11 16:34:08 +05:30
|
|
|
"openclaw@agent.local": "29206394", # PR #22194 salvage (sudo -S brute-force guard, #9590)
|
|
|
|
|
"freedemon@gmail.com": "fr33d3m0n", # PR #21128 salvage (sudo stdin/askpass DANGEROUS, #17873 cat 4)
|
2026-05-11 08:05:26 -07:00
|
|
|
"zhaowh3613@outlook.com": "VinceZcrikl", # PR #23647 salvage (npm UTF-8 decode on GBK Windows)
|
feat(session_search): single-shape tool with discovery, scroll, browse — no LLM (#27590)
* feat(session_search): single-shape tool with discovery, scroll, browse — no LLM
Replaces the LLM-summarized session_search with a single-shape tool that
returns actual messages from the DB. Three calling shapes inferred from
args (no mode parameter):
1. Discovery — pass query. FTS5 + anchored ±5 window + bookends per hit,
all in one call. ~20ms on a real DB instead of ~90s for the previous
three aux-LLM calls.
2. Scroll — pass session_id + around_message_id. Returns a window
centered on the anchor. To paginate, re-anchor on the first/last id
of the returned window. Boundary message appears in both windows
as the orientation marker. ~1ms per scroll call.
3. Browse — no args. Recent sessions chronologically.
Bookend_start (first 3 user+assistant msgs) and bookend_end (last 3) give
the agent goal + resolution on every discovery hit, so a single tool call
reconstructs a long session's arc without loading the whole transcript.
The aux-LLM summary path is gone: it cost ~$0.30/call, took ~30s, and
laundered FTS5 hits through a model that could confabulate when the right
session wasn't in the hit list. The merged shape returns byte-for-byte
content from SQLite.
History:
- PR #20238 (JabberELF) seeded the fast/summary dual-mode split.
- PR #26419 (yoniebans) expanded to fast/guided/summary with bookends,
multi-anchor drill-down, default-mode config, and a teaching skill.
This PR collapses that toolkit into one shape with explicit scroll
support, drops the summary path, drops the mode parameter, drops the
config knob, drops the skill. JabberELF's seed work is acknowledged via
the AUTHOR_MAP entry.
Validation:
- 38/38 tool tests pass (tests/tools/test_session_search.py)
- 12/12 get_messages_around tests pass (tests/hermes_state/)
- 11/11 get_anchored_view tests pass (tests/hermes_state/)
- Full tests/tools/ run: 5168 passing, 2 failures pre-exist on main
(test ordering in test_delegate.py, unrelated)
- E2E against live state DB: discovery 20ms, scroll 1ms, browse 280ms;
pagination forward+backward works with boundary-message orientation;
error paths return clean tool_error responses
Co-authored-by: JabberELF <abcdjmm970703@gmail.com>
Co-authored-by: yoniebans <jonny@nousresearch.com>
* chore(session_search): prune dead LLM-summary config and docs
Companion to the single-shape rewrite. The auxiliary.session_search config
block, max_concurrency / extra_body tunables, and matching docs sections
all referenced the removed LLM summarization path. Removing them so users
don't try to tune knobs that nothing reads.
- hermes_cli/config.py: drop dead auxiliary.session_search block from
DEFAULT_CONFIG. Leftover keys in user config.yaml are harmless and
ignored.
- hermes_cli/tips.py: drop two tips referencing the removed
max_concurrency / extra_body knobs.
- website/docs/user-guide/configuration.md: drop 'Session Search Tuning'
section and the auxiliary.session_search block from the example.
- website/docs/user-guide/features/fallback-providers.md: drop session_search
rows from the auxiliary-tasks tables and the dedicated tuning subsection.
- website/docs/reference/tools-reference.md: rewrite the session_search
entry to describe the new three-shape behaviour.
- CONTRIBUTING.md: update the file-tree description.
- tests/tools/test_llm_content_none_guard.py: remove TestSessionSearchContentNone
class and test_session_search_tool_guarded — both guard against an
unguarded .content.strip() call site in _summarize_session() that no
longer exists.
Validation: 97/97 targeted tests still pass (hermes_state + session_search +
llm_content_none_guard). Config tests 55/55.
---------
Co-authored-by: JabberELF <abcdjmm970703@gmail.com>
Co-authored-by: yoniebans <jonny@nousresearch.com>
2026-05-17 23:28:45 -07:00
|
|
|
"abcdjmm970703@gmail.com": "JabberELF", # PR #20238 seed (session_search dual-mode, evolved into single-shape)
|
2026-05-13 09:01:33 -07:00
|
|
|
"anton.kuenzi@gmail.com": "ZeterMordio", # PR #11754 salvage (zsh completion compdef + _arguments syntax)
|
2026-05-13 08:38:36 -07:00
|
|
|
"23yntong@stu.edu.cn": "iuyup", # PR #6155 salvage (shell=True hardening)
|
2026-05-13 23:04:16 -07:00
|
|
|
"86501179+1RB@users.noreply.github.com": "1RB", # PR #25462 salvage (discord forwarded messages)
|
|
|
|
|
"44045943+ayushere@users.noreply.github.com": "ayushere", # PR #25342 salvage (memory teardown leak)
|
|
|
|
|
"15791290+domtriola@users.noreply.github.com": "domtriola", # PR #25424 salvage (docs tirith link)
|
|
|
|
|
"284216128+ephron-ren@users.noreply.github.com": "ephron-ren", # PR #25358 salvage (MiMo reasoning echo-back)
|
|
|
|
|
"96843562+freqyfreqy@users.noreply.github.com": "freqyfreqy", # PR #25423 salvage (docs LSP worktree -> repo)
|
|
|
|
|
"54306477+fu576@users.noreply.github.com": "fu576", # PR #25369 salvage (api_mode not inherited cross-provider)
|
|
|
|
|
"258095375+kfa-ai@users.noreply.github.com": "kfa-ai", # PR #25398 salvage (whatsapp quoted reply metadata)
|
|
|
|
|
"99181308+magic524@users.noreply.github.com": "magic524", # PR #25361 salvage (QQBot reconnect loop)
|
|
|
|
|
"9150277+PaTTeeL@users.noreply.github.com": "PaTTeeL", # PR #25359 salvage (custom_providers in compression length)
|
|
|
|
|
"1700913+pearjelly@users.noreply.github.com": "pearjelly", # PR #25388 salvage (feishu ws connect override sync)
|
|
|
|
|
"100820567+raymaylee@users.noreply.github.com": "raymaylee", # PR #25394 salvage (context compaction status)
|
|
|
|
|
"122434621+Tianyu199509@users.noreply.github.com": "Tianyu199509", # PR #25421 salvage (gateway PID Windows)
|
2026-05-14 07:57:00 -07:00
|
|
|
"58224596+HxT9@users.noreply.github.com": "HxT9", # PR #25760 salvage (web sync-assets cross-platform)
|
|
|
|
|
"120411712+evgyur@users.noreply.github.com": "evgyur", # PR #25651 salvage (docs media session context)
|
|
|
|
|
"36507055+AsoTora@users.noreply.github.com": "AsoTora", # PR #25624 salvage (MCP auth no-retry)
|
|
|
|
|
"98992931+oxngon@users.noreply.github.com": "oxngon", # PR #25603 salvage (forward image attachments to bg tasks)
|
|
|
|
|
"37467487+yifengingit@users.noreply.github.com": "yifengingit", # PR #25589 salvage (AUTOINCREMENT id ordering)
|
|
|
|
|
"89525629+vanthinh6886@users.noreply.github.com": "vanthinh6886", # PR #25562 salvage (.env 0600 perms)
|
|
|
|
|
"16034932+Arkmusn@users.noreply.github.com": "Arkmusn", # PR #25559 salvage (approvals.timeout from config)
|
2026-05-15 01:49:56 -07:00
|
|
|
"nidhi2894@gmail.com": "nidhi-singh02", # PR #2752 salvage (slack whitespace-only IndexError guard)
|
|
|
|
|
"38173192+nidhi-singh02@users.noreply.github.com": "nidhi-singh02",
|
2026-05-15 17:44:27 +01:00
|
|
|
"Jaaneek@users.noreply.github.com": "Jaaneek", # PR #26457 (xAI Grok OAuth provider)
|
2026-05-16 02:58:57 -07:00
|
|
|
# v0.14.0 additions
|
|
|
|
|
"chuang.guo@hopechart.com": "wuwuzhijing", # PR #21063 salvage (gateway docs mention Weixin)
|
|
|
|
|
"nightcityblade@gmail.com": "nightcityblade", # PR #24138 (docs voice/tts table)
|
|
|
|
|
"pol.kuijken@gmail.com": "polkn", # PR #6136 salvage (skill_view collision refusal)
|
|
|
|
|
"robin@soal.org": "rewbs",
|
2026-05-16 20:31:55 -07:00
|
|
|
# batch salvage (May 2026 LHF run)
|
|
|
|
|
"sauravsejal40@gmail.com": "Saurav0989", # PR #27071 (docs: hermes-eval community link)
|
|
|
|
|
"220110965+Saurav0989@users.noreply.github.com": "Saurav0989",
|
|
|
|
|
"aviarchi1994@gmail.com": "avifenesh", # PR #25902 (docs: computer-use-linux MCP)
|
|
|
|
|
"55848801+avifenesh@users.noreply.github.com": "avifenesh",
|
|
|
|
|
"279959838+BROCCOLO1D@users.noreply.github.com": "BROCCOLO1D", # PR #26796 (docs: spotify + HA)
|
|
|
|
|
"m@matthewlai.ca": "matthewlai", # PR #25293 (feat: gemma 4 reasoning allowlist)
|
|
|
|
|
"4296245+matthewlai@users.noreply.github.com": "matthewlai",
|
2026-05-16 20:27:45 -07:00
|
|
|
"109617724+0xchainer@users.noreply.github.com": "0xchainer", # PR #27154/27138/27147 salvage
|
|
|
|
|
"201800237+kronexoi@users.noreply.github.com": "kronexoi", # PR #27167 salvage (Teams port fallback)
|
2026-05-16 23:09:08 -07:00
|
|
|
"283442588+EloquentBrush0x@users.noreply.github.com": "EloquentBrush0x", # PR #26642 salvage (post_setup parity)
|
2026-05-16 22:53:29 -07:00
|
|
|
# batch salvage (May 2026 LHF run, group 2)
|
|
|
|
|
"shellybotmoyer@example.com": "shellybotmoyer", # PR #26661 (kanban --severity >=)
|
|
|
|
|
"coulson@shellybotmoyer.com": "shellybotmoyer", # PR #25576 (credential_pool ISO rehydrate)
|
|
|
|
|
"258858106+shellybotmoyer@users.noreply.github.com": "shellybotmoyer",
|
|
|
|
|
"33156212+ether-btc@users.noreply.github.com": "ether-btc", # PR #26632 (memory provider whitespace guard)
|
|
|
|
|
"Bloomtonjovish@gmail.com": "LifeJiggy", # PR #26516 (paste collapse logging)
|
|
|
|
|
"141562589+LifeJiggy@users.noreply.github.com": "LifeJiggy",
|
2026-05-18 19:35:21 -07:00
|
|
|
"192385615+LifeJiggy@users.noreply.github.com": "LifeJiggy", # stale salvage commit alias (PR #28315)
|
2026-05-16 22:53:29 -07:00
|
|
|
"beastant1@gmail.com": "nekwo", # PR #26481 (PS5.1 UTF-8 BOM)
|
|
|
|
|
"43717185+nekwo@users.noreply.github.com": "nekwo",
|
2026-05-19 11:30:25 -07:00
|
|
|
"9785479+stepanov1975@users.noreply.github.com": "stepanov1975", # PR #22074 (setup config picker writes)
|
2026-05-16 22:53:29 -07:00
|
|
|
"67979730+flooryyyy@users.noreply.github.com": "flooryyyy", # PR #26374 (tool_trace error detection)
|
|
|
|
|
"188585318+dgians@users.noreply.github.com": "dgians", # PR #26034 (.ts/.py/.sh docs types)
|
|
|
|
|
"zealy@tz.co": "dgians", # PR #26034 (bot-committed by zealy-tzco under dgians' PR)
|
|
|
|
|
"mottei.survive@gmail.com": "flanny7", # PR #27030 (setup_open_webui python var)
|
|
|
|
|
"20530505+flanny7@users.noreply.github.com": "flanny7",
|
|
|
|
|
"hermesagent26@gmail.com": "hermesagent26", # PR #26438 (kimi model-name reasoning pad)
|
|
|
|
|
"276067471+hermesagent26@users.noreply.github.com": "hermesagent26",
|
|
|
|
|
"71590782+kriscolab@users.noreply.github.com": "kriscolab", # PR #26926 (deepseek default_aux_model)
|
2026-05-16 23:04:09 -07:00
|
|
|
# batch salvage (May 2026 LHF run, group 3)
|
|
|
|
|
"darvsum@users.noreply.github.com": "darvsum", # PR #26766 (preserve discover_models in normalize)
|
|
|
|
|
"peter@Peters-Mac-mini.local": "hueilau", # PR #26498 (strip image parts for non-vision)
|
|
|
|
|
"33933019+hueilau@users.noreply.github.com": "hueilau",
|
|
|
|
|
"32297275+Timur00Kh@users.noreply.github.com": "Timur00Kh", # PR #27114 (telegram DM topic for synthetic events)
|
|
|
|
|
"al.bellemare@gmail.com": "Grogger", # PR #27061 (windows console flash suppress)
|
2026-05-18 20:01:12 -07:00
|
|
|
"7065068+Grogger@users.noreply.github.com": "Grogger",
|
|
|
|
|
"18091625+Grogger@users.noreply.github.com": "Grogger", # stale salvage commit alias (PR #28330)
|
2026-05-16 23:04:09 -07:00
|
|
|
"clement@nousresearch.com": "lemassykoi", # PR #27042 (model-switch probe keyless providers)
|
|
|
|
|
"16377344+lemassykoi@users.noreply.github.com": "lemassykoi",
|
|
|
|
|
"draplater@icloud.com": "draplater", # PR #26707 (goal judge current time)
|
|
|
|
|
"6349758+draplater@users.noreply.github.com": "draplater",
|
|
|
|
|
"pr7426@users.noreply.github.com": "pr7426", # PR #27048 (cron parallel job loss)
|
|
|
|
|
"rahulnilvan43@gmail.com": "therahul-yo", # PR #26215 (mock keychain in tests)
|
|
|
|
|
"kingsleyemeka117@gmail.com": "flamiinngo", # PR #27205 (UnicodeEncodeError footgun checker)
|
2026-05-16 23:10:34 -07:00
|
|
|
# batch salvage (May 2026 LHF run, group 4)
|
|
|
|
|
"283442588+EloquentBrush0x@users.noreply.github.com": "EloquentBrush0x", # PR #26657 (trust_env aiohttp)
|
|
|
|
|
"205509009+subtract0@users.noreply.github.com": "subtract0", # PR #25658 (zsh $status -> $rc)
|
|
|
|
|
"patryk@jarmakowicz.me": "zwolniony", # PR #26961 (gemini x-goog-api-key)
|
|
|
|
|
"12735938+zwolniony@users.noreply.github.com": "zwolniony",
|
|
|
|
|
"ambuj@dodopayments.com": "that-ambuj", # PR #26582 (preserve underscores)
|
|
|
|
|
"zccyman@163.com": "zccyman", # PR #25294 (custom provider api_key_env alias)
|
2026-05-18 10:22:41 -07:00
|
|
|
# xAI cluster batch salvage (May 2026)
|
|
|
|
|
"lgndscntn@gmail.com": "Fewmanism", # PR #27420 (threaded xAI OAuth callback)
|
|
|
|
|
"slimydog@Faisals-Mac-mini.local": "Slimydog21", # PR #28021 (strip slash enums xAI Responses)
|
2026-05-18 10:37:08 -07:00
|
|
|
"194121339+Slimydog21@users.noreply.github.com": "Slimydog21", # PR #28021 salvage (noreply form)
|
2026-05-16 23:10:34 -07:00
|
|
|
"bitkyc08@gmail.com": "lidge-jun", # PR #26814 (api server browser security headers)
|
|
|
|
|
"sp_ps@Mac-mini.lan": "phoenixshen", # PR #26768 (respect user-configured vision model)
|
|
|
|
|
"1594534+phoenixshen@users.noreply.github.com": "phoenixshen",
|
|
|
|
|
"147827411+AhmetArif0@users.noreply.github.com": "AhmetArif0", # PR #26635 (line proxy env vars)
|
2026-05-17 02:30:17 -07:00
|
|
|
# batch salvage (May 2026 LHF run, group 5)
|
|
|
|
|
"hari@Hariharans-MacBook-Air-8.local": "haran2001", # PR #27070 (i18n catalog test)
|
|
|
|
|
"hariharan15151@gmail.com": "haran2001", # PR #27068 (qwen3.6-plus 1M context)
|
|
|
|
|
"56040092+haran2001@users.noreply.github.com": "haran2001",
|
|
|
|
|
"1472110+ms-alan@users.noreply.github.com": "ms-alan", # PR #26443 (reload-skills tab completion)
|
|
|
|
|
"ganlinbupt@gmail.com": "godlin-gh", # PR #26118 (ACP polished tools)
|
|
|
|
|
"wesley.simplicio.ext@siemens-energy.com": "wesleysimplicio", # PR #25777 (xterm.js native selection)
|
|
|
|
|
"6108320+wesleysimplicio@users.noreply.github.com": "wesleysimplicio",
|
|
|
|
|
"carryzuo00@gmail.com": "Carry00", # PR #26851 (doctor SSH env vars)
|
|
|
|
|
"alaamohanad169-ship-it@users.noreply.github.com": "alaamohanad169-ship-it", # PR #26036 (telegram typing after send)
|
|
|
|
|
"vigo@hermes": "hawknewton", # PR #26294 (bedrock boto3 lazy_deps)
|
|
|
|
|
"211668+hawknewton@users.noreply.github.com": "hawknewton",
|
2026-05-17 11:37:09 -07:00
|
|
|
"quenvix00@gmail.com": "QuenVix", # PR #26761/26772 salvage
|
|
|
|
|
"164776164+QuenVix@users.noreply.github.com": "QuenVix",
|
|
|
|
|
"262945885+Mind-Dragon@users.noreply.github.com": "Mind-Dragon", # PR #26966 salvage
|
|
|
|
|
"soynchuux@gmail.com": "soynchux", # PR #27060 salvage
|
|
|
|
|
"209694554+soynchux@users.noreply.github.com": "soynchux",
|
2026-05-17 11:37:00 -07:00
|
|
|
# batch salvage (May 2026 LHF run, group 6 — final)
|
|
|
|
|
"6666242+bird@users.noreply.github.com": "bird", # PR #25219 (gateway docker exit-75 restart)
|
|
|
|
|
"david@loadmagic.ai": "davidcampbelldc", # PR #26834 (web_server proxy_headers=False)
|
|
|
|
|
"165905879+davidcampbelldc@users.noreply.github.com": "davidcampbelldc",
|
2026-05-17 11:50:15 -07:00
|
|
|
"hoangv.pham0803@gmail.com": "hehehe0803", # PR #26212 salvage (codex kanban writable root)
|
|
|
|
|
"26063003+hehehe0803@users.noreply.github.com": "hehehe0803",
|
fix(codex): size and propagate timeouts for Responses-API requests; lower stale defaults
Codex / Responses-API requests had three latent timeout bugs that combined
into the long silent hangs reported on #21444:
1. The non-stream stale-call detector estimated context tokens from
``api_kwargs["messages"]`` only. Codex / Responses-API payloads carry
their conversational load in ``input`` (with ``instructions`` and
``tools``), so every Codex turn logged ``context=~0 tokens`` and the
detector never applied its >50k / >100k tier bumps.
2. ``providers.<id>.request_timeout_seconds`` was silently dropped on the
main Codex path. The chat_completions path and the auxiliary Codex
adapter both forwarded it; the main path skipped it through three
places (``build_api_kwargs``, ``ResponsesApiTransport.build_kwargs``,
``_preflight_codex_api_kwargs``).
3. The streaming stale detector had the same payload-shape bug for
``codex_responses`` requests, which route through the non-streaming
detector (it's the path that emits the user-facing
"No response from provider for 300s (non-streaming, ...)" warning that
reporters keep pasting).
This commit:
- Adds ``estimate_request_context_tokens`` in ``chat_completion_helpers``,
used by both the non-stream and stream detectors. Handles ``messages``
(Chat Completions), ``input + instructions + tools`` (Responses API),
bare lists, and an unknown-dict fallback.
- Forwards ``timeout`` through ``ResponsesApiTransport.build_kwargs``
and ``_preflight_codex_api_kwargs`` (with guards against
zero/negative/inf/bool values), and wires
``_resolved_api_call_timeout()`` into the Codex branch of
``build_api_kwargs``.
- Lowers the implicit non-stream stale defaults so fallback providers
kick in faster when upstream stalls:
* base 300s -> 90s
* >50k 450s -> 150s
* >100k 600s -> 240s
These only apply when the user has *not* set
``providers.<id>.stale_timeout_seconds`` or
``HERMES_API_CALL_STALE_TIMEOUT``. Explicit config still wins.
- Adds regression tests for the estimator shapes, the new defaults, the
context-tier scaling, transport timeout pass-through, and preflight
timeout pass-through / rejection of invalid values.
Closes #21444
Supersedes #21652 #24126 #31855
Co-authored-by: Hoang V. Pham <26063003+hehehe0803@users.noreply.github.com>
2026-05-25 01:36:22 -07:00
|
|
|
"kasunvinod@users.noreply.github.com": "kasunvinod", # PR #24126 salvage (codex timeout propagation)
|
|
|
|
|
"15059870+kasunvinod@users.noreply.github.com": "kasunvinod",
|
2026-05-17 11:51:36 -07:00
|
|
|
"38348871+vaddisrinivas@users.noreply.github.com": "vaddisrinivas", # PR #26394 salvage (Docker messaging extra)
|
2026-05-18 19:30:38 -07:00
|
|
|
# batch salvage (May 2026 LHF run, group 7)
|
|
|
|
|
"198679067+02356abc@users.noreply.github.com": "02356abc", # PR #28286 salvage (wecom CLOSING)
|
|
|
|
|
"1743117+burjorjee@users.noreply.github.com": "burjorjee", # PR #28201 salvage (inline-shell timeout guard)
|
|
|
|
|
"keki@MacBookPro.attlocal.net": "burjorjee",
|
|
|
|
|
"264690993+oseftg@users.noreply.github.com": "oseftg", # PR #28168 salvage (natural ending emoji/caret)
|
|
|
|
|
"hex.hermes@agentmail.to": "oseftg",
|
|
|
|
|
"236912655+rudi193-cmd@users.noreply.github.com": "rudi193-cmd", # PR #28241 salvage (empty credential pool)
|
|
|
|
|
"rudi193@gmail.com": "rudi193-cmd",
|
|
|
|
|
"86684667+sadiksaifi@users.noreply.github.com": "sadiksaifi", # PR #27982 salvage (kanban horiz scroll)
|
|
|
|
|
"mail@sadiksaifi.dev": "sadiksaifi",
|
2026-05-28 01:49:48 -07:00
|
|
|
"231588442+vynxevainglory-ai@users.noreply.github.com": "vynxevainglory-ai", # PR #29233 salvage (kanban scrollbar + body overflow)
|
|
|
|
|
"vynxevainglory@gmail.com": "vynxevainglory-ai",
|
2026-05-18 19:59:23 -07:00
|
|
|
# batch salvage (May 2026 LHF run, group 8)
|
|
|
|
|
"266824395+AceWattGit@users.noreply.github.com": "AceWattGit", # PR #28159 salvage (_pool_may_recover NameError)
|
|
|
|
|
"57024493+YuanHanzhong@users.noreply.github.com": "YuanHanzhong", # PR #28032 salvage (x.com status link-like)
|
|
|
|
|
"24368158+colin-chang@users.noreply.github.com": "colin-chang", # PR #28245/#28249/#28251 salvage
|
|
|
|
|
"zhangcheng5468@gmail.com": "colin-chang",
|
|
|
|
|
"172729123+felix-windsor@users.noreply.github.com": "felix-windsor", # PR #28019 salvage (cron asterisks)
|
|
|
|
|
"felixwindsor3344@gmail.com": "felix-windsor",
|
|
|
|
|
"259054917+houenyang-momo@users.noreply.github.com": "houenyang-momo", # PR #28205 salvage (charizard contrast)
|
2026-05-27 02:27:25 -07:00
|
|
|
"33547839+sir-ad@users.noreply.github.com": "sir-ad", # PR #31941 salvage (compaction noise)
|
|
|
|
|
"adarsh.agrahari26@gmail.com": "sir-ad",
|
|
|
|
|
"269599864+rdasilva1016-ui@users.noreply.github.com": "rdasilva1016-ui", # PR #31098 salvage (Telegram /start ping)
|
|
|
|
|
"rdasilva1016-ui@users.noreply.github.com": "rdasilva1016-ui",
|
2026-05-18 19:59:23 -07:00
|
|
|
"35931201+iqdoctor@users.noreply.github.com": "iqdoctor", # PR #28095 salvage (windows installer docs)
|
|
|
|
|
"29513231+joe102084@users.noreply.github.com": "joe102084", # PR #28151 salvage (whitespace cron responses)
|
|
|
|
|
"joe102084@gmail.com": "joe102084",
|
|
|
|
|
"4139778+jvinals@users.noreply.github.com": "jvinals", # PR #27936 salvage (Slack U-IDs)
|
|
|
|
|
"3001335+maxmilian@users.noreply.github.com": "maxmilian", # PR #28267 salvage (Change Model portal)
|
|
|
|
|
"maxmilian@gmail.com": "maxmilian",
|
|
|
|
|
"41468846+samggggflynn@users.noreply.github.com": "samggggflynn", # PR #27952 salvage (dingtalk pre_start)
|
|
|
|
|
"abc401011721@gmail.com": "samggggflynn",
|
2026-05-18 20:09:12 -07:00
|
|
|
"yannsunn@users.noreply.github.com": "yannsunn", # PR #28064 salvage (xai proxy upstream)
|
|
|
|
|
"yannsunn1116@gmail.com": "yannsunn",
|
2026-05-18 21:48:55 -07:00
|
|
|
"asdlem@users.noreply.github.com": "asdlem", # PR #27852 salvage (clarify full text in body)
|
2026-05-18 23:57:55 -07:00
|
|
|
# batch salvage (May 2026 LHF run, group 9)
|
|
|
|
|
"1779909+jdelmerico@users.noreply.github.com": "jdelmerico", # PR #28278 salvage (signal require_mention)
|
|
|
|
|
"20639347+justemu@users.noreply.github.com": "justemu", # PR #27996 salvage (matrix thread_require_mention)
|
|
|
|
|
"justemu@users.noreply.github.com": "justemu",
|
|
|
|
|
"57024493+YuanHanzhong@users.noreply.github.com": "YuanHanzhong", # PR #28029 salvage (dashboard scrollback)
|
|
|
|
|
"YuanHanzhong@users.noreply.github.com": "YuanHanzhong",
|
|
|
|
|
"1663402+noctilust@users.noreply.github.com": "noctilust", # PR #28080 salvage (stale TUI resume env)
|
|
|
|
|
"1663402+freeurmind@users.noreply.github.com": "noctilust",
|
|
|
|
|
"35164907+MoonJuhan@users.noreply.github.com": "MoonJuhan", # PR #28288 salvage (unreadable JSONL transcripts)
|
|
|
|
|
"codemike@naver.com": "MoonJuhan",
|
|
|
|
|
"201563152+outsourc-e@users.noreply.github.com": "outsourc-e", # PR #28164 salvage (cron emoji ZWJ)
|
|
|
|
|
"201803425+Zyrixtrex@users.noreply.github.com": "Zyrixtrex", # PR #28275 salvage (Google OAuth timeout)
|
|
|
|
|
"zyrixtrex@gmail.com": "Zyrixtrex",
|
|
|
|
|
"120500656+ooovenenoso@users.noreply.github.com": "ooovenenoso", # PR #28256 salvage (tool loop recovery hints)
|
|
|
|
|
"120500656+oooindefatigable@users.noreply.github.com": "ooovenenoso",
|
|
|
|
|
"vanthinh6886@gmail.com": "vanthinh6886", # PR #28018 salvage (yaml/flock/atomic write guards)
|
2026-05-19 17:44:51 +00:00
|
|
|
"erik.engervall@gmail.com": "erikengervall", # PR #28774 (firecrawl integration tag)
|
2026-05-23 01:41:31 -07:00
|
|
|
"egilewski@egilewski.com": "egilewski", # PR #30432 (MEDIA path traversal fix, GHSA-jmf9-9729-7pp8)
|
2026-05-23 16:16:12 -07:00
|
|
|
"edison@mcclean.codes": "McClean-Edison", # PR #29817 (register_auxiliary_task plugin API)
|
2026-05-24 15:06:15 -07:00
|
|
|
"zhangsamuel12@gmail.com": "SamuelZ12", # PR #7480 (show recap after in-session resume)
|
2026-05-24 15:49:10 -07:00
|
|
|
"490408354@qq.com": "daizhonggeng", # PR #9020 (numbered /resume selection)
|
2026-05-25 00:44:35 -07:00
|
|
|
"claw@openclaw.ai": "wanwan2qq", # PR #10215 (strip brackets/quotes from /resume; gateway session-ID lookup)
|
2026-05-25 03:50:03 -07:00
|
|
|
"simo.kiihamaki@gmail.com": "SimoKiihamaki", # PR #30773 (Windows /reset+/new freeze; stdin fallback for modal)
|
2026-05-25 03:59:30 -07:00
|
|
|
"66773372+Tranquil-Flow@users.noreply.github.com": "Tranquil-Flow", # PR #27518 (bracketed-paste timeout)
|
2026-05-25 12:47:56 +00:00
|
|
|
"8bit64k@pm.me": "8bit64k", # PR #14681 (TUI /q alias from quit to queue)
|
|
|
|
|
"chenglunhu@gmail.com": "hclsys", # PR #31985 (TUI /q alias regression test)
|
2026-05-25 17:38:06 -07:00
|
|
|
"dearmayo@localhost": "ffr31mr", # PR #32103 (SubdirectoryHintTracker workspace boundary)
|
|
|
|
|
"TheOnlyMika@users.noreply.github.com": "TheOnlyMika", # PR #32155 (dashboard XSS + defusedxml)
|
2026-05-25 23:15:56 -07:00
|
|
|
"krislidimo@gmail.com": "krislidimo", # PR #29775 (tighten Telegram table row-group spacing; drop redundant first bullet)
|
2026-05-27 01:41:20 -07:00
|
|
|
"timothy.b.dixon@gmail.com": "Codename-11", # PR #29302 (API server session controls — sessions/chat/fork/stream)
|
|
|
|
|
"jpschwartz2@uwalumni.com": "Schwartz10", # PR #29302 sub-PR (multimodal media in session chat API)
|
2026-05-27 09:37:50 -07:00
|
|
|
"JohnC1009@users.noreply.github.com": "JohnC1009", # PR #32020 salvage (auth: global auth.json fallback in _load_provider_state)
|
2026-05-28 03:02:52 -07:00
|
|
|
"biser@bisko.be": "bisko", # PR #33784 salvage (re-pad reasoning_content on cross-provider fallback to require-side providers)
|
chore: release v0.15.0 (2026.5.28) (#34008)
* chore: release v0.15.0 (2026.5.28)
The Velocity Release. Run_agent.py refactor (16k→3.8k LOC, -76%),
kanban grows into a multi-agent platform (104 PRs), cold-start perf wave
continues (-240ms / -47% per-turn function calls / -195ms per tool call),
session_search rebuilt (4500x faster, no LLM), promptware defense lands,
Bitwarden Secrets Manager integration, two new image_gen providers
(Krea 2, FAL plugin port), Nous-approved MCP catalog, OpenHands skill,
ntfy as 23rd messaging platform, deep xAI integration round.
15 P0 + 65 P1 closures. 747 PRs, 1,302 commits, 321 contributors.
* chore(release): bump acp_registry/agent.json to 0.15.0 (sync with pyproject)
2026-05-28 10:45:33 -07:00
|
|
|
# v0.15.0 additions
|
|
|
|
|
"glen@workmanfirearms.com": "sgtworkman",
|
|
|
|
|
"jorge.fuenmayort@gmail.com": "jfuenmayor",
|
|
|
|
|
"mordred@inaugust.com": "emonty",
|
|
|
|
|
"rodrigoeq@hotmail.com": "rodrigoeqnit",
|
|
|
|
|
"soliva.johnpaul@icloud.com": "jonpol01",
|
|
|
|
|
"2182712990@qq.com": "yu-xin-c", # PR #32122 (Docker audio bridge notes)
|
|
|
|
|
"baxter@bitreserve.ai": "BaxBit", # PR #30200 (Svix webhook signature validation)
|
|
|
|
|
"chris.eth@qq.com": "duyua9", # PR #10949 (render object config values structurally)
|
|
|
|
|
"ethie@nous": "ethernet8023", # PR #29342 (TUI clipboard copy on linux/wayland)
|
|
|
|
|
"jiahuigu@sjtu.edu.cn": "Jiahui-Gu", # PR #29276 (guard pickle.loads in darwinian-evolver)
|
|
|
|
|
"justinccdev@gmail.com": "justincc", # PR #28914 (set tool_name on tool-result messages)
|
|
|
|
|
"kdkcfp@gmail.com": "slowtokki0409", # PR #29025 (ignore local Hermes runtime files)
|
|
|
|
|
"peter.yuqin@gmail.com": "WuKongAI-CMU", # PR #10082 (reject symlinked audio inputs)
|
|
|
|
|
"sunil.nitie@gmail.com": "Sunil123135", # PR #31031 (Windows Docker Desktop compose)
|
|
|
|
|
"weichangyuwcy@gmail.com": "ChyuWei", # PR #30987 (TUI TTS env var on voice off)
|
2026-03-12 01:35:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def git(*args, cwd=None):
|
|
|
|
|
"""Run a git command and return stdout."""
|
|
|
|
|
result = subprocess.run(
|
|
|
|
|
["git"] + list(args),
|
|
|
|
|
capture_output=True, text=True,
|
|
|
|
|
cwd=cwd or str(REPO_ROOT),
|
|
|
|
|
)
|
|
|
|
|
if result.returncode != 0:
|
|
|
|
|
print(f"git {' '.join(args)} failed: {result.stderr}", file=sys.stderr)
|
|
|
|
|
return ""
|
|
|
|
|
return result.stdout.strip()
|
|
|
|
|
|
|
|
|
|
|
2026-03-30 17:34:43 -07:00
|
|
|
def git_result(*args, cwd=None):
|
|
|
|
|
"""Run a git command and return the full CompletedProcess."""
|
|
|
|
|
return subprocess.run(
|
|
|
|
|
["git"] + list(args),
|
|
|
|
|
capture_output=True,
|
|
|
|
|
text=True,
|
|
|
|
|
cwd=cwd or str(REPO_ROOT),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2026-03-12 01:35:47 -07:00
|
|
|
def get_last_tag():
|
|
|
|
|
"""Get the most recent CalVer tag."""
|
|
|
|
|
tags = git("tag", "--list", "v20*", "--sort=-v:refname")
|
|
|
|
|
if tags:
|
|
|
|
|
return tags.split("\n")[0]
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
2026-03-30 17:34:43 -07:00
|
|
|
def next_available_tag(base_tag: str) -> tuple[str, str]:
|
|
|
|
|
"""Return a tag/calver pair, suffixing same-day releases when needed."""
|
|
|
|
|
if not git("tag", "--list", base_tag):
|
|
|
|
|
return base_tag, base_tag.removeprefix("v")
|
|
|
|
|
|
|
|
|
|
suffix = 2
|
|
|
|
|
while git("tag", "--list", f"{base_tag}.{suffix}"):
|
|
|
|
|
suffix += 1
|
|
|
|
|
tag_name = f"{base_tag}.{suffix}"
|
|
|
|
|
return tag_name, tag_name.removeprefix("v")
|
|
|
|
|
|
|
|
|
|
|
2026-03-12 01:35:47 -07:00
|
|
|
def get_current_version():
|
|
|
|
|
"""Read current semver from __init__.py."""
|
|
|
|
|
content = VERSION_FILE.read_text()
|
|
|
|
|
match = re.search(r'__version__\s*=\s*"([^"]+)"', content)
|
|
|
|
|
return match.group(1) if match else "0.0.0"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def bump_version(current: str, part: str) -> str:
|
|
|
|
|
"""Bump a semver version string."""
|
|
|
|
|
parts = current.split(".")
|
|
|
|
|
if len(parts) != 3:
|
|
|
|
|
parts = ["0", "0", "0"]
|
|
|
|
|
major, minor, patch = int(parts[0]), int(parts[1]), int(parts[2])
|
|
|
|
|
|
|
|
|
|
if part == "major":
|
|
|
|
|
major += 1
|
|
|
|
|
minor = 0
|
|
|
|
|
patch = 0
|
|
|
|
|
elif part == "minor":
|
|
|
|
|
minor += 1
|
|
|
|
|
patch = 0
|
|
|
|
|
elif part == "patch":
|
|
|
|
|
patch += 1
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError(f"Unknown bump part: {part}")
|
|
|
|
|
|
|
|
|
|
return f"{major}.{minor}.{patch}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def update_version_files(semver: str, calver_date: str):
|
|
|
|
|
"""Update version strings in source files."""
|
|
|
|
|
# Update __init__.py
|
|
|
|
|
content = VERSION_FILE.read_text()
|
|
|
|
|
content = re.sub(
|
|
|
|
|
r'__version__\s*=\s*"[^"]+"',
|
|
|
|
|
f'__version__ = "{semver}"',
|
|
|
|
|
content,
|
|
|
|
|
)
|
|
|
|
|
content = re.sub(
|
|
|
|
|
r'__release_date__\s*=\s*"[^"]+"',
|
|
|
|
|
f'__release_date__ = "{calver_date}"',
|
|
|
|
|
content,
|
|
|
|
|
)
|
|
|
|
|
VERSION_FILE.write_text(content)
|
|
|
|
|
|
|
|
|
|
# Update pyproject.toml
|
|
|
|
|
pyproject = PYPROJECT_FILE.read_text()
|
|
|
|
|
pyproject = re.sub(
|
|
|
|
|
r'^version\s*=\s*"[^"]+"',
|
|
|
|
|
f'version = "{semver}"',
|
|
|
|
|
pyproject,
|
|
|
|
|
flags=re.MULTILINE,
|
|
|
|
|
)
|
|
|
|
|
PYPROJECT_FILE.write_text(pyproject)
|
|
|
|
|
|
2026-05-14 20:15:37 -07:00
|
|
|
# Update ACP Registry manifest + npm launcher (must stay version-locked
|
|
|
|
|
# with pyproject — enforced by tests/acp/test_registry_manifest.py).
|
|
|
|
|
_update_acp_registry_versions(semver)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _update_acp_registry_versions(semver: str) -> None:
|
2026-05-14 22:05:39 -07:00
|
|
|
"""Bump the ACP Registry manifest's version + uvx package pin in lockstep
|
|
|
|
|
with pyproject.
|
2026-05-14 20:15:37 -07:00
|
|
|
|
2026-05-14 22:05:39 -07:00
|
|
|
Skips silently if the manifest is missing — older release branches predate
|
|
|
|
|
the ACP Registry assets.
|
2026-05-14 20:15:37 -07:00
|
|
|
"""
|
|
|
|
|
if ACP_REGISTRY_MANIFEST.exists():
|
|
|
|
|
manifest = json.loads(ACP_REGISTRY_MANIFEST.read_text(encoding="utf-8"))
|
|
|
|
|
manifest["version"] = semver
|
2026-05-14 22:05:39 -07:00
|
|
|
uvx = manifest.get("distribution", {}).get("uvx", {})
|
|
|
|
|
if "package" in uvx:
|
|
|
|
|
uvx["package"] = f"hermes-agent[acp]=={semver}"
|
2026-05-14 20:15:37 -07:00
|
|
|
# Preserve trailing newline + 2-space indent the file already uses.
|
|
|
|
|
ACP_REGISTRY_MANIFEST.write_text(
|
|
|
|
|
json.dumps(manifest, indent=2) + "\n", encoding="utf-8"
|
|
|
|
|
)
|
|
|
|
|
|
2026-03-12 01:35:47 -07:00
|
|
|
|
2026-03-30 17:34:43 -07:00
|
|
|
def build_release_artifacts(semver: str) -> list[Path]:
|
|
|
|
|
"""Build sdist/wheel artifacts for the current release.
|
|
|
|
|
|
2026-05-15 13:21:48 +05:30
|
|
|
Tries ``uv build`` first (matching the CI workflow), falls back to
|
|
|
|
|
``python -m build`` if uv is unavailable.
|
2026-03-30 17:34:43 -07:00
|
|
|
"""
|
|
|
|
|
dist_dir = REPO_ROOT / "dist"
|
|
|
|
|
shutil.rmtree(dist_dir, ignore_errors=True)
|
|
|
|
|
|
2026-05-15 13:21:48 +05:30
|
|
|
# Prefer uv build (matches CI workflow), fall back to python -m build.
|
|
|
|
|
uv_bin = shutil.which("uv")
|
|
|
|
|
if uv_bin:
|
|
|
|
|
cmd = [uv_bin, "build", "--sdist", "--wheel"]
|
|
|
|
|
else:
|
|
|
|
|
cmd = [sys.executable, "-m", "build", "--sdist", "--wheel"]
|
|
|
|
|
|
2026-03-30 17:34:43 -07:00
|
|
|
result = subprocess.run(
|
2026-05-15 13:21:48 +05:30
|
|
|
cmd,
|
2026-03-30 17:34:43 -07:00
|
|
|
cwd=str(REPO_ROOT),
|
|
|
|
|
capture_output=True,
|
|
|
|
|
text=True,
|
|
|
|
|
)
|
|
|
|
|
if result.returncode != 0:
|
|
|
|
|
print(" ⚠ Could not build Python release artifacts.")
|
|
|
|
|
stderr = result.stderr.strip()
|
|
|
|
|
stdout = result.stdout.strip()
|
|
|
|
|
if stderr:
|
|
|
|
|
print(f" {stderr.splitlines()[-1]}")
|
|
|
|
|
elif stdout:
|
|
|
|
|
print(f" {stdout.splitlines()[-1]}")
|
2026-05-15 13:21:48 +05:30
|
|
|
print(" Install uv or the 'build' package to attach sdist/wheel assets.")
|
2026-03-30 17:34:43 -07:00
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
artifacts = sorted(p for p in dist_dir.iterdir() if p.is_file())
|
|
|
|
|
matching = [p for p in artifacts if semver in p.name]
|
|
|
|
|
if not matching:
|
|
|
|
|
print(" ⚠ Built artifacts did not match the expected release version.")
|
|
|
|
|
return []
|
|
|
|
|
return matching
|
|
|
|
|
|
|
|
|
|
|
2026-03-12 01:35:47 -07:00
|
|
|
def resolve_author(name: str, email: str) -> str:
|
|
|
|
|
"""Resolve a git author to a GitHub @mention."""
|
|
|
|
|
# Try email lookup first
|
|
|
|
|
gh_user = AUTHOR_MAP.get(email)
|
|
|
|
|
if gh_user:
|
|
|
|
|
return f"@{gh_user}"
|
|
|
|
|
|
|
|
|
|
# Try noreply pattern
|
|
|
|
|
noreply_match = re.match(r"(\d+)\+(.+)@users\.noreply\.github\.com", email)
|
|
|
|
|
if noreply_match:
|
|
|
|
|
return f"@{noreply_match.group(2)}"
|
|
|
|
|
|
|
|
|
|
# Try username@users.noreply.github.com
|
|
|
|
|
noreply_match2 = re.match(r"(.+)@users\.noreply\.github\.com", email)
|
|
|
|
|
if noreply_match2:
|
|
|
|
|
return f"@{noreply_match2.group(1)}"
|
|
|
|
|
|
|
|
|
|
# Fallback to git name
|
|
|
|
|
return name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def categorize_commit(subject: str) -> str:
|
|
|
|
|
"""Categorize a commit by its conventional commit prefix."""
|
|
|
|
|
subject_lower = subject.lower()
|
|
|
|
|
|
|
|
|
|
# Match conventional commit patterns
|
|
|
|
|
patterns = {
|
|
|
|
|
"breaking": [r"^breaking[\s:(]", r"^!:", r"BREAKING CHANGE"],
|
|
|
|
|
"features": [r"^feat[\s:(]", r"^feature[\s:(]", r"^add[\s:(]"],
|
|
|
|
|
"fixes": [r"^fix[\s:(]", r"^bugfix[\s:(]", r"^bug[\s:(]", r"^hotfix[\s:(]"],
|
|
|
|
|
"improvements": [r"^improve[\s:(]", r"^perf[\s:(]", r"^enhance[\s:(]",
|
|
|
|
|
r"^refactor[\s:(]", r"^cleanup[\s:(]", r"^clean[\s:(]",
|
|
|
|
|
r"^update[\s:(]", r"^optimize[\s:(]"],
|
|
|
|
|
"docs": [r"^doc[\s:(]", r"^docs[\s:(]"],
|
|
|
|
|
"tests": [r"^test[\s:(]", r"^tests[\s:(]"],
|
|
|
|
|
"chore": [r"^chore[\s:(]", r"^ci[\s:(]", r"^build[\s:(]",
|
|
|
|
|
r"^deps[\s:(]", r"^bump[\s:(]"],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for category, regexes in patterns.items():
|
|
|
|
|
for regex in regexes:
|
|
|
|
|
if re.match(regex, subject_lower):
|
|
|
|
|
return category
|
|
|
|
|
|
|
|
|
|
# Heuristic fallbacks
|
|
|
|
|
if any(w in subject_lower for w in ["add ", "new ", "implement", "support "]):
|
|
|
|
|
return "features"
|
|
|
|
|
if any(w in subject_lower for w in ["fix ", "fixed ", "resolve", "patch "]):
|
|
|
|
|
return "fixes"
|
|
|
|
|
if any(w in subject_lower for w in ["refactor", "cleanup", "improve", "update "]):
|
|
|
|
|
return "improvements"
|
|
|
|
|
|
|
|
|
|
return "other"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def clean_subject(subject: str) -> str:
|
|
|
|
|
"""Clean up a commit subject for display."""
|
|
|
|
|
# Remove conventional commit prefix
|
|
|
|
|
cleaned = re.sub(r"^(feat|fix|docs|chore|refactor|test|perf|ci|build|improve|add|update|cleanup|hotfix|breaking|enhance|optimize|bugfix|bug|feature|tests|deps|bump)[\s:(!]+\s*", "", subject, flags=re.IGNORECASE)
|
|
|
|
|
# Remove trailing issue refs that are redundant with PR links
|
|
|
|
|
cleaned = cleaned.strip()
|
|
|
|
|
# Capitalize first letter
|
|
|
|
|
if cleaned:
|
|
|
|
|
cleaned = cleaned[0].upper() + cleaned[1:]
|
|
|
|
|
return cleaned
|
|
|
|
|
|
|
|
|
|
|
2026-04-13 16:31:27 -07:00
|
|
|
def parse_coauthors(body: str) -> list:
|
|
|
|
|
"""Extract Co-authored-by trailers from a commit message body.
|
|
|
|
|
|
|
|
|
|
Returns a list of {'name': ..., 'email': ...} dicts.
|
|
|
|
|
Filters out AI assistants and bots (Claude, Copilot, Cursor, etc.).
|
|
|
|
|
"""
|
|
|
|
|
if not body:
|
|
|
|
|
return []
|
|
|
|
|
# AI/bot emails to ignore in co-author trailers
|
|
|
|
|
_ignored_emails = {"noreply@anthropic.com", "noreply@github.com",
|
|
|
|
|
"cursoragent@cursor.com", "hermes@nousresearch.com"}
|
|
|
|
|
_ignored_names = re.compile(r"^(Claude|Copilot|Cursor Agent|GitHub Actions?|dependabot|renovate)", re.IGNORECASE)
|
|
|
|
|
pattern = re.compile(r"Co-authored-by:\s*(.+?)\s*<([^>]+)>", re.IGNORECASE)
|
|
|
|
|
results = []
|
|
|
|
|
for m in pattern.finditer(body):
|
|
|
|
|
name, email = m.group(1).strip(), m.group(2).strip()
|
|
|
|
|
if email in _ignored_emails or _ignored_names.match(name):
|
|
|
|
|
continue
|
|
|
|
|
results.append({"name": name, "email": email})
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
|
2026-03-12 01:35:47 -07:00
|
|
|
def get_commits(since_tag=None):
|
|
|
|
|
"""Get commits since a tag (or all commits if None)."""
|
|
|
|
|
if since_tag:
|
|
|
|
|
range_spec = f"{since_tag}..HEAD"
|
|
|
|
|
else:
|
|
|
|
|
range_spec = "HEAD"
|
|
|
|
|
|
2026-05-15 13:21:48 +05:30
|
|
|
# Format: hash<US>author_name<US>author_email<US>subject\0body
|
|
|
|
|
# Using %x1f (unit separator) to avoid conflict with | in author names
|
2026-03-12 01:35:47 -07:00
|
|
|
log = git(
|
|
|
|
|
"log", range_spec,
|
2026-05-15 13:21:48 +05:30
|
|
|
"--format=%H%x1f%an%x1f%ae%x1f%s%x00%b%x00",
|
2026-03-12 01:35:47 -07:00
|
|
|
"--no-merges",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if not log:
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
commits = []
|
2026-04-13 16:31:27 -07:00
|
|
|
# Split on double-null to get each commit entry, since body ends with \0
|
|
|
|
|
# and format ends with \0, each record ends with \0\0 between entries
|
|
|
|
|
for entry in log.split("\0\0"):
|
|
|
|
|
entry = entry.strip()
|
|
|
|
|
if not entry:
|
2026-03-12 01:35:47 -07:00
|
|
|
continue
|
2026-05-15 13:21:48 +05:30
|
|
|
# Split on first null to separate "hash<US>name<US>email<US>subject" from "body"
|
2026-04-13 16:31:27 -07:00
|
|
|
if "\0" in entry:
|
|
|
|
|
header, body = entry.split("\0", 1)
|
|
|
|
|
body = body.strip()
|
|
|
|
|
else:
|
|
|
|
|
header = entry
|
|
|
|
|
body = ""
|
2026-05-15 13:21:48 +05:30
|
|
|
parts = header.split("\x1f", 3)
|
2026-03-12 01:35:47 -07:00
|
|
|
if len(parts) != 4:
|
|
|
|
|
continue
|
|
|
|
|
sha, name, email, subject = parts
|
2026-04-13 16:31:27 -07:00
|
|
|
coauthor_info = parse_coauthors(body)
|
|
|
|
|
coauthors = [resolve_author(ca["name"], ca["email"]) for ca in coauthor_info]
|
2026-03-12 01:35:47 -07:00
|
|
|
commits.append({
|
|
|
|
|
"sha": sha,
|
|
|
|
|
"short_sha": sha[:8],
|
|
|
|
|
"author_name": name,
|
|
|
|
|
"author_email": email,
|
|
|
|
|
"subject": subject,
|
|
|
|
|
"category": categorize_commit(subject),
|
|
|
|
|
"github_author": resolve_author(name, email),
|
2026-04-13 16:31:27 -07:00
|
|
|
"coauthors": coauthors,
|
2026-03-12 01:35:47 -07:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return commits
|
|
|
|
|
|
|
|
|
|
|
2026-05-15 13:21:48 +05:30
|
|
|
def get_pr_number(subject: str) -> str | None:
|
2026-03-12 01:35:47 -07:00
|
|
|
"""Extract PR number from commit subject if present."""
|
|
|
|
|
match = re.search(r"#(\d+)", subject)
|
|
|
|
|
if match:
|
|
|
|
|
return match.group(1)
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_changelog(commits, tag_name, semver, repo_url="https://github.com/NousResearch/hermes-agent",
|
|
|
|
|
prev_tag=None, first_release=False):
|
|
|
|
|
"""Generate markdown changelog from categorized commits."""
|
|
|
|
|
lines = []
|
|
|
|
|
|
|
|
|
|
# Header
|
|
|
|
|
now = datetime.now()
|
|
|
|
|
date_str = now.strftime("%B %d, %Y")
|
|
|
|
|
lines.append(f"# Hermes Agent v{semver} ({tag_name})")
|
|
|
|
|
lines.append("")
|
|
|
|
|
lines.append(f"**Release Date:** {date_str}")
|
|
|
|
|
lines.append("")
|
|
|
|
|
|
|
|
|
|
if first_release:
|
|
|
|
|
lines.append("> 🎉 **First official release!** This marks the beginning of regular weekly releases")
|
|
|
|
|
lines.append("> for Hermes Agent. See below for everything included in this initial release.")
|
|
|
|
|
lines.append("")
|
|
|
|
|
|
|
|
|
|
# Group commits by category
|
|
|
|
|
categories = defaultdict(list)
|
|
|
|
|
all_authors = set()
|
|
|
|
|
teknium_aliases = {"@teknium1"}
|
|
|
|
|
|
|
|
|
|
for commit in commits:
|
|
|
|
|
categories[commit["category"]].append(commit)
|
|
|
|
|
author = commit["github_author"]
|
|
|
|
|
if author not in teknium_aliases:
|
|
|
|
|
all_authors.add(author)
|
2026-04-13 16:31:27 -07:00
|
|
|
for coauthor in commit.get("coauthors", []):
|
|
|
|
|
if coauthor not in teknium_aliases:
|
|
|
|
|
all_authors.add(coauthor)
|
2026-03-12 01:35:47 -07:00
|
|
|
|
|
|
|
|
# Category display order and emoji
|
|
|
|
|
category_order = [
|
|
|
|
|
("breaking", "⚠️ Breaking Changes"),
|
|
|
|
|
("features", "✨ Features"),
|
|
|
|
|
("improvements", "🔧 Improvements"),
|
|
|
|
|
("fixes", "🐛 Bug Fixes"),
|
|
|
|
|
("docs", "📚 Documentation"),
|
|
|
|
|
("tests", "🧪 Tests"),
|
|
|
|
|
("chore", "🏗️ Infrastructure"),
|
|
|
|
|
("other", "📦 Other Changes"),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
for cat_key, cat_title in category_order:
|
|
|
|
|
cat_commits = categories.get(cat_key, [])
|
|
|
|
|
if not cat_commits:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
lines.append(f"## {cat_title}")
|
|
|
|
|
lines.append("")
|
|
|
|
|
|
|
|
|
|
for commit in cat_commits:
|
|
|
|
|
subject = clean_subject(commit["subject"])
|
|
|
|
|
pr_num = get_pr_number(commit["subject"])
|
|
|
|
|
author = commit["github_author"]
|
|
|
|
|
|
|
|
|
|
# Build the line
|
|
|
|
|
parts = [f"- {subject}"]
|
|
|
|
|
if pr_num:
|
|
|
|
|
parts.append(f"([#{pr_num}]({repo_url}/pull/{pr_num}))")
|
|
|
|
|
else:
|
|
|
|
|
parts.append(f"([`{commit['short_sha']}`]({repo_url}/commit/{commit['sha']}))")
|
|
|
|
|
|
|
|
|
|
if author not in teknium_aliases:
|
|
|
|
|
parts.append(f"— {author}")
|
|
|
|
|
|
|
|
|
|
lines.append(" ".join(parts))
|
|
|
|
|
|
|
|
|
|
lines.append("")
|
|
|
|
|
|
|
|
|
|
# Contributors section
|
|
|
|
|
if all_authors:
|
|
|
|
|
# Sort contributors by commit count
|
|
|
|
|
author_counts = defaultdict(int)
|
|
|
|
|
for commit in commits:
|
|
|
|
|
author = commit["github_author"]
|
|
|
|
|
if author not in teknium_aliases:
|
|
|
|
|
author_counts[author] += 1
|
2026-04-13 16:31:27 -07:00
|
|
|
for coauthor in commit.get("coauthors", []):
|
|
|
|
|
if coauthor not in teknium_aliases:
|
|
|
|
|
author_counts[coauthor] += 1
|
2026-03-12 01:35:47 -07:00
|
|
|
|
|
|
|
|
sorted_authors = sorted(author_counts.items(), key=lambda x: -x[1])
|
|
|
|
|
|
|
|
|
|
lines.append("## 👥 Contributors")
|
|
|
|
|
lines.append("")
|
|
|
|
|
lines.append("Thank you to everyone who contributed to this release!")
|
|
|
|
|
lines.append("")
|
|
|
|
|
for author, count in sorted_authors:
|
|
|
|
|
commit_word = "commit" if count == 1 else "commits"
|
|
|
|
|
lines.append(f"- {author} ({count} {commit_word})")
|
|
|
|
|
lines.append("")
|
|
|
|
|
|
|
|
|
|
# Full changelog link
|
|
|
|
|
if prev_tag:
|
|
|
|
|
lines.append(f"**Full Changelog**: [{prev_tag}...{tag_name}]({repo_url}/compare/{prev_tag}...{tag_name})")
|
|
|
|
|
else:
|
|
|
|
|
lines.append(f"**Full Changelog**: [{tag_name}]({repo_url}/commits/{tag_name})")
|
|
|
|
|
lines.append("")
|
|
|
|
|
|
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
parser = argparse.ArgumentParser(description="Hermes Agent Release Tool")
|
|
|
|
|
parser.add_argument("--bump", choices=["major", "minor", "patch"],
|
|
|
|
|
help="Which semver component to bump")
|
|
|
|
|
parser.add_argument("--publish", action="store_true",
|
|
|
|
|
help="Actually create the tag and GitHub release (otherwise dry run)")
|
|
|
|
|
parser.add_argument("--date", type=str,
|
|
|
|
|
help="Override CalVer date (format: YYYY.M.D)")
|
|
|
|
|
parser.add_argument("--first-release", action="store_true",
|
|
|
|
|
help="Mark as first release (no previous tag expected)")
|
|
|
|
|
parser.add_argument("--output", type=str,
|
|
|
|
|
help="Write changelog to file instead of stdout")
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
|
|
# Determine CalVer date
|
|
|
|
|
if args.date:
|
|
|
|
|
calver_date = args.date
|
|
|
|
|
else:
|
|
|
|
|
now = datetime.now()
|
|
|
|
|
calver_date = f"{now.year}.{now.month}.{now.day}"
|
|
|
|
|
|
2026-03-30 17:34:43 -07:00
|
|
|
base_tag = f"v{calver_date}"
|
|
|
|
|
tag_name, calver_date = next_available_tag(base_tag)
|
|
|
|
|
if tag_name != base_tag:
|
|
|
|
|
print(f"Note: Tag {base_tag} already exists, using {tag_name}")
|
2026-03-12 01:35:47 -07:00
|
|
|
|
|
|
|
|
# Determine semver
|
|
|
|
|
current_version = get_current_version()
|
|
|
|
|
if args.bump:
|
|
|
|
|
new_version = bump_version(current_version, args.bump)
|
|
|
|
|
else:
|
|
|
|
|
new_version = current_version
|
|
|
|
|
|
|
|
|
|
# Get previous tag
|
|
|
|
|
prev_tag = get_last_tag()
|
|
|
|
|
if not prev_tag and not args.first_release:
|
|
|
|
|
print("No previous tags found. Use --first-release for the initial release.")
|
|
|
|
|
print(f"Would create tag: {tag_name}")
|
|
|
|
|
print(f"Would set version: {new_version}")
|
2026-05-15 13:21:48 +05:30
|
|
|
return
|
2026-03-12 01:35:47 -07:00
|
|
|
|
|
|
|
|
# Get commits
|
|
|
|
|
commits = get_commits(since_tag=prev_tag)
|
|
|
|
|
if not commits:
|
|
|
|
|
print("No new commits since last tag.")
|
|
|
|
|
if not args.first_release:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
print(f"{'='*60}")
|
|
|
|
|
print(f" Hermes Agent Release Preview")
|
|
|
|
|
print(f"{'='*60}")
|
|
|
|
|
print(f" CalVer tag: {tag_name}")
|
|
|
|
|
print(f" SemVer: v{current_version} → v{new_version}")
|
|
|
|
|
print(f" Previous tag: {prev_tag or '(none — first release)'}")
|
|
|
|
|
print(f" Commits: {len(commits)}")
|
2026-05-11 11:20:58 -07:00
|
|
|
print(f" Unique authors: {len({c['github_author'] for c in commits})}")
|
2026-03-12 01:35:47 -07:00
|
|
|
print(f" Mode: {'PUBLISH' if args.publish else 'DRY RUN'}")
|
|
|
|
|
print(f"{'='*60}")
|
|
|
|
|
print()
|
|
|
|
|
|
|
|
|
|
# Generate changelog
|
|
|
|
|
changelog = generate_changelog(
|
|
|
|
|
commits, tag_name, new_version,
|
|
|
|
|
prev_tag=prev_tag,
|
|
|
|
|
first_release=args.first_release,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if args.output:
|
codebase: add encoding='utf-8' to all bare open() calls (PLW1514)
Closes the last Python-on-Windows UTF-8 exposure by making every
text-mode open() call explicit about its encoding.
Before: on Windows, bare open(path, 'r') defaults to the system
locale encoding (cp1252 on US-locale installs). That means reading
any config/yaml/markdown/json file with non-ASCII content either
crashes with UnicodeDecodeError or silently mis-decodes bytes.
After: all 89 affected call sites in production code now pass
encoding='utf-8' explicitly. Works identically on every platform
and every locale, no surprise behavior.
Mechanical sweep via:
ruff check --preview --extend-select PLW1514 --unsafe-fixes --fix --exclude 'tests,venv,.venv,node_modules,website,optional-skills, skills,tinker-atropos,plugins' .
All 89 fixes have the same shape: open(x) or open(x, mode) became
open(x, encoding='utf-8') or open(x, mode, encoding='utf-8'). Nothing
else changed. Every modified file still parses and the Windows/sandbox
test suite is still green (85 passed, 14 skipped, 0 failed across
tests/tools/test_code_execution_windows_env.py +
tests/tools/test_code_execution_modes.py + tests/tools/test_env_passthrough.py +
tests/test_hermes_bootstrap.py).
Scope notes:
- tests/ excluded: test fixtures can use locale encoding intentionally
(exercising edge cases). If we want to tighten tests later that's
a separate PR.
- plugins/ excluded: plugin-specific conventions may differ; plugin
authors own their code.
- optional-skills/ and skills/ excluded: skill scripts are user-authored
and we don't want to mass-edit them.
- website/ and tinker-atropos/ excluded: vendored / generated content.
46 files touched, 89 +/- lines (symmetric replacement). No behavior
change on POSIX or on Windows when the file is ASCII; bug fix on
Windows when the file contains non-ASCII.
2026-05-07 19:24:45 -07:00
|
|
|
Path(args.output).write_text(changelog, encoding="utf-8")
|
2026-03-12 01:35:47 -07:00
|
|
|
print(f"Changelog written to {args.output}")
|
|
|
|
|
else:
|
|
|
|
|
print(changelog)
|
|
|
|
|
|
|
|
|
|
if args.publish:
|
|
|
|
|
print(f"\n{'='*60}")
|
|
|
|
|
print(" Publishing release...")
|
|
|
|
|
print(f"{'='*60}")
|
|
|
|
|
|
|
|
|
|
# Update version files
|
|
|
|
|
if args.bump:
|
|
|
|
|
update_version_files(new_version, calver_date)
|
|
|
|
|
print(f" ✓ Updated version files to v{new_version} ({calver_date})")
|
|
|
|
|
|
|
|
|
|
# Commit version bump
|
2026-05-15 13:21:48 +05:30
|
|
|
add_files = [str(VERSION_FILE), str(PYPROJECT_FILE)]
|
|
|
|
|
if ACP_REGISTRY_MANIFEST.exists():
|
|
|
|
|
add_files.append(str(ACP_REGISTRY_MANIFEST))
|
|
|
|
|
add_result = git_result("add", *add_files)
|
2026-03-30 17:34:43 -07:00
|
|
|
if add_result.returncode != 0:
|
|
|
|
|
print(f" ✗ Failed to stage version files: {add_result.stderr.strip()}")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
commit_result = git_result(
|
|
|
|
|
"commit", "-m", f"chore: bump version to v{new_version} ({calver_date})"
|
|
|
|
|
)
|
|
|
|
|
if commit_result.returncode != 0:
|
|
|
|
|
print(f" ✗ Failed to commit version bump: {commit_result.stderr.strip()}")
|
|
|
|
|
return
|
2026-03-12 01:35:47 -07:00
|
|
|
print(f" ✓ Committed version bump")
|
|
|
|
|
|
|
|
|
|
# Create annotated tag
|
2026-03-30 17:34:43 -07:00
|
|
|
tag_result = git_result(
|
|
|
|
|
"tag", "-a", tag_name, "-m",
|
|
|
|
|
f"Hermes Agent v{new_version} ({calver_date})\n\nWeekly release"
|
|
|
|
|
)
|
|
|
|
|
if tag_result.returncode != 0:
|
|
|
|
|
print(f" ✗ Failed to create tag {tag_name}: {tag_result.stderr.strip()}")
|
|
|
|
|
return
|
2026-03-12 01:35:47 -07:00
|
|
|
print(f" ✓ Created tag {tag_name}")
|
|
|
|
|
|
|
|
|
|
# Push
|
2026-03-30 17:34:43 -07:00
|
|
|
push_result = git_result("push", "origin", "HEAD", "--tags")
|
|
|
|
|
if push_result.returncode == 0:
|
|
|
|
|
print(f" ✓ Pushed to origin")
|
|
|
|
|
else:
|
|
|
|
|
print(f" ✗ Failed to push to origin: {push_result.stderr.strip()}")
|
|
|
|
|
print(" Continue manually after fixing access:")
|
|
|
|
|
print(" git push origin HEAD --tags")
|
|
|
|
|
|
|
|
|
|
# Build semver-named Python artifacts so downstream packagers
|
|
|
|
|
# (e.g. Homebrew) can target them without relying on CalVer tag names.
|
|
|
|
|
artifacts = build_release_artifacts(new_version)
|
|
|
|
|
if artifacts:
|
|
|
|
|
print(" ✓ Built release artifacts:")
|
|
|
|
|
for artifact in artifacts:
|
|
|
|
|
print(f" - {artifact.relative_to(REPO_ROOT)}")
|
2026-03-12 01:35:47 -07:00
|
|
|
|
|
|
|
|
# Create GitHub release
|
|
|
|
|
changelog_file = REPO_ROOT / ".release_notes.md"
|
2026-05-15 13:21:48 +05:30
|
|
|
changelog_file.write_text(changelog, encoding="utf-8")
|
2026-03-12 01:35:47 -07:00
|
|
|
|
2026-03-30 17:34:43 -07:00
|
|
|
gh_cmd = [
|
|
|
|
|
"gh", "release", "create", tag_name,
|
|
|
|
|
"--title", f"Hermes Agent v{new_version} ({calver_date})",
|
|
|
|
|
"--notes-file", str(changelog_file),
|
|
|
|
|
]
|
|
|
|
|
gh_cmd.extend(str(path) for path in artifacts)
|
|
|
|
|
|
|
|
|
|
gh_bin = shutil.which("gh")
|
|
|
|
|
if gh_bin:
|
|
|
|
|
result = subprocess.run(
|
|
|
|
|
gh_cmd,
|
|
|
|
|
capture_output=True, text=True,
|
|
|
|
|
cwd=str(REPO_ROOT),
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
result = None
|
2026-03-12 01:35:47 -07:00
|
|
|
|
2026-03-30 17:34:43 -07:00
|
|
|
if result and result.returncode == 0:
|
|
|
|
|
changelog_file.unlink(missing_ok=True)
|
2026-03-12 01:35:47 -07:00
|
|
|
print(f" ✓ GitHub release created: {result.stdout.strip()}")
|
2026-03-30 17:34:43 -07:00
|
|
|
print(f"\n 🎉 Release v{new_version} ({tag_name}) published!")
|
2026-03-12 01:35:47 -07:00
|
|
|
else:
|
2026-03-30 17:34:43 -07:00
|
|
|
if result is None:
|
|
|
|
|
print(" ✗ GitHub release skipped: `gh` CLI not found.")
|
|
|
|
|
else:
|
|
|
|
|
print(f" ✗ GitHub release failed: {result.stderr.strip()}")
|
|
|
|
|
print(f" Release notes kept at: {changelog_file}")
|
|
|
|
|
print(f" Tag was created locally. Create the release manually:")
|
|
|
|
|
print(
|
|
|
|
|
f" gh release create {tag_name} --title 'Hermes Agent v{new_version} ({calver_date})' "
|
|
|
|
|
f"--notes-file .release_notes.md {' '.join(str(path) for path in artifacts)}"
|
|
|
|
|
)
|
|
|
|
|
print(f"\n ✓ Release artifacts prepared for manual publish: v{new_version} ({tag_name})")
|
2026-03-12 01:35:47 -07:00
|
|
|
else:
|
|
|
|
|
print(f"\n{'='*60}")
|
|
|
|
|
print(f" Dry run complete. To publish, add --publish")
|
|
|
|
|
print(f" Example: python scripts/release.py --bump minor --publish")
|
|
|
|
|
print(f"{'='*60}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
main()
|