Skip to content

Commit 3ebb673

Browse files
committed
FEAT: 添加skills_hub 模块
1 parent 73655ab commit 3ebb673

32 files changed

Lines changed: 4247 additions & 28 deletions

docs/mkdocs/en/skill.md

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2143,17 +2143,56 @@ The **Dynamic Tool Selection** mechanism has been fully implemented and verified
21432143
- ❌ All tools need to be available simultaneously
21442144
- ❌ Token cost is not a primary concern
21452145

2146-
## References and Examples
2147-
2148-
- Background:
2149-
- Blog:
2150-
https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills
2151-
- Open repository: https://github.com/anthropics/skills
2152-
- This repository:
2153-
- Interactive demo: [examples/skills/run_agent.py](../../../examples/skills/run_agent.py)
2154-
- Dynamic tool selection full example: [examples/skills_with_dynamic_tools/run_agent.py](../../../examples/skills_with_dynamic_tools/run_agent.py)
2155-
- Example structure guide: [examples/skills/README.md](../../../examples/skills/README.md)
2156-
- Example skills:
2157-
- [examples/skills/skills/python-math/SKILL.md](../../../examples/skills/skills/python-math/SKILL.md)
2158-
- [examples/skills/skills/file_tools/SKILL.md](../../../examples/skills/skills/file_tools/SKILL.md)
2159-
- [examples/skills/skills/user_file_ops/SKILL.md](../../../examples/skills/skills/user_file_ops/SKILL.md)
2146+
## Skill Hub - Discovering and Fetching Skills from Remote Sources
2147+
2148+
**Skill Hub** (`trpc_agent_sdk.skills.hub`) is a set of adapters (`SkillSource`) for discovering and fetching skills from remote sources. It provides three capabilities: searching for available skills from a source (GitHub, ClawHub, skills.sh, and others), inspecting metadata for a specific skill, and downloading the complete file contents for that skill. Users can also implement the `SkillSource` interface to integrate their own skill source.
2149+
2150+
### `SkillSource` Contract
2151+
2152+
Every adapter implements the same four-method interface:
2153+
2154+
```python
2155+
from trpc_agent_sdk.skills.hub import SkillSource, SkillMeta, SkillBundle
2156+
2157+
class SkillSource(ABC):
2158+
def source_id(self) -> str: ...
2159+
def search(self, query: str, limit: int = 10) -> list[SkillMeta]: ...
2160+
def inspect(self, identifier: str) -> SkillMeta | None: ...
2161+
def fetch(self, identifier: str) -> SkillBundle | None: ...
2162+
```
2163+
2164+
- `SkillMeta` - lightweight search/inspect result (`name`, `description`, `source`, `identifier`, plus optional `repo`/`path`/`tags`/`extra`)
2165+
- `SkillBundle` - the downloaded skill (`name`, `files: dict[str, str | bytes]`, `source`, `identifier`, `metadata`)
2166+
2167+
`fetch()` only returns an in-memory `SkillBundle`. Writing it to disk (including overwrite policy, atomic writes, and concurrency safety) is the **caller's** responsibility, because different harnesses have different installation semantics. For this purpose, the SDK also exports three path validation functions:
2168+
2169+
```python
2170+
from trpc_agent_sdk.skills.hub import validate_skill_name, validate_category_name, validate_bundle_rel_path
2171+
```
2172+
2173+
### Built-in Adapters
2174+
2175+
| Adapter | Source | Identifier format |
2176+
| --- | --- | --- |
2177+
| `GitHubSource` | GitHub repos, via the Contents / Git Trees API | `"owner/repo/path/to/skill-dir"` |
2178+
| `WellKnownSkillSource` | Any domain exposing `/.well-known/skills/index.json` | `well-known:{base_url}/{skill_name}` or a raw HTTPS URL |
2179+
| `HermesIndexSource` | A centralized, pre-crawled skills catalog | Same identifiers as the underlying `GitHubSource` entries |
2180+
| `SkillsShSource` | [skills.sh](https://skills.sh) | `skills-sh/{owner}/{repo}/{skill_path}` |
2181+
| `ClawHubSource` | [ClawHub](https://clawhub.ai) | slug, e.g. `"notion"` |
2182+
| `ClaudeMarketplaceSource` | Claude Code marketplace repos (`.claude-plugin/marketplace.json`) | Resolves to a `GitHubSource` identifier |
2183+
| `LobeHubSource` | LobeHub agent marketplace (converted to synthetic `SKILL.md`) | `lobehub/{agent_id}` |
2184+
2185+
### Minimal Usage
2186+
2187+
```python
2188+
from trpc_agent_sdk.skills.hub import GitHubAuth, GitHubSource
2189+
2190+
source = GitHubSource(GitHubAuth()) # no authentication is required for public repositories
2191+
meta = source.inspect("anthropics/skills/skills/skill-creator")
2192+
bundle = source.fetch("anthropics/skills/skills/skill-creator")
2193+
# bundle.files: {"SKILL.md": "...", "scripts/...": "...", ...}
2194+
```
2195+
2196+
### Full Example
2197+
2198+
See the complete Skill Hub usage example: [examples/skills_hub/run_agent.py](../../../examples/skills_hub/run_agent.py)

docs/mkdocs/zh/skill.md

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,17 +2141,56 @@ Tools:
21412141
- ❌ 所有工具都需要同时可用
21422142
- ❌ Token 成本不是主要考虑因素
21432143

2144-
## 参考和示例
2145-
2146-
- 背景:
2147-
- 博客:
2148-
https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills
2149-
- 开放仓库:https://github.com/anthropics/skills
2150-
- 本仓库:
2151-
- 交互式演示:[examples/skills/run_agent.py](../../../examples/skills/run_agent.py)
2152-
- 动态工具选择完整示例:[examples/skills_with_dynamic_tools/run_agent.py](../../../examples/skills_with_dynamic_tools/run_agent.py)
2153-
- 示例结构说明:[examples/skills/README.md](../../../examples/skills/README.md)
2154-
- 示例技能:
2155-
- [examples/skills/skills/python-math/SKILL.md](../../../examples/skills/skills/python-math/SKILL.md)
2156-
- [examples/skills/skills/file_tools/SKILL.md](../../../examples/skills/skills/file_tools/SKILL.md)
2157-
- [examples/skills/skills/user_file_ops/SKILL.md](../../../examples/skills/skills/user_file_ops/SKILL.md)
2144+
## Skill Hub —— 从远程来源发现并获取 Skill
2145+
2146+
**Skill Hub**`trpc_agent_sdk.skills.hub`)是一组用于从远程来源发现和获取 skill 的适配器(`SkillSource`)。它能做三件事:搜索某个来源(GitHub、ClawHub、skills.sh 等)上有哪些 skill、查看某个 skill 的元信息、下载它的完整文件内容。用户也可以实现SkillSource 接口来对接自己的skill source.
2147+
2148+
### `SkillSource` 契约
2149+
2150+
每个适配器都实现同样的四方法接口:
2151+
2152+
```python
2153+
from trpc_agent_sdk.skills.hub import SkillSource, SkillMeta, SkillBundle
2154+
2155+
class SkillSource(ABC):
2156+
def source_id(self) -> str: ...
2157+
def search(self, query: str, limit: int = 10) -> list[SkillMeta]: ...
2158+
def inspect(self, identifier: str) -> SkillMeta | None: ...
2159+
def fetch(self, identifier: str) -> SkillBundle | None: ...
2160+
```
2161+
2162+
- `SkillMeta` —— 轻量的 search/inspect 结果(`name``description``source``identifier`,以及可选的 `repo`/`path`/`tags`/`extra`
2163+
- `SkillBundle` —— 下载到的 skill(`name``files: dict[str, str | bytes]``source``identifier``metadata`
2164+
2165+
`fetch()` 只会返回内存中的 `SkillBundle`。把它写到磁盘(包括覆盖策略、原子写入、并发安全)是**调用方**自己的职责,因为不同 harness 对安装语义的要求各不相同。为此 SDK 也导出了三个路径校验函数:
2166+
2167+
```python
2168+
from trpc_agent_sdk.skills.hub import validate_skill_name, validate_category_name, validate_bundle_rel_path
2169+
```
2170+
2171+
### 内置适配器
2172+
2173+
| 适配器 | 来源 | 标识符格式 |
2174+
| --- | --- | --- |
2175+
| `GitHubSource` | GitHub 仓库,如 https://github.com/anthropics/skills | `owner/repo/path/to/skill-dir`,例如 `"anthropics/skills/skills/skill-creator"` |
2176+
| `WellKnownSkillSource` | 暴露 `/.well-known/skills/index.json` 的站点,如 https://www.mintlify.com/docs/.well-known/skills/index.json | HTTPS URL,例如 `"https://example.com/.well-known/skills/plan"` |
2177+
| `HermesIndexSource` | [Hermes Skills Index](https://hermes-agent.nousresearch.com/docs/api/skills-index.json) | `owner/repo/path`,例如 `"anthropics/skills/skills/skill-creator"` |
2178+
| `SkillsShSource` | [skills.sh](https://skills.sh) | `skills-sh/{owner}/{repo}/{skill_path}`,例如 `"skills-sh/owner/repo/plan"` |
2179+
| `ClawHubSource` | [ClawHub](https://clawhub.ai) | `{slug}`,例如 `notion` |
2180+
| `ClaudeMarketplaceSource` |`.claude-plugin/marketplace.json` 的 GitHub marketplace 仓库,如 https://github.com/anthropics/skills | `owner/repo/path`,例如 `"anthropics/skills/plugins/docx"` |
2181+
| `LobeHubSource` | [LobeHub agent marketplace](https://chat-agents.lobehub.com/index.json) | `lobehub/{agent_id}`,例如 `lobehub/writer-bot` |
2182+
2183+
### 最小用法
2184+
2185+
```python
2186+
from trpc_agent_sdk.skills.hub import GitHubAuth, GitHubSource
2187+
2188+
source = GitHubSource(GitHubAuth()) # 拉取公开仓库无需认证
2189+
meta = source.inspect("anthropics/skills/skills/skill-creator")
2190+
bundle = source.fetch("anthropics/skills/skills/skill-creator")
2191+
# bundle.files: {"SKILL.md": "...", "scripts/...": "...", ...}
2192+
```
2193+
2194+
### 完整示例
2195+
2196+
查看完整的 Skill Hub 使用示例:[examples/skills_hub/run_agent.py](../../../examples/skills_hub/run_agent.py)

examples/skills_hub/.env

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Set TRPC_AGENT_API_KEY、TRPC_AGENT_BASE_URL、TRPC_AGENT_MODEL_NAME
2+
TRPC_AGENT_API_KEY=your-api-key
3+
TRPC_AGENT_BASE_URL=your-base-url
4+
TRPC_AGENT_MODEL_NAME=your-model-name
5+
6+
# Optional: a GitHub personal access token (raises the unauthenticated
7+
# 60 req/hr GitHub API limit to 5,000/hr). Not required to run this demo.
8+
# GITHUB_TOKEN=

examples/skills_hub/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
data

examples/skills_hub/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Skill Hub 示例
2+
3+
本示例演示 `trpc_agent_sdk.skills.hub`(Skill Hub):在启动 `LlmAgent` 之前,通过 `GitHubSource` 从 GitHub 上按需拉取一个技能(Anthropic 官方的 `skill-creator`),写入本地技能目录,再像本地技能一样交给 `SkillToolSet` 使用。
4+
5+
## 什么是 Skill Hub
6+
7+
Skill Hub(`trpc_agent_sdk.skills.hub`)把"从各种来源发现并获取 skill"统一到同一个接口后面。每个来源都是一个 `SkillSource` 适配器,对外提供一致的 `search` / `inspect` / `fetch` 三种能力:
8+
9+
| 适配器 | 来源 |
10+
| --- | --- |
11+
| `GitHubSource` | GitHub 仓库目录(本示例使用) |
12+
| `WellKnownSkillSource` | 站点 `.well-known/skills` |
13+
| `HermesIndexSource` | Hermes 内置 skill index |
14+
| `SkillsShSource` | skills.sh |
15+
| `ClawHubSource` | ClawHub registry |
16+
| `ClaudeMarketplaceSource` | Claude Skills Marketplace |
17+
| `LobeHubSource` | LobeHub |
18+
19+
`SkillSource.fetch()` 只返回内存中的 `SkillBundle``name` + `files` + `metadata`)。**把它写到磁盘、决定是否覆盖已有版本,都是调用方自己的策略**。SDK 本身不内置"安装"逻辑,因为不同 harness(本示例、trpc-hermes 的 `SkillSpec`/`preinstall_skills_to_dir`,或你自己的服务)对覆盖策略、原子写入、并发安全的要求都不一样。本示例里最小化的这部分逻辑在 `agent/hub.py``install_skill_from_github()`
20+
21+
## 关键特性
22+
23+
- `GitHubSource(GitHubAuth(token))` 无需认证即可拉取公开仓库(60 次/小时限额,足够本示例使用;设置 `GITHUB_TOKEN` 可提升到 5000 次/小时)
24+
- 用 SDK 导出的 `validate_skill_name` / `validate_bundle_rel_path` 校验 hub 返回的路径,避免恶意 `SkillBundle` 写出到目标目录之外
25+
- 已安装的技能会被跳过,重复运行示例不会重复下载
26+
- 拉取完成后,技能通过标准的 `create_default_skill_repository` + `SkillToolSet` 链路对 agent 可见,和本地技能没有区别
27+
28+
## Agent 层级结构说明
29+
30+
- 根节点:`LlmAgent``skill_hub_demo_agent`),挂载 `SkillToolSet``skill_repository`
31+
- 无子 Agent;单智能体通过 `skill_load` / `skill_list_docs` 等技能工具完成任务
32+
33+
## 关键代码解释
34+
35+
- `agent/hub.py`
36+
- `install_skill_from_github()`:若目标目录已存在则跳过;否则用 `GitHubSource.fetch(identifier)` 拉取 `SkillBundle`,校验并写出每个文件
37+
- `create_skill_tool_set()`:用安装好的目录构造 `create_default_skill_repository` + `SkillToolSet`
38+
- `agent/agent.py``create_agent(skills_dir)` 先调用 `install_skill_from_github`,再把返回的 `skill_repository` / `skill_tool_set` 绑定到 `LlmAgent`
39+
- `run_agent.py`:清空 `data/` 目录(保证每次都重新走一遍 Skill Hub 拉取流程),创建 agent,跑一轮 `skill_load` + 总结的对话,并打印实际下载到的文件列表
40+
41+
## 环境与运行
42+
43+
- Python 3.10+;仓库根目录执行 `pip install -e .`
44+
- 配置 `TRPC_AGENT_API_KEY``TRPC_AGENT_BASE_URL``TRPC_AGENT_MODEL_NAME`(可用 `.env`
45+
- 可选:`GITHUB_TOKEN`,用于提高 GitHub API 限额(本示例只读取公开仓库,不设置也能跑)
46+
47+
```bash
48+
cd examples/skills_hub
49+
python3 run_agent.py
50+
```
51+
52+
运行后会在 `data/skills/skill-creator/` 下看到从 GitHub 拉取的真实文件(`SKILL.md``scripts/``references/` 等)。
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
2+
#
3+
# Copyright (C) 2026 Tencent. All rights reserved.
4+
#
5+
# tRPC-Agent-Python is licensed under Apache-2.0.

examples/skills_hub/agent/agent.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
2+
#
3+
# Copyright (C) 2026 Tencent. All rights reserved.
4+
#
5+
# tRPC-Agent-Python is licensed under Apache-2.0.
6+
""" Agent that demonstrates fetching a skill from the Skill Hub before running. """
7+
8+
from pathlib import Path
9+
10+
from trpc_agent_sdk.agents import LlmAgent
11+
from trpc_agent_sdk.models import LLMModel
12+
from trpc_agent_sdk.models import OpenAIModel
13+
14+
from .config import get_model_config
15+
from .hub import GITHUB_SKILL_IDENTIFIER
16+
from .hub import GITHUB_SKILL_NAME
17+
from .hub import create_skill_tool_set
18+
from .hub import install_skill_from_github
19+
from .prompts import INSTRUCTION
20+
21+
22+
def _create_model() -> LLMModel:
23+
""" Create a model"""
24+
api_key, url, model_name = get_model_config()
25+
model = OpenAIModel(model_name=model_name, api_key=api_key, base_url=url)
26+
return model
27+
28+
29+
def create_agent(skills_dir: Path) -> LlmAgent:
30+
"""Fetch a skill from GitHub via the Skill Hub, then build an agent that can use it.
31+
32+
Args:
33+
skills_dir: Local directory to install fetched skills into. Populated
34+
with `skills_dir/skill-creator/` before the agent is constructed.
35+
"""
36+
install_skill_from_github(
37+
skills_dir=skills_dir,
38+
skill_name=GITHUB_SKILL_NAME,
39+
identifier=GITHUB_SKILL_IDENTIFIER,
40+
)
41+
skill_tool_set, skill_repository = create_skill_tool_set(skills_dir)
42+
43+
return LlmAgent(
44+
name="skill_hub_demo_agent",
45+
description="An assistant that fetches skills on demand from the Skill Hub.",
46+
model=_create_model(),
47+
instruction=INSTRUCTION,
48+
tools=[skill_tool_set],
49+
skill_repository=skill_repository,
50+
)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
2+
#
3+
# Copyright (C) 2026 Tencent. All rights reserved.
4+
#
5+
# tRPC-Agent-Python is licensed under Apache-2.0.
6+
""" Agent config module"""
7+
8+
import os
9+
10+
11+
def get_model_config() -> tuple[str, str, str]:
12+
"""Get model config from environment variables"""
13+
api_key = os.getenv('TRPC_AGENT_API_KEY', '')
14+
url = os.getenv('TRPC_AGENT_BASE_URL', '')
15+
model_name = os.getenv('TRPC_AGENT_MODEL_NAME', '')
16+
if not api_key or not url or not model_name:
17+
raise ValueError('''TRPC_AGENT_API_KEY, TRPC_AGENT_BASE_URL,
18+
and TRPC_AGENT_MODEL_NAME must be set in environment variables''')
19+
return api_key, url, model_name

examples/skills_hub/agent/hub.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
2+
#
3+
# Copyright (C) 2026 Tencent. All rights reserved.
4+
#
5+
# tRPC-Agent-Python is licensed under Apache-2.0.
6+
"""Skill Hub glue: fetch a skill from GitHub and install it into a local
7+
skills directory before the agent starts.
8+
9+
`trpc_agent_sdk.skills.hub.SkillSource.fetch()` only returns a `SkillBundle`
10+
in memory -- writing it to disk (and deciding on overwrite/skip semantics) is
11+
intentionally left to the caller, since that policy is harness-specific. This
12+
module shows the minimal version of that glue; a real harness (e.g.
13+
trpc-hermes's `SkillSpec` + `preinstall_skills_to_dir`) typically adds atomic
14+
staging and richer error handling on top of the same `SkillSource` adapters.
15+
"""
16+
17+
from __future__ import annotations
18+
19+
import os
20+
from pathlib import Path
21+
22+
from trpc_agent_sdk.code_executors import create_local_workspace_runtime
23+
from trpc_agent_sdk.skills import BaseSkillRepository
24+
from trpc_agent_sdk.skills import SkillToolSet
25+
from trpc_agent_sdk.skills import create_default_skill_repository
26+
from trpc_agent_sdk.skills.hub import GitHubAuth
27+
from trpc_agent_sdk.skills.hub import GitHubSource
28+
from trpc_agent_sdk.skills.hub import validate_bundle_rel_path
29+
from trpc_agent_sdk.skills.hub import validate_skill_name
30+
31+
# `skill-creator` is Anthropic's own skill for building and iterating on
32+
# skills -- a fitting "meta" skill to fetch through the Skill Hub for a demo.
33+
GITHUB_SKILL_IDENTIFIER = "anthropics/skills/skills/skill-creator"
34+
GITHUB_SKILL_NAME = "skill-creator"
35+
36+
37+
def install_skill_from_github(*, skills_dir: Path, skill_name: str, identifier: str) -> None:
38+
"""Fetch `identifier` via `GitHubSource` and write it into `skills_dir/skill_name/`.
39+
40+
Skips the fetch entirely if the skill directory already exists, so
41+
re-running the demo doesn't re-download the skill every time.
42+
"""
43+
safe_name = validate_skill_name(skill_name)
44+
target_dir = skills_dir / safe_name
45+
if target_dir.exists():
46+
return
47+
48+
# Unauthenticated requests are capped at 60 req/hr, which is plenty for
49+
# this demo. Set GITHUB_TOKEN to raise that limit for repeated runs.
50+
source = GitHubSource(GitHubAuth(os.getenv("GITHUB_TOKEN") or None))
51+
bundle = source.fetch(identifier)
52+
if bundle is None:
53+
raise RuntimeError(
54+
f"Could not fetch skill {identifier!r} from GitHub via the Skill Hub "
55+
"(hit the rate limit? set GITHUB_TOKEN in .env)."
56+
)
57+
58+
skills_dir.mkdir(parents=True, exist_ok=True)
59+
target_dir.mkdir(parents=True)
60+
for rel_path, content in bundle.files.items():
61+
safe_rel_path = validate_bundle_rel_path(rel_path)
62+
dest = target_dir / safe_rel_path
63+
dest.parent.mkdir(parents=True, exist_ok=True)
64+
if isinstance(content, bytes):
65+
dest.write_bytes(content)
66+
else:
67+
dest.write_text(content, encoding="utf-8")
68+
69+
70+
def create_skill_tool_set(skills_dir: Path) -> tuple[SkillToolSet, BaseSkillRepository]:
71+
"""Build a `SkillToolSet` backed by whatever has been installed into `skills_dir`."""
72+
workspace_runtime = create_local_workspace_runtime()
73+
repository = create_default_skill_repository(str(skills_dir), workspace_runtime=workspace_runtime)
74+
skill_toolset = SkillToolSet(repository=repository)
75+
return skill_toolset, repository
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
2+
#
3+
# Copyright (C) 2026 Tencent. All rights reserved.
4+
#
5+
# tRPC-Agent-Python is licensed under Apache-2.0.
6+
""" prompts for agent"""
7+
8+
INSTRUCTION = """
9+
Be a concise, helpful assistant that can use Agent Skills.
10+
11+
A skill named "skill-creator" was just fetched on demand from GitHub via the
12+
Skill Hub (`trpc_agent_sdk.skills.hub`) and installed locally before you were
13+
started, so it is available like any other local skill.
14+
15+
When asked about a skill, call skill_load to load its documentation, then
16+
skill_list_docs to see what documentation and files are available. Summarize
17+
what you find concisely; do not run any of the skill's scripts unless
18+
explicitly asked to.
19+
"""

0 commit comments

Comments
 (0)