1414 RLMMetadata ,
1515)
1616from rlm .environments import BaseEnv , get_environment
17- from rlm .logger . rlm_logger import RLMLogger
17+ from rlm .logger import RLMLogger , VerbosePrinter
1818from rlm .utils .parsing import (
1919 find_code_blocks ,
2020 find_final_answer ,
@@ -50,6 +50,7 @@ def __init__(
5050 other_backends : list [ClientBackend ] | None = None ,
5151 other_backend_kwargs : list [dict [str , Any ]] | None = None ,
5252 logger : RLMLogger | None = None ,
53+ verbose : bool = False ,
5354 ):
5455 """
5556 Args:
@@ -58,12 +59,13 @@ def __init__(
5859 environment: The environment to use for the RLM.
5960 environment_kwargs: The kwargs to pass to the environment.
6061 depth: The current depth of the RLM (0-indexed).
61- max_depth: The maximum depth of the RLM.
62+ max_depth: The maximum depth of the RLM. Currently, only depth 1 is supported.
6263 max_iterations: The maximum number of iterations of the RLM.
6364 custom_system_prompt: The custom system prompt to use for the RLM.
6465 other_backends: A list of other client backends that the environments can use to make sub-calls.
6566 other_backend_kwargs: The kwargs to pass to the other client backends (ordered to match other_backends).
6667 logger: The logger to use for the RLM.
68+ verbose: Whether to print verbose output in rich to console.
6769 """
6870 # Store config for spawning per-completion
6971 self .backend = backend
@@ -78,9 +80,10 @@ def __init__(
7880 self .max_iterations = max_iterations
7981 self .system_prompt = custom_system_prompt if custom_system_prompt else RLM_SYSTEM_PROMPT
8082 self .logger = logger
83+ self .verbose = VerbosePrinter (enabled = verbose )
8184
8285 # Log metadata if logger is provided
83- if self .logger :
86+ if self .logger or verbose :
8487 metadata = RLMMetadata (
8588 root_model = backend_kwargs .get ("model_name" , "unknown" ),
8689 max_depth = max_depth ,
@@ -91,7 +94,9 @@ def __init__(
9194 environment_kwargs = filter_sensitive_keys (environment_kwargs ),
9295 other_backends = other_backends ,
9396 )
94- self .logger .log_metadata (metadata )
97+ if self .logger :
98+ self .logger .log_metadata (metadata )
99+ self .verbose .print_metadata (metadata )
95100
96101 @contextmanager
97102 def _spawn_completion_context (self , prompt : str | dict [str , Any ]):
@@ -156,6 +161,11 @@ def completion(
156161 A final answer as a string.
157162 """
158163 time_start = time .perf_counter ()
164+
165+ # If we're at max depth, the RLM is an LM, so we fallback to the regular LM.
166+ if self .depth >= self .max_depth :
167+ return self ._fallback_answer (prompt )
168+
159169 with self ._spawn_completion_context (prompt ) as (lm_handler , environment ):
160170 message_history = self ._setup_prompt (prompt )
161171
@@ -177,13 +187,19 @@ def completion(
177187 if self .logger :
178188 self .logger .log (iteration )
179189
190+ # Verbose output for this iteration
191+ self .verbose .print_iteration (iteration , i + 1 )
192+
180193 if final_answer :
181194 time_end = time .perf_counter ()
195+ usage = lm_handler .get_usage_summary ()
196+ self .verbose .print_final_answer (final_answer )
197+ self .verbose .print_summary (i + 1 , time_end - time_start , usage .to_dict ())
182198 return RLMChatCompletion (
183199 root_model = self .backend_kwargs .get ("model_name" , "unknown" ),
184200 prompt = prompt ,
185201 response = final_answer ,
186- usage_summary = lm_handler . get_usage_summary () ,
202+ usage_summary = usage ,
187203 execution_time = time_end - time_start ,
188204 )
189205
@@ -194,8 +210,18 @@ def completion(
194210 message_history .extend (new_messages )
195211
196212 # Default behavior: we run out of iterations, provide one final answer
213+ time_end = time .perf_counter ()
197214 final_answer = self ._default_answer (message_history , lm_handler )
198- return final_answer
215+ usage = lm_handler .get_usage_summary ()
216+ self .verbose .print_final_answer (final_answer )
217+ self .verbose .print_summary (self .max_iterations , time_end - time_start , usage .to_dict ())
218+ return RLMChatCompletion (
219+ root_model = self .backend_kwargs .get ("model_name" , "unknown" ),
220+ prompt = prompt ,
221+ response = final_answer ,
222+ usage_summary = usage ,
223+ execution_time = time_end - time_start ,
224+ )
199225
200226 def _completion_turn (
201227 self ,
@@ -248,3 +274,11 @@ def _default_answer(self, message_history: list[dict[str, Any]], lm_handler: LMH
248274 )
249275
250276 return response
277+
278+ def _fallback_answer (self , message : str | dict [str , Any ]) -> str :
279+ """
280+ Fallback behavior if the RLM is actually at max depth, and should be treated as an LM.
281+ """
282+ client : BaseLM = get_client (self .backend , self .backend_kwargs )
283+ response = client .completion (message )
284+ return response
0 commit comments