Skip to content

Commit 7dc76a2

Browse files
authored
Merge branch 'alexzhang13:main' into gemini-support
2 parents e8f0865 + 37f6d0b commit 7dc76a2

8 files changed

Lines changed: 109 additions & 9 deletions

File tree

‎rlm/environments/daytona_repl.py‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,14 +261,24 @@ def FINAL_VAR(variable_name):
261261
variable_name = variable_name.strip().strip("\\"\\'")
262262
if variable_name in _locals:
263263
return str(_locals[variable_name])
264-
return f"Error: Variable '{{variable_name}}' not found"
264+
available = [k for k in _locals.keys() if not k.startswith("_")]
265+
if available:
266+
return f"Error: Variable '{{variable_name}}' not found. Available variables: {{available}}. You must create and assign a variable BEFORE calling FINAL_VAR on it."
267+
return f"Error: Variable '{{variable_name}}' not found. No variables have been created yet. You must create and assign a variable in a REPL block BEFORE calling FINAL_VAR on it."
268+
269+
def SHOW_VARS():
270+
available = {{k: type(v).__name__ for k, v in _locals.items() if not k.startswith("_")}}
271+
if not available:
272+
return "No variables created yet. Use ```repl``` blocks to create variables."
273+
return f"Available variables: {{available}}"
265274
266275
_globals = {{
267276
"__builtins__": __builtins__,
268277
"__name__": "__main__",
269278
"llm_query": llm_query,
270279
"llm_query_batched": llm_query_batched,
271280
"FINAL_VAR": FINAL_VAR,
281+
"SHOW_VARS": SHOW_VARS,
272282
}}
273283
274284
code = base64.b64decode("{code_b64}").decode()

‎rlm/environments/docker_repl.py‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,20 @@ def save_state(s):
142142
143143
def FINAL_VAR(name):
144144
name = name.strip().strip("\\"\\'")
145-
return str(_locals.get(name, f"Error: Variable '{{name}}' not found"))
146-
147-
_globals = {{"__builtins__": __builtins__, "__name__": "__main__", "llm_query": llm_query, "llm_query_batched": llm_query_batched, "FINAL_VAR": FINAL_VAR}}
145+
if name in _locals:
146+
return str(_locals[name])
147+
available = [k for k in _locals.keys() if not k.startswith("_")]
148+
if available:
149+
return f"Error: Variable '{{name}}' not found. Available variables: {{available}}. You must create and assign a variable BEFORE calling FINAL_VAR on it."
150+
return f"Error: Variable '{{name}}' not found. No variables have been created yet. You must create and assign a variable in a REPL block BEFORE calling FINAL_VAR on it."
151+
152+
def SHOW_VARS():
153+
available = {{k: type(v).__name__ for k, v in _locals.items() if not k.startswith("_")}}
154+
if not available:
155+
return "No variables created yet. Use ```repl``` blocks to create variables."
156+
return f"Available variables: {{available}}"
157+
158+
_globals = {{"__builtins__": __builtins__, "__name__": "__main__", "llm_query": llm_query, "llm_query_batched": llm_query_batched, "FINAL_VAR": FINAL_VAR, "SHOW_VARS": SHOW_VARS}}
148159
149160
code = base64.b64decode("{code_b64}").decode()
150161
stdout_buf, stderr_buf = io.StringIO(), io.StringIO()

‎rlm/environments/local_repl.py‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ def setup(self):
161161

162162
# Add helper functions
163163
self.globals["FINAL_VAR"] = self._final_var
164+
self.globals["SHOW_VARS"] = self._show_vars
164165
self.globals["llm_query"] = self._llm_query
165166
self.globals["llm_query_batched"] = self._llm_query_batched
166167

@@ -169,7 +170,27 @@ def _final_var(self, variable_name: str) -> str:
169170
variable_name = variable_name.strip().strip("\"'")
170171
if variable_name in self.locals:
171172
return str(self.locals[variable_name])
172-
return f"Error: Variable '{variable_name}' not found"
173+
174+
# Provide helpful error message with available variables
175+
available = [k for k in self.locals.keys() if not k.startswith("_")]
176+
if available:
177+
return (
178+
f"Error: Variable '{variable_name}' not found. "
179+
f"Available variables: {available}. "
180+
f"You must create and assign a variable BEFORE calling FINAL_VAR on it."
181+
)
182+
return (
183+
f"Error: Variable '{variable_name}' not found. "
184+
f"No variables have been created yet. "
185+
f"You must create and assign a variable in a REPL block BEFORE calling FINAL_VAR on it."
186+
)
187+
188+
def _show_vars(self) -> str:
189+
"""Show all available variables in the REPL environment."""
190+
available = {k: type(v).__name__ for k, v in self.locals.items() if not k.startswith("_")}
191+
if not available:
192+
return "No variables created yet. Use ```repl``` blocks to create variables."
193+
return f"Available variables: {available}"
173194

174195
def _llm_query(self, prompt: str, model: str | None = None) -> str:
175196
"""Query the LM via socket connection to the handler.

‎rlm/environments/modal_repl.py‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,14 +221,24 @@ def FINAL_VAR(variable_name):
221221
variable_name = variable_name.strip().strip("\\"\\'")
222222
if variable_name in _locals:
223223
return str(_locals[variable_name])
224-
return f"Error: Variable '{{variable_name}}' not found"
224+
available = [k for k in _locals.keys() if not k.startswith("_")]
225+
if available:
226+
return f"Error: Variable '{{variable_name}}' not found. Available variables: {{available}}. You must create and assign a variable BEFORE calling FINAL_VAR on it."
227+
return f"Error: Variable '{{variable_name}}' not found. No variables have been created yet. You must create and assign a variable in a REPL block BEFORE calling FINAL_VAR on it."
228+
229+
def SHOW_VARS():
230+
available = {{k: type(v).__name__ for k, v in _locals.items() if not k.startswith("_")}}
231+
if not available:
232+
return "No variables created yet. Use ```repl``` blocks to create variables."
233+
return f"Available variables: {{available}}"
225234
226235
_globals = {{
227236
"__builtins__": __builtins__,
228237
"__name__": "__main__",
229238
"llm_query": llm_query,
230239
"llm_query_batched": llm_query_batched,
231240
"FINAL_VAR": FINAL_VAR,
241+
"SHOW_VARS": SHOW_VARS,
232242
}}
233243
234244
code = base64.b64decode("{code_b64}").decode()

‎rlm/environments/prime_repl.py‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,14 +220,24 @@ def FINAL_VAR(variable_name):
220220
variable_name = variable_name.strip().strip("\\"\\'")
221221
if variable_name in _locals:
222222
return str(_locals[variable_name])
223-
return f"Error: Variable '{{variable_name}}' not found"
223+
available = [k for k in _locals.keys() if not k.startswith("_")]
224+
if available:
225+
return f"Error: Variable '{{variable_name}}' not found. Available variables: {{available}}. You must create and assign a variable BEFORE calling FINAL_VAR on it."
226+
return f"Error: Variable '{{variable_name}}' not found. No variables have been created yet. You must create and assign a variable in a REPL block BEFORE calling FINAL_VAR on it."
227+
228+
def SHOW_VARS():
229+
available = {{k: type(v).__name__ for k, v in _locals.items() if not k.startswith("_")}}
230+
if not available:
231+
return "No variables created yet. Use ```repl``` blocks to create variables."
232+
return f"Available variables: {{available}}"
224233
225234
_globals = {{
226235
"__builtins__": __builtins__,
227236
"__name__": "__main__",
228237
"llm_query": llm_query,
229238
"llm_query_batched": llm_query_batched,
230239
"FINAL_VAR": FINAL_VAR,
240+
"SHOW_VARS": SHOW_VARS,
231241
}}
232242
233243
code = base64.b64decode("{code_b64}").decode()

‎rlm/utils/parsing.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ def find_final_answer(text: str, environment: "BaseEnv | None" = None) -> str |
5454
return None
5555

5656
# Check for FINAL pattern - must be at start of line
57-
final_pattern = r"^\s*FINAL\((.*?)\)"
57+
# Use greedy matching to capture content with nested parentheses
58+
final_pattern = r"^\s*FINAL\((.*)\)\s*$"
5859
match = re.search(final_pattern, text, re.MULTILINE | re.DOTALL)
5960
if match:
6061
return match.group(1).strip()

‎rlm/utils/prompts.py‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
1. A `context` variable that contains extremely important information about your query. You should check the content of the `context` variable to understand what you are working with. Make sure you look through it sufficiently as you answer your query.
1111
2. A `llm_query` function that allows you to query an LLM (that can handle around 500K chars) inside your REPL environment.
1212
3. A `llm_query_batched` function that allows you to query multiple prompts concurrently: `llm_query_batched(prompts: List[str]) -> List[str]`. This is much faster than sequential `llm_query` calls when you have multiple independent queries. Results are returned in the same order as the input prompts.
13-
4. The ability to use `print()` statements to view the output of your REPL code and continue your reasoning.
13+
4. A `SHOW_VARS()` function that returns all variables you have created in the REPL. Use this to check what variables exist before using FINAL_VAR.
14+
5. The ability to use `print()` statements to view the output of your REPL code and continue your reasoning.
1415
1516
You will only be able to see truncated outputs from the REPL environment, so you should use the query LLM function on variables you want to analyze. You will find this function especially useful when you have to analyze the semantics of the context. Use these variables as buffers to build up your final answer.
1617
Make sure to explicitly look through the entire context in REPL before answering your query. An example strategy is to first look at the context and figure out a chunking strategy, then break up the context into smart chunks, and query an LLM per chunk with a particular question and save the answers to a buffer, then query an LLM with all the buffers to produce your final answer.
@@ -76,6 +77,15 @@
7677
1. Use FINAL(your final answer here) to provide the answer directly
7778
2. Use FINAL_VAR(variable_name) to return a variable you have created in the REPL environment as your final output
7879
80+
WARNING - COMMON MISTAKE: FINAL_VAR retrieves an EXISTING variable. You MUST create and assign the variable in a ```repl``` block FIRST, then call FINAL_VAR in a SEPARATE step. For example:
81+
- WRONG: Calling FINAL_VAR(my_answer) without first creating `my_answer` in a repl block
82+
- CORRECT: First run ```repl
83+
my_answer = "the result"
84+
print(my_answer)
85+
``` then in the NEXT response call FINAL_VAR(my_answer)
86+
87+
If you're unsure what variables exist, you can call SHOW_VARS() in a repl block to see all available variables.
88+
7989
Think step by step carefully, plan, and execute this plan immediately in your response -- do not just say "I will do this" or "I will do that". Output to the REPL environment and recursive LLMs as much as possible. Remember to explicitly answer the original query in your final answer.
8090
"""
8191
)

‎tests/test_parsing.py‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,33 @@ def test_final_with_whitespace(self):
128128
result = find_final_answer(text)
129129
assert result == "answer with spaces"
130130

131+
def test_final_with_nested_parentheses_greedy_matching(self):
132+
"""Test that greedy matching captures content with nested parentheses correctly.
133+
Greedy matching (.*) matches to the last closing parenthesis, correctly handling
134+
nested parentheses in FINAL() content. Non-greedy (.*?) would incorrectly stop
135+
at the first closing parenthesis, breaking functions, tuples, and nested structures.
136+
"""
137+
# Function call with nested parentheses
138+
text = "FINAL(func(arg1, arg2))"
139+
result = find_final_answer(text)
140+
assert result == "func(arg1, arg2)"
141+
142+
# List and tuple with multiple closing parentheses
143+
text = "FINAL([1, 2, 3], (4, 5))"
144+
result = find_final_answer(text)
145+
assert result == "[1, 2, 3], (4, 5)"
146+
147+
# Complex nested dictionary
148+
text = "FINAL({'key': 'value', 'nested': {'a': 1, 'b': 2}})"
149+
result = find_final_answer(text)
150+
assert "'key': 'value'" in result
151+
assert "'nested':" in result
152+
153+
# Multiple function calls with nested parentheses
154+
text = "FINAL(calculate(10, 20) + process(data))"
155+
result = find_final_answer(text)
156+
assert result == "calculate(10, 20) + process(data)"
157+
131158
def test_final_and_final_var_parsing(self):
132159
"""Test that both FINAL and FINAL_VAR patterns are parsed correctly."""
133160
# Test FINAL with various content types

0 commit comments

Comments
 (0)