3434)
3535from transformerlab .routers .auth import get_user_and_team
3636from transformerlab .shared .models .user_model import get_async_session
37- from lab .task_template import TaskTemplate
3837from transformerlab .schemas .task import (
3938 ExportTaskToTeamGalleryRequest ,
4039 ImportTaskFromGalleryRequest ,
@@ -245,20 +244,15 @@ async def task_list_files(experimentId: str, task_id: str) -> TaskFilesResponse:
245244 "/{task_id}/file/{file_path:path}" ,
246245 summary = "Serve a file from a task's local workspace directory for preview" ,
247246)
248- async def task_get_file (task_id : str , file_path : str ):
247+ async def task_get_file (experimentId : str , task_id : str , file_path : str ):
249248 """
250249 Serve a file from the per-task workspace directory (used for upload-from-directory tasks).
251250
252251 This mirrors the behavior of the jobs get_job_file endpoint but is scoped to
253- workspace/ task/{task_id} . It is primarily intended for lightweight previews in
254- the UI and supports both text and binary content.
252+ the task's experiment-scoped directory . It is primarily intended for lightweight
253+ previews in the UI and supports both text and binary content.
255254 """
256- workspace_dir = await get_workspace_dir ()
257- if not workspace_dir :
258- raise HTTPException (status_code = 500 , detail = "Workspace directory is not configured" )
259-
260- # Files for upload-from-directory tasks are materialized under workspace/task/{task_id}
261- task_dir = storage .join (workspace_dir , "task" , str (task_id ))
255+ task_dir = await task_service .get_task_dir (task_id , experiment_id = experimentId )
262256 safe_rel = posixpath .normpath (file_path ).lstrip ("/" )
263257 if safe_rel .startswith (".." ) or "/.." in safe_rel :
264258 raise HTTPException (status_code = 400 , detail = "Invalid file path" )
@@ -365,11 +359,7 @@ async def task_update_file(experimentId: str, task_id: str, file_path: str, requ
365359 if not task :
366360 raise HTTPException (status_code = 404 , detail = "Task not found" )
367361
368- workspace_dir = await get_workspace_dir ()
369- if not workspace_dir :
370- raise HTTPException (status_code = 500 , detail = "Workspace directory is not configured" )
371-
372- task_dir = storage .join (workspace_dir , "task" , str (task_id ))
362+ task_dir = await task_service .get_task_dir (task_id , experiment_id = experimentId )
373363 safe_rel = posixpath .normpath (file_path ).lstrip ("/" )
374364 if safe_rel .startswith (".." ) or "/.." in safe_rel :
375365 raise HTTPException (status_code = 400 , detail = "Invalid file path" )
@@ -401,11 +391,7 @@ async def task_delete_file(experimentId: str, task_id: str, file_path: str):
401391 if not task :
402392 raise HTTPException (status_code = 404 , detail = "Task not found" )
403393
404- workspace_dir = await get_workspace_dir ()
405- if not workspace_dir :
406- raise HTTPException (status_code = 500 , detail = "Workspace directory is not configured" )
407-
408- task_dir = storage .join (workspace_dir , "task" , str (task_id ))
394+ task_dir = await task_service .get_task_dir (task_id , experiment_id = experimentId )
409395 safe_rel = posixpath .normpath (file_path ).lstrip ("/" )
410396 if safe_rel .startswith (".." ) or "/.." in safe_rel :
411397 raise HTTPException (status_code = 400 , detail = "Invalid file path" )
@@ -436,11 +422,7 @@ async def task_upload_file(
436422 if not task :
437423 raise HTTPException (status_code = 404 , detail = "Task not found" )
438424
439- workspace_dir = await get_workspace_dir ()
440- if not workspace_dir :
441- raise HTTPException (status_code = 500 , detail = "Workspace directory is not configured" )
442-
443- task_dir = storage .join (workspace_dir , "task" , str (task_id ))
425+ task_dir = await task_service .get_task_dir (task_id , experiment_id = experimentId )
444426 await storage .makedirs (task_dir , exist_ok = True )
445427
446428 saved_files : list [str ] = []
@@ -1151,21 +1133,17 @@ async def import_task_from_gallery(
11511133 # Invalidate cached task lists for this experiment (best-effort).
11521134 await cache .invalidate (f"tasks:{ experimentId } " )
11531135
1154- # Store task.yaml in the task directory for GitHub-sourced interactive tasks
1136+ # Store task.yaml in the task directory for GitHub-sourced interactive tasks.
1137+ # Use task_service.write_task_yaml so the file lands in the experiment-scoped
1138+ # path that task_list_files reads from (workspace/experiments/{exp_id}/tasks/{id}).
11551139 if github_repo_url and source_yaml_data :
1156- task_template = TaskTemplate (secure_filename (str (task_id )))
1157- task_dir_path = await task_template .get_dir ()
1158- await storage .makedirs (task_dir_path , exist_ok = True )
1159- yaml_path = storage .join (task_dir_path , "task.yaml" )
1160- async with await storage .open (yaml_path , "w" , encoding = "utf-8" ) as f :
1161- await f .write (task_yaml_content )
1140+ await task_service .write_task_yaml (task_id , task_yaml_content , experiment_id = experimentId )
11621141
11631142 # Copy local_task_dir files into the task directory (inside a subdirectory
11641143 # matching the source directory name, mirroring what github_repo_dir does
11651144 # at clone time) and mark file_mounts so the runner copies them at launch.
11661145 if local_task_dir and os .path .isdir (local_task_dir ):
1167- task_template = TaskTemplate (secure_filename (str (task_id )))
1168- task_dir_path = await task_template .get_dir ()
1146+ task_dir_path = await task_service .get_task_dir (task_id , experiment_id = experimentId )
11691147 await storage .makedirs (task_dir_path , exist_ok = True )
11701148 dest_subdir = storage .join (task_dir_path , os .path .basename (local_task_dir .rstrip ("/" )))
11711149 await storage .copy_dir (local_task_dir , dest_subdir )
@@ -1267,13 +1245,8 @@ async def import_task_from_gallery(
12671245 # Create the task with all fields stored directly (flat structure)
12681246 task_id = await task_service .add_task (task_data )
12691247
1270- # Store task.yaml in task directory
1271- task = TaskTemplate (secure_filename (str (task_id )))
1272- task_dir = await task .get_dir ()
1273- await storage .makedirs (task_dir , exist_ok = True )
1274- yaml_path = storage .join (task_dir , "task.yaml" )
1275- async with await storage .open (yaml_path , "w" , encoding = "utf-8" ) as f :
1276- await f .write (task_yaml_content )
1248+ # Store task.yaml in the experiment-scoped task directory
1249+ await task_service .write_task_yaml (task_id , task_yaml_content , experiment_id = experimentId )
12771250
12781251 # Invalidate cached task lists for this experiment (best-effort).
12791252 await cache .invalidate (f"tasks:{ experimentId } " )
@@ -1550,11 +1523,10 @@ async def import_task_from_team_gallery(
15501523
15511524 # Create task + copy full directory into the task workspace dir
15521525 task_id = await task_service .add_task (task_data )
1553- task = TaskTemplate (secure_filename (str (task_id )))
1554- task_dir = await task .get_dir ()
1526+ task_dir = await task_service .get_task_dir (task_id , experiment_id = experimentId )
15551527 await storage .makedirs (task_dir , exist_ok = True )
15561528
1557- # Copy the entire directory contents (task.yaml + attachments) into workspace/ task/{task_id}
1529+ # Copy the entire directory contents (task.yaml + attachments) into the experiment-scoped task dir
15581530 try :
15591531 await storage .copy_dir (str (local_task_dir ), task_dir )
15601532 except Exception as e :
@@ -1630,10 +1602,7 @@ async def import_task_from_team_gallery(
16301602 _clear_interactive_launch_provider (task_data )
16311603 task_id = await task_service .add_task (task_data )
16321604
1633- # Write a task.yaml into the task directory so the editor works
1634- task = TaskTemplate (secure_filename (str (task_id )))
1635- task_dir = await task .get_dir ()
1636- await storage .makedirs (task_dir , exist_ok = True )
1605+ # Write a task.yaml into the experiment-scoped task directory so the editor works
16371606 yaml_obj = {
16381607 "name" : task_data ["name" ],
16391608 "setup" : task_data .get ("setup" ),
@@ -1651,9 +1620,9 @@ async def import_task_from_team_gallery(
16511620 # Remove empty values so YAML stays tidy
16521621 yaml_obj ["resources" ] = {k : v for k , v in (yaml_obj .get ("resources" ) or {}).items () if v is not None }
16531622 yaml_obj = {k : v for k , v in yaml_obj .items () if v not in (None , {}, [])}
1654- yaml_path = storage . join ( task_dir , "task.yaml" )
1655- async with await storage . open ( yaml_path , "w" , encoding = "utf-8" ) as f :
1656- await f . write ( yaml . safe_dump ( yaml_obj , sort_keys = False ) )
1623+ await task_service . write_task_yaml (
1624+ task_id , yaml . safe_dump ( yaml_obj , sort_keys = False ), experiment_id = experimentId
1625+ )
16571626
16581627 await cache .invalidate (f"tasks:{ experimentId } " )
16591628 return {
@@ -1730,13 +1699,8 @@ async def import_task_from_team_gallery(
17301699 # Create the task with all fields stored directly (flat structure)
17311700 task_id = await task_service .add_task (task_data )
17321701
1733- # Store task.yaml in task directory
1734- task = TaskTemplate (secure_filename (str (task_id )))
1735- task_dir = await task .get_dir ()
1736- await storage .makedirs (task_dir , exist_ok = True )
1737- yaml_path = storage .join (task_dir , "task.yaml" )
1738- async with await storage .open (yaml_path , "w" , encoding = "utf-8" ) as f :
1739- await f .write (task_yaml_content )
1702+ # Store task.yaml in the experiment-scoped task directory
1703+ await task_service .write_task_yaml (task_id , task_yaml_content , experiment_id = experimentId )
17401704
17411705 # Invalidate cached task lists for this experiment (best-effort).
17421706 await cache .invalidate (f"tasks:{ experimentId } " )
@@ -1827,9 +1791,8 @@ async def export_task_to_team_gallery(
18271791 short_id = secure_filename (str (request .task_id ))[:12 ]
18281792 dest_dir = storage .join (export_root , f"{ safe_title } -{ short_id } " )
18291793
1830- # Copy from the task's workspace dir (workspace/task/{task_id})
1831- src_task = TaskTemplate (secure_filename (str (request .task_id )))
1832- src_dir = await src_task .get_dir ()
1794+ # Copy from the task's experiment-scoped workspace directory
1795+ src_dir = await task_service .get_task_dir (request .task_id , experiment_id = experimentId )
18331796 if await storage .exists (src_dir ):
18341797 # Ensure destination is clean
18351798 if await storage .exists (dest_dir ):
0 commit comments