Skip to content

Commit 7550919

Browse files
authored
feat(skills): support minio object store for vestack (#546)
* feat(skills): 为vestack环境添加 minio 文件上传下载支持 添加对vestack环境的支持,包括: 1. 通过GenTempTosObjectUrl/GenTempTosObjectDownloadUrl API获取临时URL 2. 使用requests库实现文件上传下载 3. 使用环境变量AGENTKIT_TOOL_SCHEME配置请求协议 * refactor(skills): 提取vestack技能下载逻辑到独立函数并更新环境变量 将vestack环境下的技能下载逻辑提取到独立函数`_download_skill_via_vestack`中,提高代码复用性 同时将环境变量`AGENTKIT_TOOL_SCHEME`统一更新为`AGENTKIT_TOP_SCHEME` * chore: 简化日志错误信息的格式
1 parent 5fa550c commit 7550919

File tree

5 files changed

+315
-54
lines changed

5 files changed

+315
-54
lines changed

docs/docs/tools/builtin.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ VeADK 集成了以下火山引擎工具:
187187
- `AGENTKIT_TOOL_HOST`:用于调用火山引擎AgentKit Tools的EndPoint
188188
- `AGENTKIT_TOOL_SERVICE_CODE`:用于调用AgentKit Tools的ServiceCode
189189
- `AGENTKIT_TOOL_SCHEME`:用于切换调用 AgentKit Tools 的协议,允许 `http`/`https`,默认 `https`
190+
- `AGENTKIT_TOP_SCHEME`:用于切换调用 AgentKit TOP 的协议,允许 `http`/`https`,默认 `https`
190191

191192
环境变量列表:
192193

veadk/skills/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ def load_skills_from_cloud(skill_space_ids: str) -> list[Skill]:
174174
"InnerTags": {"source": "sandbox"},
175175
}
176176
logger.debug(f"ListSkillsBySpaceId request body: {request_body}")
177+
scheme = os.getenv("AGENTKIT_TOP_SCHEME", "https").lower()
177178

178179
response = ve_request(
179180
request_body=request_body,
@@ -185,6 +186,7 @@ def load_skills_from_cloud(skill_space_ids: str) -> list[Skill]:
185186
region=region,
186187
host=host,
187188
header={"X-Security-Token": session_token},
189+
scheme=scheme,
188190
)
189191

190192
if isinstance(response, str):

veadk/tools/skills_tools/download_skills_tool.py

Lines changed: 102 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,86 @@
2828
logger = get_logger(__name__)
2929

3030

