2929
3030
3131def download_skills_tool (
32- skill_space_id : str , download_path : str , skill_names : Optional [list [str ]] = None
32+ download_path : str , skill_names : Optional [list [str ]] = None
3333) -> str :
3434 """
35- Download skills from a skill space to local path.
35+ Download skills from skill spaces to local path.
3636
3737 Args:
38- skill_space_id: The skill space ID to download from
3938 download_path: Local path to save downloaded skills
4039 skill_names: Optional list of specific skill names to download. If None, download all skills.
4140
@@ -45,6 +44,16 @@ def download_skills_tool(
4544 try :
4645 from veadk .auth .veauth .utils import get_credential_from_vefaas_iam
4746
47+ # Get skill space IDs from environment variable
48+ skill_space_ids = os .getenv ("SKILL_SPACE_ID" , "" )
49+ skill_space_ids_list = [
50+ x .strip () for x in skill_space_ids .split ("," ) if x .strip ()
51+ ]
52+ if not skill_space_ids_list :
53+ return "Error: SKILL_SPACE_ID environment variable is not set"
54+
55+ logger .info (f"Downloading skills from skill spaces: { skill_space_ids_list } " )
56+
4857 # Get credentials
4958 access_key = os .getenv ("VOLCENGINE_ACCESS_KEY" )
5059 secret_key = os .getenv ("VOLCENGINE_SECRET_KEY" )
@@ -61,58 +70,6 @@ def download_skills_tool(
6170 region = os .getenv ("AGENTKIT_TOOL_REGION" , "cn-beijing" )
6271 host = os .getenv ("AGENTKIT_SKILL_HOST" , "open.volcengineapi.com" )
6372
64- # Call ListSkillsBySpaceId API
65- request_body = {
66- "SkillSpaceId" : skill_space_id ,
67- "InnerTags" : {"source" : "sandbox" },
68- }
69- logger .info (f"ListSkillsBySpaceId request body: { request_body } " )
70-
71- response = ve_request (
72- request_body = request_body ,
73- action = "ListSkillsBySpaceId" ,
74- ak = access_key ,
75- sk = secret_key ,
76- service = service ,
77- version = "2025-10-30" ,
78- region = region ,
79- host = host ,
80- header = {"X-Security-Token" : session_token },
81- )
82-
83- if isinstance (response , str ):
84- response = json .loads (response )
85-
86- list_skills_result = response .get ("Result" )
87- items = list_skills_result .get ("Items" , [])
88-
89- if not items :
90- return f"No skills found in skill space: { skill_space_id } "
91-
92- # Filter skills if skill_names is provided
93- skills_to_download = []
94- for item in items :
95- if not isinstance (item , dict ):
96- continue
97-
98- skill_name = item .get ("Name" )
99- tos_bucket = item .get ("BucketName" )
100- tos_path = item .get ("TosPath" )
101-
102- if not skill_name or not tos_bucket or not tos_path :
103- continue
104-
105- # If skill_names specified, only include matching skills
106- if skill_names is None or skill_name in skill_names :
107- skills_to_download .append (
108- {"name" : skill_name , "bucket" : tos_bucket , "path" : tos_path }
109- )
110-
111- if not skills_to_download :
112- if skill_names :
113- return f"No matching skills found for names: { skill_names } "
114- return f"No valid skills found in skill space: { skill_space_id } "
115-
11673 # Ensure download path exists
11774 download_dir = Path (download_path )
11875 download_dir .mkdir (parents = True , exist_ok = True )
@@ -125,58 +82,122 @@ def download_skills_tool(
12582 region = region ,
12683 )
12784
128- # Download each skill
129- downloaded_skills = []
130- for skill in skills_to_download :
131- skill_name = skill ["name" ]
132- tos_bucket = skill ["bucket" ]
133- tos_path = skill ["path" ]
134-
135- logger .info (
136- f"Downloading skill '{ skill_name } ' from tos://{ tos_bucket } /{ tos_path } "
137- )
138-
139- # Download zip file
140- zip_path = download_dir / f"{ skill_name } .zip"
141- success = tos_client .download (
142- bucket_name = tos_bucket ,
143- object_key = tos_path ,
144- save_path = str (zip_path ),
145- )
146-
147- if not success :
148- logger .warning (f"Failed to download skill '{ skill_name } '" )
149- continue
85+ all_downloaded_skills = []
15086
151- # Extract zip file
152- skill_extract_dir = download_dir / skill_name
87+ # Iterate through each skill space
88+ for skill_space_id in skill_space_ids_list :
15389 try :
154- # Remove existing directory if exists
155- if skill_extract_dir .exists ():
156- import shutil
157-
158- shutil .rmtree (skill_extract_dir )
159-
160- with zipfile .ZipFile (zip_path , "r" ) as z :
161- z .extractall (path = str (download_dir ))
162-
163- logger .info (
164- f"Successfully extracted skill '{ skill_name } ' to { skill_extract_dir } "
90+ # Call ListSkillsBySpaceId API
91+ request_body = {
92+ "SkillSpaceId" : skill_space_id ,
93+ "InnerTags" : {"source" : "sandbox" },
94+ }
95+ logger .info (f"ListSkillsBySpaceId request body: { request_body } " )
96+
97+ response = ve_request (
98+ request_body = request_body ,
99+ action = "ListSkillsBySpaceId" ,
100+ ak = access_key ,
101+ sk = secret_key ,
102+ service = service ,
103+ version = "2025-10-30" ,
104+ region = region ,
105+ host = host ,
106+ header = {"X-Security-Token" : session_token },
165107 )
166- downloaded_skills .append (skill_name )
167108
168- except zipfile .BadZipFile :
169- logger .error (f"Downloaded file for '{ skill_name } ' is not a valid zip" )
109+ if isinstance (response , str ):
110+ response = json .loads (response )
111+
112+ list_skills_result = response .get ("Result" )
113+ items = list_skills_result .get ("Items" , [])
114+
115+ if not items :
116+ logger .warning (f"No skills found in skill space: { skill_space_id } " )
117+ continue
118+
119+ # Filter skills if skill_names is provided
120+ skills_to_download = []
121+ for item in items :
122+ if not isinstance (item , dict ):
123+ continue
124+
125+ skill_name = item .get ("Name" )
126+ tos_bucket = item .get ("BucketName" )
127+ tos_path = item .get ("TosPath" )
128+
129+ if not skill_name or not tos_bucket or not tos_path :
130+ continue
131+
132+ # If skill_names specified, only include matching skills
133+ if skill_names is None or skill_name in skill_names :
134+ skills_to_download .append (
135+ {"name" : skill_name , "bucket" : tos_bucket , "path" : tos_path }
136+ )
137+
138+ if not skills_to_download :
139+ logger .warning (
140+ f"No matching skills found in skill space: { skill_space_id } "
141+ )
142+ continue
143+
144+ # Download each skill
145+ for skill in skills_to_download :
146+ skill_name = skill ["name" ]
147+ tos_bucket = skill ["bucket" ]
148+ tos_path = skill ["path" ]
149+
150+ logger .info (
151+ f"Downloading skill '{ skill_name } ' from tos://{ tos_bucket } /{ tos_path } "
152+ )
153+
154+ # Download zip file
155+ zip_path = download_dir / f"{ skill_name } .zip"
156+ success = tos_client .download (
157+ bucket_name = tos_bucket ,
158+ object_key = tos_path ,
159+ save_path = str (zip_path ),
160+ )
161+
162+ if not success :
163+ logger .warning (f"Failed to download skill '{ skill_name } '" )
164+ continue
165+
166+ # Extract zip file
167+ skill_extract_dir = download_dir / skill_name
168+ try :
169+ # Remove existing directory if exists
170+ if skill_extract_dir .exists ():
171+ import shutil
172+
173+ shutil .rmtree (skill_extract_dir )
174+
175+ with zipfile .ZipFile (zip_path , "r" ) as z :
176+ z .extractall (path = str (download_dir ))
177+
178+ logger .info (
179+ f"Successfully extracted skill '{ skill_name } ' to { skill_extract_dir } "
180+ )
181+ all_downloaded_skills .append (skill_name )
182+
183+ except zipfile .BadZipFile :
184+ logger .error (
185+ f"Downloaded file for '{ skill_name } ' is not a valid zip"
186+ )
187+ except Exception as e :
188+ logger .error (f"Failed to extract skill '{ skill_name } ': { e } " )
189+ finally :
190+ # Delete zip file
191+ if zip_path .exists ():
192+ zip_path .unlink ()
193+ logger .debug (f"Deleted zip file: { zip_path } " )
194+
170195 except Exception as e :
171- logger .error (f"Failed to extract skill '{ skill_name } ': { e } " )
172- finally :
173- # Delete zip file
174- if zip_path .exists ():
175- zip_path .unlink ()
176- logger .debug (f"Deleted zip file: { zip_path } " )
177-
178- if downloaded_skills :
179- return f"Successfully downloaded { len (downloaded_skills )} skill(s): { ', ' .join (downloaded_skills )} to { download_path } "
196+ logger .error (f"Failed to process skill space { skill_space_id } : { e } " )
197+ continue
198+
199+ if all_downloaded_skills :
200+ return f"Successfully downloaded { len (all_downloaded_skills )} skill(s): { ', ' .join (all_downloaded_skills )} to { download_path } "
180201 else :
181202 return "Failed to download any skills"
182203
0 commit comments