@@ -84,6 +84,8 @@ iterate_forecast <- function(agent_info,
8484 agent_info $ project_info $ combo_variables <- " ID"
8585 }
8686
87+ agent_info $ max_iter <- max_iter
88+
8789 # run exploratory data analysis
8890 # check if eda data already exists
8991 eda_exists <- tryCatch(
@@ -160,23 +162,60 @@ iterate_forecast <- function(agent_info,
160162 } else {
161163 cli :: cli_alert_info(" Max iterations already met. Skipping global model optimization." )
162164 }
165+ } else if (length(combo_list ) > 1 & ! run_global_models ) {
166+ message(" [agent] Global models disabled. Skipping global model optimization." )
167+ } else {
168+ message(" [agent] Only one time series found. Skipping global model optimization." )
169+ }
170+
171+ # get local combo list
172+ best_run_tbl <- load_best_agent_run(agent_info = agent_info )
173+
174+ if (nrow(best_run_tbl ) > 0 ) {
175+ # check if max_iter OR run_complete columns exist (for backward compatibility)
176+ if (! " run_complete" %in% colnames(best_run_tbl ) | ! " max_iterations" %in% colnames(best_run_tbl )) {
177+ best_run_tbl <- best_run_tbl %> %
178+ dplyr :: mutate(
179+ run_complete = FALSE ,
180+ max_iterations = 0
181+ )
182+ }
183+
184+ # set run_complete to FALSE for global models that did not meet mape goal,
185+ # which will allow local models to run if needed
186+ best_run_tbl <- best_run_tbl %> %
187+ dplyr :: mutate(
188+ run_complete = ifelse(model_type == " global" & weighted_mape > weighted_mape_goal , FALSE , run_complete )
189+ )
190+
191+ # add in missing combos that have not been run yet (no agent best run file)
192+ missing_combos <- setdiff(combo_list , best_run_tbl $ combo )
193+
194+ if (length(missing_combos ) > 0 ) {
195+ missing_tbl <- tibble :: tibble(
196+ combo = missing_combos ,
197+ weighted_mape = Inf ,
198+ run_complete = FALSE ,
199+ max_iterations = 0
200+ )
201+
202+ best_run_tbl <- best_run_tbl %> %
203+ dplyr :: bind_rows(missing_tbl )
204+ }
163205
164- # filter out which time series met the mape goal after global models
165- local_combo_list <- load_best_agent_run( agent_info = agent_info ) %> %
206+ # filter combos that need local model optimization
207+ local_combo_list <- best_run_tbl %> %
166208 dplyr :: filter(weighted_mape > weighted_mape_goal ) %> %
209+ dplyr :: filter(run_complete == FALSE | max_iterations < max_iter ) %> %
167210 dplyr :: pull(combo ) %> %
168211 unique()
169- } else if (length(combo_list ) > 1 & ! run_global_models ) {
170- message(" [agent] Global models disabled. Skipping global model optimization." )
171- local_combo_list <- combo_list
172212 } else {
173- message(" [agent] Only one time series found. Skipping global model optimization." )
174213 local_combo_list <- combo_list
175214 }
176215
177216 # optimize local models
178217 if (length(local_combo_list ) == 0 ) {
179- message(" [agent] All time series met the MAPE goal after global models . Skipping local model optimization." )
218+ message(" [agent] All time series already finished running . Skipping local model optimization." )
180219 } else if (! run_local_models ) {
181220 message(" [agent] Local models disabled. Skipping local model optimization." )
182221 } else {
@@ -752,6 +791,10 @@ save_best_agent_run <- function(agent_info) {
752791 stop(" Error in save_best_agent_run(). No best run found for agent." , call. = FALSE )
753792 }
754793
794+ # remove unnecessary columns
795+ final_run_tbl <- final_run_tbl %> %
796+ dplyr :: select(- dplyr :: any_of(c(" run_complete" , " max_iterations" )))
797+
755798 # save the best run for the agent
756799 write_data(
757800 x = final_run_tbl ,
@@ -822,7 +865,14 @@ fcst_agent_workflow <- function(agent_info,
822865
823866 # check if the LLM aborted the run
824867 if (" abort" %in% names(results $ reason_inputs ) && results $ reason_inputs $ abort == " TRUE" ) {
825- return (list (ctx = ctx , `next` = " stop" ))
868+ # check if any iterations have been completed
869+ if (ctx $ iter > 0 ) {
870+ # proceed to finalize run step if there is existing run_info from previous iterations
871+ return (list (ctx = ctx , `next` = " finalize_run" ))
872+ } else {
873+ # skip finalize run step since run was aborted with no existing run_info
874+ return (list (ctx = ctx , `next` = " stop" ))
875+ }
826876 } else {
827877 return (list (ctx = ctx , `next` = " submit_fcst_run" ))
828878 }
@@ -903,14 +953,25 @@ fcst_agent_workflow <- function(agent_info,
903953
904954 # determine next node based on conditions
905955 if (wmape_goal_reached || max_runs_reached ) {
906- next_node <- " stop "
956+ next_node <- " finalize_run "
907957 } else {
908958 next_node <- " start"
909959 }
910960
911961 return (list (ctx = ctx , `next` = next_node ))
912962 }
913963 ),
964+ finalize_run = list (
965+ fn = " finalize_run" ,
966+ `next` = " stop" ,
967+ retry_mode = " plain" ,
968+ max_retry = 3 ,
969+ args = list (
970+ agent_info = agent_info ,
971+ run_info = " {results$submit_fcst_run}" ,
972+ combo = combo
973+ )
974+ ),
914975 stop = list (fn = NULL )
915976 )
916977
@@ -1632,7 +1693,9 @@ log_best_run <- function(agent_info,
16321693 best_run_name = run_info $ run_name ,
16331694 model_type = ifelse(combo == " all" , " global" , " local" ),
16341695 combo = combo_name ,
1635- weighted_mape = wmape
1696+ weighted_mape = wmape ,
1697+ max_iterations = 0 ,
1698+ run_complete = FALSE
16361699 ) %> %
16371700 dplyr :: left_join(
16381701 log_df %> %
@@ -1656,6 +1719,97 @@ log_best_run <- function(agent_info,
16561719 return (" Run logged successfully." )
16571720}
16581721
1722+ # ' Finalize Agent Run Metadata
1723+ # '
1724+ # ' This function updates the agent best run file for each combo by setting
1725+ # ' the max_iterations and run_complete flags. For global models (combo = NULL or combo = "all"),
1726+ # ' it updates all combo files. For local models, it updates a single combo file.
1727+ # '
1728+ # ' @param agent_info Agent info from `set_agent_info()`
1729+ # ' @param run_info A list containing run information including project name, run name, storage object, path, data output, and object output.
1730+ # ' @param combo A character string representing the hashed combo. If NULL or "all", updates all combos for global models.
1731+ # '
1732+ # ' @return Character string indicating success
1733+ # ' @noRd
1734+ finalize_run <- function (agent_info ,
1735+ run_info ,
1736+ combo = NULL ) {
1737+ # metadata
1738+ project_info <- agent_info $ project_info
1739+ project_info $ run_name <- agent_info $ run_id
1740+ max_iter <- agent_info $ max_iter
1741+
1742+ # load forecast to get combo list (always load to get original combo names)
1743+ if (is.null(combo )) {
1744+ combo <- " all"
1745+ combo_filter <- " All-Data"
1746+ } else {
1747+ combo_filter <- combo
1748+ }
1749+
1750+ back_test_tbl <- load_combo_forecast(
1751+ combo = combo_filter ,
1752+ run_info = run_info
1753+ )
1754+
1755+ # get unique combo names (unhashed)
1756+ combo_list <- unique(back_test_tbl $ Combo )
1757+
1758+ # for each combo, update the agent best run file
1759+ for (combo_name in combo_list ) {
1760+ # hash the combo name for file operations
1761+ combo_hash <- hash_data(combo_name )
1762+
1763+ # load the current best run file for this combo
1764+ best_run_file <- paste0(
1765+ project_info $ path , " /logs/" ,
1766+ hash_data(project_info $ project_name ), " -" ,
1767+ hash_data(agent_info $ run_id ), " -" ,
1768+ combo_hash , " -agent_best_run." , project_info $ data_output
1769+ ) %> % fs :: path_tidy()
1770+
1771+ best_run_tbl <- read_file(
1772+ run_info = project_info ,
1773+ file_list = best_run_file ,
1774+ return_type = " df"
1775+ )
1776+
1777+ if (nrow(best_run_tbl ) == 0 ) {
1778+ stop(
1779+ paste0(
1780+ " Error in finalize_run(). No best run file found for combo: " ,
1781+ combo_name
1782+ ),
1783+ call. = FALSE
1784+ )
1785+ }
1786+
1787+ # skip updating for global runs that are less accurate than previous local best runs
1788+ if (best_run_tbl $ model_type == " local" & combo == " all" ) {
1789+ next
1790+ }
1791+
1792+ # update max_iterations and run_complete
1793+ best_run_tbl_updated <- best_run_tbl %> %
1794+ dplyr :: mutate(
1795+ max_iterations = max_iter ,
1796+ run_complete = TRUE
1797+ )
1798+
1799+ # write the updated file back using the original combo name
1800+ write_data(
1801+ x = best_run_tbl_updated ,
1802+ combo = combo_name ,
1803+ run_info = project_info ,
1804+ output_type = " log" ,
1805+ folder = " logs" ,
1806+ suffix = " -agent_best_run"
1807+ )
1808+ }
1809+
1810+ return (" Run finalized successfully." )
1811+ }
1812+
16591813# ' Load previous run results for the agent
16601814# '
16611815# ' @param agent_info A list containing agent information including project info and run ID.
0 commit comments