@@ -259,6 +259,16 @@ def _format_score(score: dict) -> str:
259259 return text
260260
261261
262+ def _is_discarded (job_data : dict ) -> bool :
263+ """Return whether a job is marked discarded via score.discard."""
264+ if not isinstance (job_data , dict ):
265+ return False
266+ score = job_data .get ("score" , {})
267+ if not isinstance (score , dict ):
268+ return False
269+ return bool (score .get ("discard" , False ))
270+
271+
262272def _render_jobs (jobs ) -> Table :
263273 """Make a new table."""
264274 # Create a table to display job details
@@ -279,13 +289,16 @@ def _render_jobs(jobs) -> Table:
279289 # Truncate long descriptions for the table view
280290 if description and len (description ) > 40 :
281291 description = description [:37 ] + "…"
292+ completion_status = str (job_data .get ("completion_status" , "N/A" ))
293+ if _is_discarded (job_data ):
294+ completion_status = f"{ completion_status } (discarded)"
282295 table .add_row (
283296 str (job .get ("id" , "N/A" )),
284297 job .get ("experiment_id" , "N/A" ),
285298 job_data .get ("task_name" , "N/A" ),
286299 job .get ("status" , "N/A" ),
287300 f"{ job .get ('progress' , 0 )} %" ,
288- job_data . get ( " completion_status" , "N/A" ) ,
301+ completion_status ,
289302 description or "" ,
290303 _format_score (job_data .get ("score" , {})),
291304 _compute_duration (job_data ),
@@ -364,6 +377,7 @@ def _render_job(job) -> None:
364377 "End Time" : job_data .get ("end_time" , "N/A" ),
365378 "Duration" : _compute_duration (job_data ) or "N/A" ,
366379 "Completion Status" : job_data .get ("completion_status" , "N/A" ),
380+ "Discarded" : "Yes" if _is_discarded (job_data ) else "No" ,
367381 "Completion Details" : job_data .get ("completion_details" , "N/A" ),
368382 "Error" : job_data .get ("error_msg" , "" ),
369383 "Config" : job_data .get ("_config" , {}),
@@ -413,6 +427,7 @@ def _sort_key(job):
413427 jobs = sorted (jobs , key = _sort_key )
414428
415429 if output_format == "json" :
430+ jobs = [{** job , "discarded" : _is_discarded (job .get ("job_data" , {}))} for job in jobs ]
416431 print (json .dumps (jobs ))
417432 else :
418433 table = _render_jobs (jobs )
@@ -439,7 +454,7 @@ def info_job(job_id: str, experiment_id: str):
439454
440455 if output_format == "json" :
441456 files = _fetch_job_files (experiment_id , job_id )
442- print (json .dumps ({** job , "files" : files }))
457+ print (json .dumps ({** job , "files" : files , "discarded" : _is_discarded ( job . get ( "job_data" , {})) }))
443458 return
444459
445460 console .print (f"[bold success]Job Details for ID { job_id } :[/bold success]" )
@@ -863,6 +878,44 @@ def command_job_logs(
863878 command_job_machine_logs (job_id , follow )
864879
865880
881+ @app .command ("discard" )
882+ def command_job_discard (
883+ job_id : str = typer .Argument (..., help = "Job ID to mark as discarded" ),
884+ undo : bool = typer .Option (False , "--undo" , help = "Unset discard and mark the job as not discarded" ),
885+ ):
886+ """Toggle score.discard on a job."""
887+ current_experiment = require_current_experiment ()
888+ discard_value = not undo
889+ response = api .put (
890+ f"/experiment/{ current_experiment } /jobs/{ job_id } /job_data" ,
891+ json = {"updates" : {"discard" : discard_value }},
892+ )
893+ if response .status_code == 200 :
894+ if cli_state .output_format == "json" :
895+ print (json .dumps ({"job_id" : job_id , "discard" : discard_value }))
896+ return
897+ if discard_value :
898+ console .print (f"[success]✓[/success] Job [bold]{ job_id } [/bold] marked as discarded." )
899+ else :
900+ console .print (f"[success]✓[/success] Job [bold]{ job_id } [/bold] unmarked as discarded." )
901+ return
902+
903+ try :
904+ detail = response .json ().get ("detail" , response .text )
905+ except Exception :
906+ detail = response .text
907+ if cli_state .output_format == "json" :
908+ print (json .dumps ({"error" : "Failed to update discard flag" , "status_code" : response .status_code , "detail" : detail }))
909+ else :
910+ console .print (
911+ f"[error]Error:[/error] Failed to update discard flag for job { job_id } . "
912+ f"Status code: { response .status_code } "
913+ )
914+ if detail :
915+ console .print (f"[error]Detail:[/error] { detail } " )
916+ raise typer .Exit (1 )
917+
918+
866919@app .command ("list" )
867920def command_job_list (
868921 running : bool = typer .Option (
0 commit comments