Skip to content

Commit 49c7c11

Browse files
committed
fix: use greedy matching in FINAL pattern to handle nested parentheses
1 parent b052ed1 commit 49c7c11

2 files changed

Lines changed: 38 additions & 4 deletions

File tree

‎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()

‎tests/test_parsing.py‎

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ def test_final_var_answer(self):
9090
text = "Check the variable:\nFINAL_VAR(result)"
9191
# Create a mock environment that returns the variable value
9292
mock_env = Mock()
93-
mock_env.execute_code.return_value = REPLResult(stdout="42", stderr="", locals={})
93+
mock_env.execute_code.return_value = REPLResult(
94+
stdout="42", stderr="", locals={}
95+
)
9496
result = find_final_answer(text, environment=mock_env)
9597
assert result == "42"
9698
# Verify execute_code was called with the correct code
@@ -128,6 +130,33 @@ def test_final_with_whitespace(self):
128130
result = find_final_answer(text)
129131
assert result == "answer with spaces"
130132

133+
def test_final_with_nested_parentheses_greedy_matching(self):
134+
"""Test that greedy matching captures content with nested parentheses correctly.
135+
Greedy matching (.*) matches to the last closing parenthesis, correctly handling
136+
nested parentheses in FINAL() content. Non-greedy (.*?) would incorrectly stop
137+
at the first closing parenthesis, breaking functions, tuples, and nested structures.
138+
"""
139+
# Function call with nested parentheses
140+
text = "FINAL(func(arg1, arg2))"
141+
result = find_final_answer(text)
142+
assert result == "func(arg1, arg2)"
143+
144+
# List and tuple with multiple closing parentheses
145+
text = "FINAL([1, 2, 3], (4, 5))"
146+
result = find_final_answer(text)
147+
assert result == "[1, 2, 3], (4, 5)"
148+
149+
# Complex nested dictionary
150+
text = "FINAL({'key': 'value', 'nested': {'a': 1, 'b': 2}})"
151+
result = find_final_answer(text)
152+
assert "'key': 'value'" in result
153+
assert "'nested':" in result
154+
155+
# Multiple function calls with nested parentheses
156+
text = "FINAL(calculate(10, 20) + process(data))"
157+
result = find_final_answer(text)
158+
assert result == "calculate(10, 20) + process(data)"
159+
131160
def test_final_and_final_var_parsing(self):
132161
"""Test that both FINAL and FINAL_VAR patterns are parsed correctly."""
133162
# Test FINAL with various content types
@@ -170,7 +199,9 @@ def test_final_and_final_var_parsing(self):
170199
def test_final_var_takes_precedence_over_final(self):
171200
"""Test that FINAL_VAR is checked first and takes precedence over FINAL."""
172201
mock_env = Mock()
173-
mock_env.execute_code.return_value = REPLResult(stdout="var_value", stderr="", locals={})
202+
mock_env.execute_code.return_value = REPLResult(
203+
stdout="var_value", stderr="", locals={}
204+
)
174205

175206
# If both appear, FINAL_VAR should be found first (checked first in the function)
176207
text = "FINAL_VAR(result)\nFINAL(direct_answer)"
@@ -213,7 +244,9 @@ def test_final_var_retrieves_actual_variables_from_environment(self):
213244
# Test retrieving list variable
214245
text = "FINAL_VAR(answer)"
215246
result = find_final_answer(text, environment=env)
216-
assert result == "[1, 2, 3, 4, 5]", f"Expected '[1, 2, 3, 4, 5]', got '{result}'"
247+
assert (
248+
result == "[1, 2, 3, 4, 5]"
249+
), f"Expected '[1, 2, 3, 4, 5]', got '{result}'"
217250

218251
# Test retrieving computed variable
219252
text = "FINAL_VAR(computed)"

0 commit comments

Comments
 (0)