dsh-plugin-ccp 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.0"
|
dsh_plugin_ccp/tools.py
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DSH Plugin CCP — CCP 协议能力发现层
|
|
3
|
+
|
|
4
|
+
让 DSH Agent 通过 CCP 协议搜索、评估、调用能力锚点。
|
|
5
|
+
|
|
6
|
+
提供三个 DSH 工具:
|
|
7
|
+
- ccp_search: 搜索能力锚点
|
|
8
|
+
- ccp_detail: 获取能力详情 + 生成适配器
|
|
9
|
+
- ccp_telemetry: 回传调用结果(信任向量闭环)
|
|
10
|
+
|
|
11
|
+
版本:v1.0.0
|
|
12
|
+
协议:CCP v1.0.0
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import json
|
|
17
|
+
import urllib.parse
|
|
18
|
+
import urllib.request
|
|
19
|
+
import urllib.error
|
|
20
|
+
from typing import Optional
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _normalize_endpoint(endpoint: str) -> str:
|
|
24
|
+
"""将端点 URL 规范化:非 ASCII 主机名转为 IDNA(punycode)编码。
|
|
25
|
+
|
|
26
|
+
Python urllib 不支持含非 ASCII 字符的 hostname(会抛 latin-1 编码错误),
|
|
27
|
+
需在发起请求前把中文域名转换为 punycode 形式(如 礼字号.中国 -> xn--...)。
|
|
28
|
+
"""
|
|
29
|
+
parts = urllib.parse.urlsplit(endpoint)
|
|
30
|
+
hostname = parts.hostname
|
|
31
|
+
if hostname and any(ord(c) > 127 for c in hostname):
|
|
32
|
+
ascii_host = hostname.encode("idna").decode("ascii")
|
|
33
|
+
if ":" in hostname or (parts.port is not None):
|
|
34
|
+
ascii_host = f"{ascii_host}:{parts.port}"
|
|
35
|
+
netloc = ascii_host
|
|
36
|
+
if parts.username:
|
|
37
|
+
userinfo = parts.username
|
|
38
|
+
if parts.password:
|
|
39
|
+
userinfo += f":{parts.password}"
|
|
40
|
+
netloc = f"{userinfo}@{ascii_host}"
|
|
41
|
+
return urllib.parse.urlunsplit(
|
|
42
|
+
(parts.scheme, netloc, parts.path, parts.query, parts.fragment)
|
|
43
|
+
)
|
|
44
|
+
return endpoint
|
|
45
|
+
|
|
46
|
+
CCP_ENDPOINT = os.environ.get(
|
|
47
|
+
"CCP_ENDPOINT", "https://skillmesh.礼字号.中国/api/ccp/v1"
|
|
48
|
+
)
|
|
49
|
+
CCP_FEDERATED = os.environ.get("CCP_FEDERATED", "false").lower() == "true"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class CCPClient:
|
|
53
|
+
"""CCP API HTTP 客户端"""
|
|
54
|
+
|
|
55
|
+
def __init__(self, endpoint: str = CCP_ENDPOINT):
|
|
56
|
+
self.endpoint = _normalize_endpoint(endpoint).rstrip("/")
|
|
57
|
+
|
|
58
|
+
def _request(self, path: str, method: str = "GET", body: Optional[dict] = None) -> dict:
|
|
59
|
+
url = f"{self.endpoint}{path}"
|
|
60
|
+
data = json.dumps(body).encode("utf-8") if body else None
|
|
61
|
+
req = urllib.request.Request(
|
|
62
|
+
url,
|
|
63
|
+
data=data,
|
|
64
|
+
headers={
|
|
65
|
+
"Content-Type": "application/json",
|
|
66
|
+
"Accept": "application/json",
|
|
67
|
+
"User-Agent": "dsh-plugin-ccp/1.0.0",
|
|
68
|
+
},
|
|
69
|
+
method=method,
|
|
70
|
+
)
|
|
71
|
+
try:
|
|
72
|
+
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
73
|
+
return json.loads(resp.read().decode("utf-8"))
|
|
74
|
+
except urllib.error.HTTPError as e:
|
|
75
|
+
return {"error": {"code": "HTTP_ERROR", "detail": str(e), "status": e.code}}
|
|
76
|
+
except Exception as e:
|
|
77
|
+
return {"error": {"code": "NETWORK_ERROR", "detail": str(e)}}
|
|
78
|
+
|
|
79
|
+
def search(self, q: str, category: Optional[str] = None) -> dict:
|
|
80
|
+
"""搜索能力锚点"""
|
|
81
|
+
params = f"?q={urllib.parse.quote(q)}"
|
|
82
|
+
if category:
|
|
83
|
+
params += f"&category={urllib.parse.quote(category)}"
|
|
84
|
+
if CCP_FEDERATED:
|
|
85
|
+
params += "&federated=true"
|
|
86
|
+
return self._request(f"/search{params}")
|
|
87
|
+
|
|
88
|
+
def detail(self, capability_id: str) -> dict:
|
|
89
|
+
"""获取能力锚点详情"""
|
|
90
|
+
return self._request(f"/capabilities/{urllib.parse.quote(capability_id)}")
|
|
91
|
+
|
|
92
|
+
def adapter(self, capability_id: str, framework: str = "dsh") -> dict:
|
|
93
|
+
"""获取适配器代码(服务端返回 YAML 文本)"""
|
|
94
|
+
url = (
|
|
95
|
+
f"{self.endpoint}/capabilities/{urllib.parse.quote(capability_id)}"
|
|
96
|
+
f"/adapters/{urllib.parse.quote(framework)}"
|
|
97
|
+
)
|
|
98
|
+
req = urllib.request.Request(
|
|
99
|
+
url,
|
|
100
|
+
headers={
|
|
101
|
+
"Accept": "text/yaml,text/plain,*/*",
|
|
102
|
+
"User-Agent": "dsh-plugin-ccp/1.0.0",
|
|
103
|
+
},
|
|
104
|
+
method="GET",
|
|
105
|
+
)
|
|
106
|
+
try:
|
|
107
|
+
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
108
|
+
return {"adapter": resp.read().decode("utf-8"), "framework": framework}
|
|
109
|
+
except urllib.error.HTTPError as e:
|
|
110
|
+
return {"error": {"code": "HTTP_ERROR", "detail": str(e), "status": e.code}}
|
|
111
|
+
except Exception as e:
|
|
112
|
+
return {"error": {"code": "NETWORK_ERROR", "detail": str(e)}}
|
|
113
|
+
|
|
114
|
+
def telemetry(self, capability_id: str, success: bool, latency_ms: int = 0) -> dict:
|
|
115
|
+
"""回传调用结果"""
|
|
116
|
+
return self._request(
|
|
117
|
+
"/telemetry",
|
|
118
|
+
method="POST",
|
|
119
|
+
body={
|
|
120
|
+
"capability_id": capability_id,
|
|
121
|
+
"success": success,
|
|
122
|
+
"latency_ms": latency_ms,
|
|
123
|
+
"agent_id": "dsh-plugin-ccp",
|
|
124
|
+
},
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def list_capabilities(self, category: Optional[str] = None) -> dict:
|
|
128
|
+
"""列出所有能力锚点"""
|
|
129
|
+
params = ""
|
|
130
|
+
if category:
|
|
131
|
+
params = f"?category={urllib.parse.quote(category)}"
|
|
132
|
+
return self._request(f"/capabilities{params}")
|
|
133
|
+
|
|
134
|
+
def node_info(self) -> dict:
|
|
135
|
+
"""获取节点信息"""
|
|
136
|
+
return self._request("/node")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
_client = CCPClient()
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def ccp_search(q: str, category: Optional[str] = None) -> dict:
|
|
143
|
+
"""
|
|
144
|
+
DSH 工具:搜索能力锚点。
|
|
145
|
+
|
|
146
|
+
通过 CCP 协议搜索 AI 能力,返回能力锚点列表(含信任向量)。
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
q: 搜索关键词(中文或英文)
|
|
150
|
+
category: 能力分类过滤(ai/data/media/language/dev),可选
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
包含 results 列表和 count 的字典,每个结果包含 id/name/desc/trust 向量
|
|
154
|
+
"""
|
|
155
|
+
result = _client.search(q, category)
|
|
156
|
+
if "error" in result:
|
|
157
|
+
return {"error": result["error"], "results": [], "count": 0}
|
|
158
|
+
|
|
159
|
+
summary = []
|
|
160
|
+
for cap in result.get("results", []):
|
|
161
|
+
summary.append(
|
|
162
|
+
{
|
|
163
|
+
"id": cap.get("id"),
|
|
164
|
+
"name": cap.get("name"),
|
|
165
|
+
"name_en": cap.get("name_en"),
|
|
166
|
+
"desc": cap.get("desc"),
|
|
167
|
+
"category": cap.get("category"),
|
|
168
|
+
"endpoint_type": cap.get("endpointType"),
|
|
169
|
+
"trust": {
|
|
170
|
+
"source": cap.get("trustSource"),
|
|
171
|
+
"usage_rate": cap.get("trustUsageRate"),
|
|
172
|
+
"success": cap.get("trustSuccess"),
|
|
173
|
+
"risk": cap.get("trustRisk"),
|
|
174
|
+
"time": cap.get("trustTime"),
|
|
175
|
+
},
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
"query": result.get("query", q),
|
|
181
|
+
"count": len(summary),
|
|
182
|
+
"federated": result.get("federated", False),
|
|
183
|
+
"results": summary,
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def ccp_detail(capability_id: str) -> dict:
|
|
188
|
+
"""
|
|
189
|
+
DSH 工具:获取能力锚点详情。
|
|
190
|
+
|
|
191
|
+
获取指定能力的完整信息,包括端点、输入输出规格、信任向量和证据层。
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
capability_id: 能力锚点 ID(如 pdf-extract-text-001)
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
完整的能力锚点对象
|
|
198
|
+
"""
|
|
199
|
+
result = _client.detail(capability_id)
|
|
200
|
+
if "error" in result:
|
|
201
|
+
return {"error": result["error"]}
|
|
202
|
+
return result
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def ccp_telemetry(capability_id: str, success: bool, latency_ms: int = 0) -> dict:
|
|
206
|
+
"""
|
|
207
|
+
DSH 工具:回传调用结果到 CCP 遥测端点。
|
|
208
|
+
|
|
209
|
+
每次 Agent 调用能力后应回传结果,以维护信任向量的准确性。
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
capability_id: 能力锚点 ID
|
|
213
|
+
success: 调用是否成功
|
|
214
|
+
latency_ms: 调用延迟(毫秒)
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
确认信息
|
|
218
|
+
"""
|
|
219
|
+
result = _client.telemetry(capability_id, success, latency_ms)
|
|
220
|
+
if "error" in result:
|
|
221
|
+
return {"error": result["error"], "acknowledged": False}
|
|
222
|
+
return {"acknowledged": True, "capability_id": capability_id}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: dsh-plugin-ccp
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: DSH 插件:CCP 协议能力发现层 — 让 DSH Agent 通过 CCP 协议搜索、评估、调用能力
|
|
5
|
+
Author-email: CCP Community <ccp@skillmesh.礼字号.中国>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://skillmesh.礼字号.中国
|
|
8
|
+
Project-URL: Repository, https://github.com/aidulibrary/skillmesh-index
|
|
9
|
+
Project-URL: CCP RFC, https://github.com/aidulibrary/skillmesh-index/blob/main/docs/rfc-dsh-ccp-discovery.md
|
|
10
|
+
Keywords: dsh,ccp,deepseek-harness,capability,discovery,trust-vector
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: urllib3 >=2.0
|
|
22
|
+
|
|
23
|
+
# dsh-plugin-ccp
|
|
24
|
+
|
|
25
|
+
DSH 插件:CCP 协议能力发现层。
|
|
26
|
+
|
|
27
|
+
## 安装
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
dsh plugin install dsh-plugin-ccp
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 配置
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
dsh config set ccp.endpoint https://skillmesh.礼字号.中国/api/ccp/v1
|
|
37
|
+
dsh config set ccp.federated true
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 提供的工具
|
|
41
|
+
|
|
42
|
+
| 工具 | 功能 |
|
|
43
|
+
| --------------- | ----------------------------- |
|
|
44
|
+
| `ccp_search` | 搜索能力锚点(支持中文/英文) |
|
|
45
|
+
| `ccp_detail` | 获取能力详情 + 信任向量 |
|
|
46
|
+
| `ccp_telemetry` | 回传调用结果(信任向量闭环) |
|
|
47
|
+
|
|
48
|
+
## 使用示例
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
# DSH Agent 中使用 CCP 发现能力
|
|
52
|
+
result = ccp_search("pdf text extraction")
|
|
53
|
+
for cap in result["results"]:
|
|
54
|
+
print(f"{cap['name']} — trust: {cap['trust']['success']:.0%}")
|
|
55
|
+
|
|
56
|
+
# 获取详情
|
|
57
|
+
detail = ccp_detail("pdf-extract-text-001")
|
|
58
|
+
|
|
59
|
+
# 回传调用结果
|
|
60
|
+
ccp_telemetry("pdf-extract-text-001", success=True, latency_ms=120)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 许可
|
|
64
|
+
|
|
65
|
+
MIT
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
dsh_plugin_ccp/__init__.py,sha256=Aj77VL1d5Mdku7sgCgKQmPuYavPpAHuZuJcy6bygQZE,21
|
|
2
|
+
dsh_plugin_ccp/tools.py,sha256=HjhtRvpW6VAKcYCv5sLqLsOTQRilIo67nxehLMnzAEI,7582
|
|
3
|
+
dsh_plugin_ccp-1.0.0.dist-info/METADATA,sha256=Y8dLk6QzC3m9QkZdkL0TV9sTMM5ccBVYUwVS15PCtDY,2066
|
|
4
|
+
dsh_plugin_ccp-1.0.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
5
|
+
dsh_plugin_ccp-1.0.0.dist-info/top_level.txt,sha256=5b0pqzn-AGOGxtt1f3ZOvya_B3aLtQE9AYWozYQhnRM,15
|
|
6
|
+
dsh_plugin_ccp-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dsh_plugin_ccp
|