mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-05 02:31:47 +00:00
fix: skills-sh install fails for deeply nested repo structures (#2980)
* fix(run_agent): ensure _fire_first_delta() is called for tool generation events Added calls to _fire_first_delta() in the AIAgent class to improve the handling of tool generation events, ensuring timely notifications during the processing of function calls and tool usage. * fix(run_agent): improve timeout handling for chat completions Enhanced the timeout configuration for chat completions in the AIAgent class by introducing customizable connection, read, and write timeouts using environment variables. This ensures more robust handling of API requests during streaming operations. * fix(run_agent): reduce default stream read timeout for chat completions Updated the default stream read timeout from 120 seconds to 60 seconds in the AIAgent class, enhancing the timeout configuration for chat completions. This change aims to improve responsiveness during streaming operations. * fix(run_agent): enhance streaming error handling and retry logic Improved the error handling and retry mechanism for streaming requests in the AIAgent class. Introduced a configurable maximum number of stream retries and refined the handling of transient network errors, allowing for retries with fresh connections. Non-transient errors now trigger a fallback to non-streaming only when appropriate, ensuring better resilience during API interactions. * fix: skills-sh install fails for deeply nested repo structures Skills in repos with deep directory nesting (e.g. cli-tool/components/skills/development/senior-backend/) could not be installed because the candidate path generation and shallow root-dir scan never reached them. Added GitHubSource._find_skill_in_repo_tree() which uses the GitHub Trees API to recursively search the entire repo tree in a single API call. This is used as a final fallback in SkillsShSource._discover_identifier() when the standard candidate paths and shallow scan both fail. Fixes installation of skills from repos like davila7/claude-code-templates where skills are nested 4+ levels deep. Reported by user Samuraixheart.
This commit is contained in:
parent
c6f4515f73
commit
5dbe2d9d73
3 changed files with 298 additions and 22 deletions
|
|
@ -434,6 +434,56 @@ class GitHubSource(SkillSource):
|
|||
|
||||
return files
|
||||
|
||||
def _find_skill_in_repo_tree(self, repo: str, skill_name: str) -> Optional[str]:
|
||||
"""Use the GitHub Trees API to find a skill directory anywhere in the repo.
|
||||
|
||||
Returns the full identifier (``repo/path/to/skill``) or ``None``.
|
||||
This is a single API call regardless of repo depth, so it efficiently
|
||||
handles deeply nested directory structures like
|
||||
``cli-tool/components/skills/development/<skill>/SKILL.md``.
|
||||
"""
|
||||
# Get default branch
|
||||
try:
|
||||
resp = httpx.get(
|
||||
f"https://api.github.com/repos/{repo}",
|
||||
headers=self.auth.get_headers(),
|
||||
timeout=15,
|
||||
follow_redirects=True,
|
||||
)
|
||||
if resp.status_code != 200:
|
||||
return None
|
||||
default_branch = resp.json().get("default_branch", "main")
|
||||
except (httpx.HTTPError, json.JSONDecodeError):
|
||||
return None
|
||||
|
||||
# Get recursive tree (single API call for the entire repo)
|
||||
try:
|
||||
resp = httpx.get(
|
||||
f"https://api.github.com/repos/{repo}/git/trees/{default_branch}",
|
||||
params={"recursive": "1"},
|
||||
headers=self.auth.get_headers(),
|
||||
timeout=30,
|
||||
follow_redirects=True,
|
||||
)
|
||||
if resp.status_code != 200:
|
||||
return None
|
||||
tree_data = resp.json()
|
||||
except (httpx.HTTPError, json.JSONDecodeError):
|
||||
return None
|
||||
|
||||
# Look for SKILL.md files inside directories named <skill_name>
|
||||
skill_md_suffix = f"/{skill_name}/SKILL.md"
|
||||
for entry in tree_data.get("tree", []):
|
||||
if entry.get("type") != "blob":
|
||||
continue
|
||||
path = entry.get("path", "")
|
||||
if path.endswith(skill_md_suffix) or path == f"{skill_name}/SKILL.md":
|
||||
# Strip /SKILL.md to get the skill directory path
|
||||
skill_dir = path[: -len("/SKILL.md")]
|
||||
return f"{repo}/{skill_dir}"
|
||||
|
||||
return None
|
||||
|
||||
def _fetch_file_content(self, repo: str, path: str) -> Optional[str]:
|
||||
"""Fetch a single file's content from GitHub."""
|
||||
url = f"https://api.github.com/repos/{repo}/contents/{path}"
|
||||
|
|
@ -1014,6 +1064,14 @@ class SkillsShSource(SkillSource):
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
# Final fallback: use the GitHub Trees API to find the skill anywhere
|
||||
# in the repo tree. This handles deeply nested structures like
|
||||
# cli-tool/components/skills/development/<skill>/ that the shallow
|
||||
# scan above can't reach.
|
||||
tree_result = self.github._find_skill_in_repo_tree(repo, skill_token)
|
||||
if tree_result:
|
||||
return tree_result
|
||||
|
||||
return None
|
||||
|
||||
def _finalize_inspect_meta(self, meta: SkillMeta, canonical: str, detail: Optional[dict]) -> SkillMeta:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue