Skip to content

Commit 6a57025

Browse files
authored
πŸ› mismatch the pattern of `\n{{content}}\n
πŸ› mismatch the pattern of ````\n{{content}}\n```
2 parents c98e5c7 + f50b6f9 commit 6a57025

File tree

2 files changed

+216
-1
lines changed

2 files changed

+216
-1
lines changed

β€Žsdk/nexent/core/agents/core_agent.pyβ€Ž

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import re
2+
import ast
23
import time
34
import threading
5+
from textwrap import dedent
46
from typing import Any, Optional, List, Dict
57
from collections.abc import Generator
68

@@ -12,7 +14,7 @@
1214
from smolagents.memory import ActionStep, PlanningStep, FinalAnswerStep, ToolCall, TaskStep, SystemPromptStep
1315
from smolagents.models import ChatMessage
1416
from smolagents.monitoring import LogLevel
15-
from smolagents.utils import AgentExecutionError, AgentGenerationError, AgentParsingError, parse_code_blobs, \
17+
from smolagents.utils import AgentExecutionError, AgentGenerationError, AgentParsingError, \
1618
truncate_content
1719

1820
from ..utils.observer import MessageObserver, ProcessType
@@ -23,6 +25,47 @@
2325
import PIL.Image
2426

2527

28+
def parse_code_blobs(text: str) -> str:
29+
"""Extract code blocs from the LLM's output.
30+
31+
If a valid code block is passed, it returns it directly.
32+
33+
Args:
34+
text (`str`): LLM's output text to parse.
35+
36+
Returns:
37+
`str`: Extracted code block.
38+
39+
Raises:
40+
ValueError: If no valid code block is found in the text.
41+
"""
42+
pattern = r"```(?:py|python)\s*\n(.*?)\n```"
43+
matches = re.findall(pattern, text, re.DOTALL)
44+
if matches:
45+
return "\n\n".join(match.strip() for match in matches)
46+
# Maybe the LLM outputted a code blob directly
47+
try:
48+
ast.parse(text)
49+
return text
50+
except SyntaxError:
51+
pass
52+
53+
raise ValueError(
54+
dedent(
55+
f"""
56+
Your code snippet is invalid, because the regex pattern {pattern} was not found in it.
57+
Here is your code snippet:
58+
{text}
59+
Make sure to include code with the correct pattern, for instance:
60+
Thoughts: Your thoughts
61+
Code:
62+
```py
63+
# Your python code here
64+
```<end_code>
65+
"""
66+
).strip()
67+
)
68+
2669
def convert_code_format(text):
2770
"""
2871
transform from ```code:python to ```python

β€Žtest/sdk/core/agents/test_core_agent.pyβ€Ž

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,175 @@ def test_convert_code_format_replacements():
247247
transformed = core_agent_module.convert_code_format(original_text)
248248

249249
assert transformed == expected_text, "convert_code_format did not perform expected replacements"
250+
251+
# ----------------------------------------------------------------------------
252+
# Tests for parse_code_blobs function
253+
# ----------------------------------------------------------------------------
254+
255+
def test_parse_code_blobs_python_match():
256+
"""Test parse_code_blobs with ```python\ncontent\n``` pattern."""
257+
text = """Here is some code:
258+
```python
259+
print("Hello World")
260+
x = 42
261+
```
262+
And some more text."""
263+
264+
result = core_agent_module.parse_code_blobs(text)
265+
expected = "print(\"Hello World\")\nx = 42"
266+
assert result == expected
267+
268+
269+
def test_parse_code_blobs_py_match():
270+
"""Test parse_code_blobs with ```py\ncontent\n``` pattern."""
271+
text = """Here is some code:
272+
```py
273+
def hello():
274+
return "Hello"
275+
```
276+
And some more text."""
277+
278+
result = core_agent_module.parse_code_blobs(text)
279+
expected = "def hello():\n return \"Hello\""
280+
assert result == expected
281+
282+
283+
def test_parse_code_blobs_multiple_matches():
284+
"""Test parse_code_blobs with multiple code blocks."""
285+
text = """First code block:
286+
```python
287+
print("First")
288+
```
289+
290+
Second code block:
291+
```py
292+
print("Second")
293+
```"""
294+
295+
result = core_agent_module.parse_code_blobs(text)
296+
expected = "print(\"First\")\n\nprint(\"Second\")"
297+
assert result == expected
298+
299+
300+
def test_parse_code_blobs_with_whitespace():
301+
"""Test parse_code_blobs with whitespace around language identifier."""
302+
text = """Code with whitespace:
303+
```python
304+
print("Hello")
305+
```
306+
More code:
307+
```py
308+
print("World")
309+
```"""
310+
311+
result = core_agent_module.parse_code_blobs(text)
312+
expected = "print(\"Hello\")\n\nprint(\"World\")"
313+
assert result == expected
314+
315+
316+
def test_parse_code_blobs_no_match():
317+
"""Test parse_code_blobs with ```\ncontent\n``` (no language specified)."""
318+
text = """Here is some code:
319+
```
320+
print("Hello World")
321+
```
322+
But no language specified."""
323+
324+
with pytest.raises(ValueError) as exc_info:
325+
core_agent_module.parse_code_blobs(text)
326+
327+
assert "regex pattern" in str(exc_info.value)
328+
329+
330+
def test_parse_code_blobs_javascript_no_match():
331+
"""Test parse_code_blobs with ```javascript\ncontent\n``` (other language)."""
332+
text = """Here is some JavaScript code:
333+
```javascript
334+
console.log("Hello World");
335+
```
336+
But this should not match."""
337+
338+
with pytest.raises(ValueError) as exc_info:
339+
core_agent_module.parse_code_blobs(text)
340+
341+
assert "regex pattern" in str(exc_info.value)
342+
343+
344+
def test_parse_code_blobs_java_no_match():
345+
"""Test parse_code_blobs with ```java\ncontent\n``` (other language)."""
346+
text = """Here is some Java code:
347+
```java
348+
System.out.println("Hello World");
349+
```
350+
But this should not match."""
351+
352+
with pytest.raises(ValueError) as exc_info:
353+
core_agent_module.parse_code_blobs(text)
354+
355+
assert "regex pattern" in str(exc_info.value)
356+
357+
358+
def test_parse_code_blobs_direct_python_code():
359+
"""Test parse_code_blobs with direct Python code (no code blocks)."""
360+
text = """print("Hello World")
361+
x = 42
362+
def hello():
363+
return "Hello\""""
364+
365+
result = core_agent_module.parse_code_blobs(text)
366+
assert result == text
367+
368+
369+
def test_parse_code_blobs_invalid_python_syntax():
370+
"""Test parse_code_blobs with invalid Python syntax (should raise ValueError)."""
371+
text = """print("Hello World"
372+
x = 42
373+
def hello(:
374+
return "Hello\""""
375+
376+
with pytest.raises(ValueError) as exc_info:
377+
core_agent_module.parse_code_blobs(text)
378+
379+
assert "regex pattern" in str(exc_info.value)
380+
381+
382+
def test_parse_code_blobs_generic_error():
383+
"""Test parse_code_blobs with generic case that should raise ValueError."""
384+
text = """This is just some random text.
385+
Just plain text that should fail."""
386+
387+
with pytest.raises(ValueError) as exc_info:
388+
core_agent_module.parse_code_blobs(text)
389+
390+
error_msg = str(exc_info.value)
391+
assert "regex pattern" in error_msg
392+
assert "Make sure to include code with the correct pattern" in error_msg
393+
394+
395+
def test_parse_code_blobs_single_line_content():
396+
"""Test parse_code_blobs with single line content."""
397+
text = """Single line:
398+
```python
399+
print("Hello")
400+
```"""
401+
402+
result = core_agent_module.parse_code_blobs(text)
403+
expected = "print(\"Hello\")"
404+
assert result == expected
405+
406+
407+
def test_parse_code_blobs_mixed_content():
408+
"""Test parse_code_blobs with mixed content including non-code text."""
409+
text = """Thoughts: I need to calculate the sum
410+
Code:
411+
```python
412+
def sum_numbers(a, b):
413+
return a + b
414+
415+
result = sum_numbers(5, 3)
416+
```
417+
The result is 8."""
418+
419+
result = core_agent_module.parse_code_blobs(text)
420+
expected = "def sum_numbers(a, b):\n return a + b\n\nresult = sum_numbers(5, 3)"
421+
assert result == expected

0 commit comments

Comments
Β (0)