File size: 7,070 Bytes
dbaeeae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#!/usr/bin/env python3
"""
FINAL WORKING FIX for Smolagents 1.19
This is the definitive solution that fully resolves the code parsing issues.
"""

import re
import ast
from textwrap import dedent
import smolagents.utils

def enhanced_parse_code_blobs(text: str) -> str:
    """
    Final enhanced version that handles all code formats correctly.
    """
    
    # Try original <code> format first
    matches = smolagents.utils._original_extract_code_from_text(text)
    if matches:
        return matches
    
    # Fix the regex patterns to handle actual newlines (not literal \n)
    # Try ```python format
    python_pattern = r"```python\s*\n(.*?)\n```"
    python_matches = re.findall(python_pattern, text, re.DOTALL)
    if python_matches:
        return "\n\n".join(match.strip() for match in python_matches)
    
    # Try ```py format  
    py_pattern = r"```py\s*\n(.*?)\n```"
    py_matches = re.findall(py_pattern, text, re.DOTALL)
    if py_matches:
        return "\n\n".join(match.strip() for match in py_matches)
    
    # Try generic ``` format (with Python detection)
    generic_pattern = r"```\s*\n(.*?)\n```"
    generic_matches = re.findall(generic_pattern, text, re.DOTALL)
    for match in generic_matches:
        # Basic Python detection
        if any(keyword in match for keyword in ['import ', 'def ', 'final_answer', 'geocode_address', '=']):
            return match.strip()
    
    # Handle single-line ```python format without newlines
    single_python_pattern = r"```python\s*(.*?)\s*```"
    single_python_matches = re.findall(single_python_pattern, text, re.DOTALL)
    if single_python_matches:
        return "\n\n".join(match.strip() for match in single_python_matches)
    
    # Handle single-line ```py format without newlines  
    single_py_pattern = r"```py\s*(.*?)\s*```"
    single_py_matches = re.findall(single_py_pattern, text, re.DOTALL)
    if single_py_matches:
        return "\n\n".join(match.strip() for match in single_py_matches)
    
    # Maybe the LLM outputted a code blob directly
    try:
        ast.parse(text)
        return text
    except SyntaxError:
        pass

    # Enhanced error messages that guide towards the correct format
    if "final" in text and "answer" in text:
        raise ValueError(
            dedent(
                f"""
                Your code snippet is invalid. Please use one of these formats:
                
                Format 1 (preferred):
                <code>
                final_answer("YOUR FINAL ANSWER HERE")
                </code>
                
                Format 2 (also supported):
                ```python
                final_answer("YOUR FINAL ANSWER HERE")
                ```
                
                Your output was:
                {text}
                """
            ).strip()
        )
    
    raise ValueError(
        dedent(
            f"""
            Your code snippet is invalid. Please use one of these formats:
            
            Format 1 (preferred):
            <code>
            # Your python code here
            final_answer("result")
            </code>
            
            Format 2 (also supported):
            ```python
            # Your python code here  
            final_answer("result")
            ```
            
            Your output was:
            {text}
            """
        ).strip()
    )

def enhanced_extract_code_from_text(text: str) -> str | None:
    """Final enhanced extract_code_from_text that handles all formats."""
    
    # Try original <code> format first
    pattern = r"<code>(.*?)</code>"
    matches = re.findall(pattern, text, re.DOTALL)
    if matches:
        return "\n\n".join(match.strip() for match in matches)
    
    # Try ```python format with newlines
    python_pattern = r"```python\s*\n(.*?)\n```"
    python_matches = re.findall(python_pattern, text, re.DOTALL)
    if python_matches:
        return "\n\n".join(match.strip() for match in python_matches)
        
    # Try ```py format with newlines
    py_pattern = r"```py\s*\n(.*?)\n```"
    py_matches = re.findall(py_pattern, text, re.DOTALL)
    if py_matches:
        return "\n\n".join(match.strip() for match in py_matches)
    
    # Try single-line formats
    single_python_pattern = r"```python\s*(.*?)\s*```"
    single_python_matches = re.findall(single_python_pattern, text, re.DOTALL)
    if single_python_matches:
        return "\n\n".join(match.strip() for match in single_python_matches)
        
    single_py_pattern = r"```py\s*(.*?)\s*```"
    single_py_matches = re.findall(single_py_pattern, text, re.DOTALL)
    if single_py_matches:
        return "\n\n".join(match.strip() for match in single_py_matches)
    
    return None

def apply_final_fix():
    """Apply the final working fix to Smolagents 1.19."""
    
    print("🔧 Applying FINAL FIX to Smolagents 1.19...")
    
    # Store original functions if not already patched
    if not hasattr(smolagents.utils, '_original_parse_code_blobs'):
        smolagents.utils._original_parse_code_blobs = smolagents.utils.parse_code_blobs
        smolagents.utils._original_extract_code_from_text = smolagents.utils.extract_code_from_text
        
        # Apply patches
        smolagents.utils.parse_code_blobs = enhanced_parse_code_blobs
        smolagents.utils.extract_code_from_text = enhanced_extract_code_from_text
        
        print("✅ Successfully patched parse_code_blobs and extract_code_from_text")
        print("✅ Now supports <code>, ```python, and ```py formats!")
        print("✅ Handles both single-line and multi-line code blocks!")
        return True
    else:
        print("ℹ️ Final fix already applied")
        return True

def test_final_fix():
    """Test the final fix comprehensively."""
    print("🧪 Testing FINAL FIX")
    print("=" * 30)
    
    # Apply the fix
    success = apply_final_fix()
    if not success:
        return False
    
    # Test all formats
    print("\\n🔧 Testing all supported formats...")
    
    test_cases = [
        ('<code>final_answer("Test 1")</code>', '<code> format'),
        ('```python\\nfinal_answer("Test 2")\\n```', '```python with newlines'),
        ('```python final_answer("Test 3") ```', '```python single-line'),
        ('```py\\nfinal_answer("Test 4")\\n```', '```py with newlines'),
        ('```py final_answer("Test 5") ```', '```py single-line'),
    ]
    
    for test_code, description in test_cases:
        try:
            result = smolagents.utils.parse_code_blobs(test_code)
            print(f"✅ {description}: {result}")
        except Exception as e:
            print(f"❌ {description} failed: {str(e)[:100]}...")
    
    return True

if __name__ == "__main__":
    success = test_final_fix()
    if success:
        print("\\n🎉 FINAL FIX READY!")
        print("\\n📝 To apply to your app, add this line to the top of app.py:")
        print("from final_fix import apply_final_fix; apply_final_fix()")
    else:
        print("\\n⚠️ Final fix needs adjustment")