18 Commits

Author SHA1 Message Date
ouyangbo 012c9c6bed chore: anchor fresh-start history to upstream 2026-09-16 15:06:54 +08:00
Eugeniusz Gilewski fef98ff00f fix(skills): bound streamed ClawHub ZIP downloads (#57571)
ClawHub ZIP downloads buffered the entire response before applying member
limits. Stream the archive into a 25 MiB bounded buffer and enforce actual
received bytes even when Content-Length is absent or incorrect.

Use the existing SSRF-safe client with bounded redirects and recheck URL and
website policy at every hop. Close responses before retry delays, clamp
Retry-After, and stop after the third rate-limited response without attempting
ZIP extraction. Preserve member path validation and raw-file fallback.

Related #29450
Co-authored-by: sprmn <oncuevtv@gmail.com>
Co-authored-by: teknium1 <127238744+teknium1@users.noreply.github.com>
2026-09-12 21:50:30 -07:00
teknium1 e7794124da fix(skills-index): bound ClawHub owner enrichment so the scheduled index build finishes
Every scheduled skills-index.yml run since 2026-07-20 was cancelled at the 15-minute
job timeout, so the live skills-index.json has been frozen at that date and every
`hermes skills search` fell through to live GitHub API calls (~500 inspect requests per
cold search, against a 60/hr unauthenticated budget). The freshness watchdog has been
appending to #66616 four times a day since.

Root cause: enrich_owners() walks every ClawHub skill's detail endpoint (~2s each) to
fetch an owner handle for the "View source" link. The catalog grew from ~50k to 78k
skills, so even at 30 workers that phase alone runs over an hour; nothing bounded it.

- enrich_owners() gains budget_seconds: on expiry it stops and ships the remainder
  without an owner (the link is a nicety; the index is not).
- build_skills_index.py passes an 8-minute budget.
- skills-index.yml build job timeout 15 -> 50 min to cover the measured critical path
  (clawhub walk ~14 min || github taps ~8 min, skills.sh resolve ~6 min, enrichment 8 min).
2026-09-12 07:54:04 -07:00
Teknium 76de6ec5a8 fix: retain ClawHub owner through version and bundle requests 2026-09-07 07:05:59 -07:00
liuhao1024 f986a2b103 fix(skills): pass the ClawHub owner hint as ?owner= so ambiguous slugs resolve
ClawHub's detail endpoint now answers a slug claimed by multiple owners
with 409 AMBIGUOUS_SKILL_SLUG; the bare GET in _skill_detail returned
None for every such slug, so 'skills install clawhub/@owner/slug' (and
the owner/skills/slug URL form) failed at fetch time even though the
requester already knew the owner (#104117).

- _skill_detail forwards expected_owner as the ?owner= query param on
  the detail GET (params already flows through _get_json's **kwargs).
- _parse_identifier also accepts the clawhub/@owner/slug combination:
  the @ surfaces only after the clawhub/ prefix is stripped, so the
  had_at check now re-runs on the stripped form. GitHub-style
  owner/repo/skill paths stay rejected.
2026-09-07 07:05:59 -07:00
Teknium 2dcd97d648 simplify(compat): tools/skills_hub — drop 51 re-exports/aliases, repoint 25 callers + 11 test files 2026-09-03 13:22:48 -07:00
xxxigm a6ddfa5769 test(skills): cover same-name inspect/install provenance mixup
Pin ClawHub to GitHub-style identifiers and keep catalog metadata
from being paired with a foreign same-named bundle.
2026-08-19 01:23:17 +05:30
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
Teknium 39975613b1 test: prune wave 2 + speed fixes — 28,106 → 19,757 test functions, suite wall 315s → 294s
Second, deeper pass over tools/gateway/hermes_cli plus first pass over
the trees wave 1 missed (acp, acp_adapter, skills, computer_use, docker,
dashboard, conformance, monitoring, secret_sources, hermes_state,
providers). Same rubric as wave 1 (AGENTS.md test policy); security,
alternation/caching invariants, issue-number regressions, and E2E kept.

Real test-quality fixes found and rooted out along the way:
- tests/tools/test_command_guards.py made real auxiliary-LLM HTTPS calls
  (DEFAULT_CONFIG smart-approval leaked in) — pinned approval
  mode=manual via autouse fixture: 17.4s → 0.4s.
- test_model_switch_custom_providers.py / test_user_providers_model_switch.py
  silently probed live provider catalogs (~2s/test) — stubbed
  cached_provider_model_ids/provider_model_ids/fetch_api_models.
- test_telegram_noise_filter.py: 15-platform copy-paste matrix over
  shared gateway.run logic → 3 representative platforms (55s → 3.9s).
- test_gateway_shutdown.py: stop()'s 5s interrupt-deadline loop spun on
  MagicMock agents — interrupt.side_effect now clears _running_agents
  (22s → 1.0s).
- test_gateway_inactivity_timeout.py poll-harness timings shrunk 3-5x
  (24s → 1.1s); test_mcp_stability.py backoff/SIGTERM-grace sleeps
  patched (15.4s → 2.5s); test_async_delegation.py negative-drain wait
  5s → 0.5s.
- test_telegram_init_deadline.py: loop-block margin restored to 1.0s
  with rationale comment — the watchdog-dump assertion needs the loop
  blocked well past deadline+grace under parallel load (flaked once in
  the 40-worker verification run at a 0.2s margin).

Verification: full hermetic suite via scripts/run_tests.sh —
2,438 files, 21,718 tests passed, 0 failed, 293.9s wall.
Suite totals vs original baseline: 46,820 → 19,757 test functions
(−57.8%), wall 583.5s → 293.9s (−50%), subprocess CPU 13,564s → 11,623s.
2026-07-29 13:39:40 -07:00
Eugeniusz Gilewski 42626da1ce fix(security): pin DNS resolutions for SSRF-safe fetches
Install connect-time DNS validation for Hermes-owned direct httpx clients so SSRF-sensitive fetch paths dial a vetted IP instead of re-resolving after preflight. This preserves Host/SNI semantics for direct HTTP(S) connections and keeps proxy routing as an explicit trusted egress boundary.

Wire the guarded clients into media cache downloads, vision downloads, Skills Hub direct/raw fetches, and platform attachment fetch paths that already perform SSRF preflight and redirect validation.

Fixes #8033

Co-authored-by: Tom Qiao <zqiao@microsoft.com>
2026-07-23 11:44:43 -07:00
Austin Pickett 2ee69d0579 fix(skills): let ClawHub index build walk past the 12s browse budget (#44500)
The deploy-site skills index crawl was capped at ~3k ClawHub entries
because CATALOG_WALK_BUDGET_SECONDS applied to max_items=0 walks too.
Only enforce the wall-clock budget for bounded browse requests and pass
limit=0 from build_skills_index so CI walks the full catalog.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-11 18:03:11 -04:00
Teknium eee1da45f0 fix(skills): bound ClawHub catalog walk to requested page on cold start (#43395)
Browse renders one page but the cold-cache fallback walked the entire
50k+ ClawHub catalog, then sliced off the first N — pure waste behind the
12s budget band-aid. _load_catalog_index now takes max_items: browse's
empty-query path bounds the walk to its limit and stops early; the offline
index builder still passes limit=0 (unbounded) and walks to exhaustion.
A bounded walk is partial, so it is not written to the shared full-catalog
cache (same poison-guard as the budget-truncated case).
2026-06-10 01:01:53 -07:00
briandevans 105625d650 fix(skills): honour overall_timeout and bound ClawHub catalog walk
parallel_search_sources accepted an overall_timeout but never honoured it.
The ThreadPoolExecutor ran inside a `with ... as pool` block, whose __exit__
calls shutdown(wait=True); even after as_completed() raised TimeoutError on
schedule, leaving the block blocked the caller until every worker finished.
A single slow source (e.g. ClawHub) therefore stalled the entire browse for
minutes. Manage the executor manually and shut it down with
wait=False, cancel_futures=True in a finally, so the timeout actually returns
and not-yet-started work is dropped.

ClawHubSource._load_catalog_index walked up to 750 sequential pages with no
wall-clock bound (each request under its own timeout=30, so nothing errored),
and wrote the result to the index cache unconditionally — so an interrupted or
slow walk poisoned the cache with a partial catalog. Add a
CATALOG_WALK_BUDGET_SECONDS deadline that breaks the walk early, and only write
the cache when the walk reaches a natural stop (cursor exhausted or page cap),
never on a budget-truncated walk.

Adds regression tests covering both bugs (timeout honoured + slow source
flagged; budget abort does not poison cache) plus their happy-path invariants.
2026-06-09 23:22:54 -07:00
Teknium fb9f3a4ef9 fix(skills): pull full ClawHub catalog into the skills index (200 → 20k+) (#33748)
* fix(skills): pull full ClawHub catalog into the skills index

The website was showing 200 ClawHub skills out of 20k+ because
`ClawHubSource.search("")` for empty queries went straight to a single
unpaginated request. ClawHub's API caps any single page at 200 items and
returns a `nextCursor`; we grabbed page 1 and stopped, so the cached
index served from hermes-agent.nousresearch.com had a silent 99%
truncation.

End users never hit clawhub.ai directly (the index is rebuilt twice
daily by .github/workflows/skills-index.yml and served as a static JSON
on the docs site), so the cap-and-cache architecture is correct — it
just wasn't being filled.

Changes:
- `ClawHubSource.search(query="")` now routes through the existing
  `_load_catalog_index()` paginating walker instead of the unpaginated
  listing fallback (non-empty queries still hit the fast catalog search).
- `_load_catalog_index()` max_pages 50 → 250 (50k-skill ceiling; live
  catalog is ~20k as of May 2026, with headroom for growth).
- `build_skills_index.py`: per-source crawl limits split out — ClawHub
  and LobeHub get 100k, others keep their effective caps.
- `EXPECTED_FLOORS["clawhub"]` 50 → 5000 so the next pagination
  regression hard-fails the CI build instead of silently shipping a
  degenerate index.

Test plan:
- New unit test `test_search_empty_query_paginates_full_catalog`
  exercises the cursor-following path with three mocked pages (450
  total items) and asserts all pages are walked.
- Existing 9 ClawHub tests + 127 broader skills_hub tests all pass.
- E2E against live ClawHub API: walker reached 9700+ skills across 49
  pages before this commit landed, paginating well past the previous
  50-page cap.

* fix(skills): raise ClawHub ceilings — live catalog is 50k, not 20k

E2E walk against live ClawHub API hit my initial 250-page cap at 49,698
skills with cursor=yes still pending. The catalog is roughly 2.5x larger
than the docstring estimate.

- max_pages 250 → 750 (150k ceiling, walks terminate on cursor=None
  well before this in practice)
- SOURCE_LIMITS['clawhub'] 100k → 200k
- EXPECTED_FLOORS['clawhub'] 5000 → 20000
2026-05-28 01:42:19 -07:00
heathley 0c5c4d1b8d fix(skills-hub): cover remaining SSRF fetch paths after #10029 2026-05-09 17:52:12 -07:00
teknium1 8ccd14a0d4 fix: improve clawhub skill search matching 2026-03-14 23:15:04 -07:00
teknium1 df9020dfa3 fix: harden clawhub skill search exact matches 2026-03-14 22:31:09 -07:00
BP602 6789084ec0 Fix ClawHub Skills Hub adapter for updated API 2026-03-02 16:11:49 +01:00