hermes-agent/tools
dongjiang de6a672168 fix(skills-hub): include owner in ClawHub source URLs and add retry on 429 (#51236)
Two fixes for the Skills Hub "View source" links on ClawHub skills:

1. Source URL generation was missing the required {owner} segment —
   https://clawhub.ai/skills/{slug} → 404. Correct format is
   https://clawhub.ai/{owner}/skills/{slug}. When the owner handle is
   unavailable, source_url is now "" (card omits the button) instead of
   emitting a broken link.

2. _fetch_owner_handle() previously delegated to _get_json() which
   returned None on any non-200 response with no retry. Under HTTP 429
   rate-limiting the "50 consecutive failures" safety rail in
   enrich_owners() fired immediately — the documented claim "Respects
   HTTP 429 rate-limit responses with exponential backoff" was not
   actually implemented. Now has its own retry loop: 3 attempts, honours
   Retry-After on 429, exponential backoff on 5xx/transport errors, no
   retry on 4xx.

Changes:
- tools/skills_hub.py: _coerce_skill_payload carries owner from top-level
  response; inspect() captures owner from detail API; _fetch_owner_handle()
  added with bounded retry/backoff; enrich_owners() batch method with
  safety rails (30 workers, early termination at 50 consecutive failures).
- website/scripts/extract-skills.py: _source_url() reads extra["owner"]
  for ClawHub.
- scripts/build_skills_index.py: batch enrichment step after crawling.
- tests: 35 URL/enrichment tests + 7 retry tests (42 total).

Signed-off-by: dongjiang <dongjiang1989@126.com>
2026-07-31 22:33:11 -07:00
..
computer_use fix(computer_use): resolve gateway session-key namespace in permission-mode lookup 2026-07-29 12:19:37 -07:00
environments feat(terminal): raise Docker sandbox /dev/shm to 1g by default (configurable) 2026-07-31 21:31:51 -07:00
neutts_samples
…
wakewords feat(voice): bundle the trained "hey hermes" model as the out-of-the-box default 2026-07-28 07:58:16 -07:00
__init__.py
…
ansi_strip.py
…
approval.py Revert "remove Vercel AI Gateway and Vercel Sandbox (#33067)" 2026-07-29 19:48:37 -07:00
async_delegation.py fix(state): restore async_delegation.py symbols, keep only journal_mode routing 2026-07-29 18:13:09 -07:00
audio_container.py refactor: extract shared audio container sniffer to tools/audio_container.py 2026-07-28 11:52:44 -07:00
binary_extensions.py
…
blueprints.py chore: remove unused imports and dead locals (ruff F401/F841 sweep) 2026-07-29 11:53:39 -07:00
browser_camofox.py
…
browser_camofox_state.py
…
browser_cdp_tool.py fix(browser): stop stale cdp_url from stalling every startup by 10+ seconds 2026-07-27 14:32:05 -07:00
browser_dialog_tool.py
…
browser_supervisor.py perf(imports): lazy-load heavy SDKs off the cold-start waterfall 2026-07-29 10:54:04 -07:00
browser_tool.py perf: lazy mcp SDK import + tool-discovery mtime cache + browser_tool import diet 2026-07-29 10:02:03 -07:00
budget_config.py
…
checkpoint_manager.py refactor: single build_subprocess_env() factory for all child-process spawns (profile + secret-scrub single owner) 2026-07-29 10:14:11 -07:00
clarify_gateway.py feat(clarify): extend multi-select to gateway text fallback and TUI bridge 2026-07-26 17:46:55 -07:00
clarify_tool.py refactor: migrate hand-rolled error envelopes to shared tool_error() 2026-07-29 10:14:00 -07:00
close_terminal_tool.py chore: remove unused imports and dead locals (ruff F401/F841 sweep) 2026-07-29 11:53:39 -07:00
code_execution_tool.py Revert "remove Vercel AI Gateway and Vercel Sandbox (#33067)" 2026-07-29 19:48:37 -07:00
computer_use_tool.py feat(computer_use): align cua-driver 0.10 permission modes 2026-07-29 12:19:37 -07:00
credential_files.py fix(vision): make desktop image uploads reachable from profile Docker sandboxes (#69575) (#75671) 2026-07-31 17:43:37 -04:00
cronjob_tools.py fix(cron): close GitHub auth-header exemption abuse in prompt scanner 2026-07-31 22:33:00 -07:00
daemon_pool.py
…
debug_helpers.py
…
delegate_tool.py fix(delegation): prevent child HERMES_SESSION_ID leak into parent process env 2026-07-31 22:32:55 -07:00
delegation_live_log.py fix(delegation): redact credentials in live subagent transcripts 2026-07-20 06:50:31 -07:00
desktop_ui.py feat(desktop): agent can focus panes + shared desktop-UI event bridge 2026-07-22 12:13:01 -05:00
discord_tool.py chore: remove unused imports and dead locals (ruff F401/F841 sweep) 2026-07-29 11:53:39 -07:00
env_passthrough.py
…
env_probe.py modernize re-added Vercel integrations: SDK 0.7.2, telemetry off, sibling-site wiring 2026-07-29 19:48:37 -07:00
fal_common.py
…
feishu_doc_tool.py
…
feishu_drive_tool.py
…
file_operations.py fix(file_ops): harden new-file umask chmod for portability 2026-07-31 14:22:38 +05:30
file_state.py
…
file_tools.py modernize re-added Vercel integrations: SDK 0.7.2, telemetry off, sibling-site wiring 2026-07-29 19:48:37 -07:00
flux3_video_tool.py Portal free user vision fix + flux3 polling improvements (#75448) 2026-07-31 10:17:55 -04:00
focus_pane_tool.py feat(desktop): agent can focus panes + shared desktop-UI event bridge 2026-07-22 12:13:01 -05:00
fuzzy_match.py fix(tools): normalize Unicode space family and minus sign in patch fuzzy matching 2026-07-26 20:58:43 -07:00
homeassistant_tool.py refactor: migrate hand-rolled error envelopes to shared tool_error() 2026-07-29 10:14:00 -07:00
hook_output_spill.py fix: route stray HERMES_HOME hardcodes through get_hermes_home() (profile + native-Windows safety) 2026-07-29 09:33:48 -07:00
image_generation_tool.py
…
image_source.py fix(vision): make desktop image uploads reachable from profile Docker sandboxes (#69575) (#75671) 2026-07-31 17:43:37 -04:00
interrupt.py
…
kanban_tools.py feat(kanban): talk to a running worker without a restart 2026-07-30 07:18:08 -05:00
lazy_deps.py fix(deps): pin patched httplib2 for google extra 2026-07-31 22:28:21 -07:00
managed_tool_gateway.py Portal free user vision fix + flux3 polling improvements (#75448) 2026-07-31 10:17:55 -04:00
mcp_dashboard_oauth.py
…
mcp_oauth.py perf: lazy mcp SDK import + tool-discovery mtime cache + browser_tool import diet 2026-07-29 10:02:03 -07:00
mcp_oauth_manager.py fix(mcp): make Figma remote OAuth work via DCR allowlist defaults 2026-07-28 00:53:16 -05:00
mcp_stdio_watchdog.py fix(mcp): use direct parent identity in stdio watchdog 2026-07-18 04:15:13 -07:00
mcp_tool.py feat(mcp): warn on hidden whitespace in MCP config values 2026-07-31 21:21:10 -07:00
memory_tool.py refactor: extract atomic_write_text to utils.py; fix write-failure error handling 2026-07-29 16:49:07 +05:30
microsoft_graph_auth.py
…
microsoft_graph_client.py refactor: single shared Retry-After parser 2026-07-29 10:13:50 -07:00
neutts_synth.py fix(voice): reconcile NeuTTS backbone/codec GPU device strings 2026-07-28 14:07:21 -07:00
open_preview_tool.py feat(desktop): agent can focus panes + shared desktop-UI event bridge 2026-07-22 12:13:01 -05:00
openrouter_client.py
…
osv_check.py
…
patch_parser.py
…
path_security.py refactor: migrate hand-rolled error envelopes to shared tool_error() 2026-07-29 10:14:00 -07:00
process_registry.py fix(process): decode background process output with incremental UTF-8 decoders 2026-07-31 21:21:13 -07:00
project_tools.py
…
react_to_message_tool.py feat(desktop): reactions are opt-in under Settings → Appearance, off by default 2026-07-30 00:08:28 -05:00
read_extract.py
…
read_terminal_tool.py chore: remove unused imports and dead locals (ruff F401/F841 sweep) 2026-07-29 11:53:39 -07:00
registry.py refactor: migrate hand-rolled error envelopes to shared tool_error() 2026-07-29 10:14:00 -07:00
schema_sanitizer.py fix(schema): preserve dependentRequired property names 2026-07-28 14:37:19 -07:00
send_message_tool.py chore: remove unused imports and dead locals (ruff F401/F841 sweep) 2026-07-29 11:53:39 -07:00
session_search_tool.py fix(sessions): keep kanban worker runs out of the session lists 2026-07-31 13:53:04 -05:00
skill_manager_tool.py Merge origin/main into feat/hsp-sync-client 2026-07-29 13:01:36 -07:00
skill_provenance.py
…
skill_usage.py Merge origin/main into feat/hsp-sync-client 2026-07-29 13:01:36 -07:00
skills_ast_audit.py
…
skills_guard.py fix(security): extend secret redaction to GitLab token families 2026-07-31 21:31:10 -07:00
skills_hub.py fix(skills-hub): include owner in ClawHub source URLs and add retry on 429 (#51236) 2026-07-31 22:33:11 -07:00
skills_sync.py fix(skills): avoid redundant bind-mount scans (#72622) 2026-07-28 04:24:50 -05:00
skills_sync_client.py fix(sync): read org state from the org endpoints, not the personal ones (#75237) 2026-07-30 22:31:42 -07:00
skills_tool.py Revert "remove Vercel AI Gateway and Vercel Sandbox (#33067)" 2026-07-29 19:48:37 -07:00
slash_confirm.py
…
terminal_tool.py feat(terminal): raise Docker sandbox /dev/shm to 1g by default (configurable) 2026-07-31 21:31:51 -07:00
thread_context.py
…
threat_patterns.py
…
tirith_security.py fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428) 2026-07-24 11:45:57 -07:00
todo_tool.py fix(compression): preserve synthetic user provenance 2026-07-22 06:56:53 -07:00
tool_backend_helpers.py fix(voice): single scoped resolver — STT/TTS keys fall back to the credential pool 2026-07-28 11:53:09 -07:00
tool_output_limits.py
…
tool_result_storage.py
…
tool_search.py refactor: migrate hand-rolled error envelopes to shared tool_error() 2026-07-29 10:14:00 -07:00
transcription_tools.py fix(stt): kill faster-whisper silence hallucinations at the source 2026-07-29 00:01:33 -07:00
tts_streaming.py fix(tts): route streaming-provider secrets through resolve_provider_secret; bound per-sentence stream bodies at 16 MiB 2026-07-28 22:31:40 -07:00
tts_text_normalize.py fix(tts): unify TTS text preprocessing behind one shared cleaner 2026-07-28 11:55:01 -07:00
tts_tool.py feat(voice): calm ambient "thinking" sound while the agent works in voice chat 2026-07-29 08:24:00 -07:00
url_safety.py fix: scope private URL policy per profile 2026-07-28 14:17:45 -07:00
video_generation_tool.py
…
vision_tools.py perf(imports): lazy-load heavy SDKs off the cold-start waterfall 2026-07-29 10:54:04 -07:00
voice_mode.py fix(voice): full-duplex agent-turn listener — interrupt by voice during generation AND playback 2026-07-29 10:08:53 -07:00
wake_word.py fix(wake): route desktop control and select input devices 2026-07-29 14:04:21 -06:00
web_tools.py chore: remove unused imports and dead locals (ruff F401/F841 sweep) 2026-07-29 11:53:39 -07:00
website_policy.py
…
working_diff.py feat(diff): cross-surface /diff with staged/all/session modes 2026-07-26 18:28:20 -07:00
write_approval.py
…
x_search_tool.py docs(xai): clarify x_search vs xurl routing without schema cross-refs 2026-07-23 21:06:47 -07:00
xai_http.py fix(voice): single scoped resolver — STT/TTS keys fall back to the credential pool 2026-07-28 11:53:09 -07:00
xai_video_tools.py
…
yuanbao_tools.py
…