31+
def _download_skill_via_vestack(
32+
tos_path: str,
33+
skill_name: str,
34+
access_key: str,
35+
secret_key: str,
36+
session_token: str,
37+
service: str,
38+
region: str,
39+
host: str,
40+
scheme: str,
41+
zip_path: Path,
42+
) -> bool:
43+
import json
44+
import requests
45+
from veadk.utils.volcengine_sign import ve_request
46+
47+
try:
48+
path_parts = tos_path.split("/")
49+
if len(path_parts) >= 3:
50+
skill_id = path_parts[1]
51+
skill_version = path_parts[2]
52+
else:
53+
logger.error(f"Invalid TosPath format for skill '{skill_name}': {tos_path}")
54+
return False
55+
except Exception as e:
56+
logger.error(f"Failed to parse TosPath for skill '{skill_name}': {e}")
57+
return False
58+
59+
# Call GenTempTosObjectDownloadUrl API
60+
temp_url_request_body = {
61+
"SkillId": skill_id,
62+
"SkillVersion": skill_version,
63+
}
64+
65+
temp_url_res = ve_request(
66+
request_body=temp_url_request_body,
67+
action="GenTempTosObjectDownloadUrl",
68+
ak=access_key,
69+
sk=secret_key,
70+
service=service,
71+
version="2025-10-30",
72+
region=region,
73+
host=host,
74+
header={"X-Security-Token": session_token},
75+
scheme=scheme,
76+
)
77+
78+
if isinstance(temp_url_res, str):
79+
temp_url_res = json.loads(temp_url_res)
80+
81+
if (
82+
"ResponseMetadata" in temp_url_res
83+
and "Error" in temp_url_res["ResponseMetadata"]
84+
):
85+
error_details = temp_url_res["ResponseMetadata"]["Error"]
86+
logger.error(
87+
f"Failed to get temporary download URL for '{skill_name}': {error_details}"
88+
)
89+
return False
90+
else:
91+
signed_url = temp_url_res.get("Result", {}).get("SignedUrl")
92+
if not signed_url:
93+
logger.error(
94+
f"Failed to get SignedUrl from GenTempTosObjectDownloadUrl response: {temp_url_res}"
95+
)
96+
return False
97+
else:
98+
try:
99+
response = requests.get(signed_url)
100+
response.raise_for_status()
101+
with open(zip_path, "wb") as f:
102+
f.write(response.content)
103+
return True
104+
except Exception as e:
105+
logger.warning(
106+
f"Failed to download skill '{skill_name}' from minio: {e}"
107+
)
108+
return False
109+
110+
31111
def download_skills_tool(
32112
download_path: str, skill_names: Optional[list[str]] = None
33113
) -> str:
@@ -92,6 +172,7 @@ def download_skills_tool(
92172

93173
all_downloaded_skills = []
94174

175+
scheme = os.getenv("AGENTKIT_TOP_SCHEME", "https").lower()
95176
# Iterate through each skill space
96177
for skill_space_id in skill_space_ids_list:
97178
try:
@@ -112,6 +193,7 @@ def download_skills_tool(
112193
region=region,
113194
host=host,
114195
header={"X-Security-Token": session_token},
196+
scheme=scheme,
115197
)
116198

117199
if isinstance(response, str):
@@ -161,11 +243,26 @@ def download_skills_tool(
161243

162244
# Download zip file
163245
zip_path = download_dir / f"{skill_name}.zip"
164-
success = tos_client.download(
165-
bucket_name=tos_bucket,
166-
object_key=tos_path,
167-
save_path=str(zip_path),
168-
)
246+
247+
if cloud_provider == "vestack":
248+
success = _download_skill_via_vestack(
249+
tos_path=tos_path,
250+
skill_name=skill_name,
251+
access_key=access_key,
252+
secret_key=secret_key,
253+
session_token=session_token,
254+
service=service,
255+
region=region,
256+
host=host,
257+
scheme=scheme,
258+
zip_path=zip_path,
259+
)
260+
else:
261+
success = tos_client.download(
262+
bucket_name=tos_bucket,
263+
object_key=tos_path,
264+
save_path=str(zip_path),
265+
)
169266

170267
if not success:
171268
logger.warning(f"Failed to download skill '{skill_name}'")

veadk/tools/skills_tools/register_skills_tool.py

Lines changed: 89 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -111,46 +111,99 @@ def register_skills_tool(
111111
secret_key = cred.secret_access_key
112112
session_token = cred.session_token
113113

114-
res = ve_request(
115-
request_body={},
116-
action="GetCallerIdentity",
117-
ak=access_key,
118-
sk=secret_key,
119-
service="sts",
120-
version="2018-01-01",
121-
region=region,
122-
host="sts.volcengineapi.com"
123-
if cloud_provider != "byteplus"
124-
else "open.byteplusapi.com",
125-
header={"X-Security-Token": session_token},
126-
)
127-
try:
128-
account_id = res["Result"]["AccountId"]
129-
except KeyError as e:
130-
logger.error(
131-
f"Error occurred while getting account id: {e}, response is {res}"
114+
account_id = ""
115+
if cloud_provider != "vestack":
116+
res = ve_request(
117+
request_body={},
118+
action="GetCallerIdentity",
119+
ak=access_key,
120+
sk=secret_key,
121+
service="sts",
122+
version="2018-01-01",
123+
region=region,
124+
host="sts.volcengineapi.com"
125+
if cloud_provider != "byteplus"
126+
else "open.byteplusapi.com",
127+
header={"X-Security-Token": session_token},
132128
)
133-
return f"Error: Failed to get account id when registering skill '{skill_name}'."
129+
try:
130+
account_id = res["Result"]["AccountId"]
131+
except KeyError as e:
132+
logger.error(
133+
f"Error occurred while getting account id: {e}, response is {res}"
134+
)
135+
return f"Error: Failed to get account id when registering skill '{skill_name}'."
134136

135137
tos_bucket = f"agentkit-platform-{region}-{account_id}-skill"
138+
scheme = os.getenv("AGENTKIT_TOP_SCHEME", "https").lower()
139+
if cloud_provider == "vestack":
140+
import requests
141+
142+
# Call GenTempTosObjectUrl API
143+
temp_url_request_body = {
144+
"SkillName": skill_name,
145+
}
146+
147+
temp_url_res = ve_request(
148+
request_body=temp_url_request_body,
149+
action="GenTempTosObjectUrl",
150+
ak=access_key,
151+
sk=secret_key,
152+
service=agentkit_tool_service,
153+
version="2025-10-30",
154+
region=region,
155+
host=agentkit_skill_host,
156+
header={"X-Security-Token": session_token},
157+
scheme=scheme,
158+
)
136159

137-
tos_client = VeTOS(
138-
ak=access_key,
139-
sk=secret_key,
140-
session_token=session_token,
141-
bucket_name=tos_bucket,
142-
region=region,
143-
)
160+
if isinstance(temp_url_res, str):
161+
temp_url_res = json.loads(temp_url_res)
162+
163+
if (
164+
"ResponseMetadata" in temp_url_res
165+
and "Error" in temp_url_res["ResponseMetadata"]
166+
):
167+
error_details = temp_url_res["ResponseMetadata"]["Error"]
168+
logger.error(
169+
f"Failed to get temporary upload URL for '{skill_name}': {error_details}"
170+
)
171+
return f"Failed to get temporary upload URL for '{skill_name}': {error_details}"
172+
173+
signed_url = temp_url_res.get("Result", {}).get("SignedUrl")
174+
tos_url = temp_url_res.get("Result", {}).get("TosUrl")
175+
176+
if not signed_url or not tos_url:
177+
logger.error(
178+
f"Failed to get SignedUrl or TosUrl from GenTempTosObjectUrl response: {temp_url_res}"
179+
)
180+
return f"Failed to get temporary upload URL for '{skill_name}'."
181+
182+
try:
183+
with open(zip_file_path, "rb") as f:
184+
response = requests.put(signed_url, data=f)
185+
response.raise_for_status()
186+
except Exception as e:
187+
logger.error(f"Failed to upload skill '{skill_name}' to minio: {e}")
188+
return f"Failed to upload skill '{skill_name}' to minio: {e}"
189+
else:
190+
tos_client = VeTOS(
191+
ak=access_key,
192+
sk=secret_key,
193+
session_token=session_token,
194+
bucket_name=tos_bucket,
195+
region=region,
196+
)
144197

145-
object_key = (
146-
f"uploads/{datetime.now().strftime('%Y%m%d_%H%M%S')}/{skill_name}.zip"
147-
)
148-
tos_client.upload_file(
149-
file_path=zip_file_path, bucket_name=tos_bucket, object_key=object_key
150-
)
151-
tos_url = tos_client.build_tos_url(
152-
bucket_name=tos_bucket, object_key=object_key
153-
)
198+
object_key = (
199+
f"uploads/{datetime.now().strftime('%Y%m%d_%H%M%S')}/{skill_name}.zip"
200+
)
201+
tos_client.upload_file(
202+
file_path=zip_file_path, bucket_name=tos_bucket, object_key=object_key
203+
)
204+
tos_url = tos_client.build_tos_url(
205+
bucket_name=tos_bucket, object_key=object_key
206+
)
154207

155208
skill_space_ids = os.getenv("SKILL_SPACE_ID", "")
156209
skill_space_ids_list = [
@@ -173,6 +226,7 @@ def register_skills_tool(
173226
region=region,
174227
host=agentkit_skill_host,
175228
header={"X-Security-Token": session_token},
229+
scheme=scheme,
176230
)
177231

178232
if isinstance(response, str):

0 commit comments

Comments
 (0)