gptdiff 0.1.20__tar.gz → 0.1.22__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gptdiff-0.1.20 → gptdiff-0.1.22}/PKG-INFO +2 -2
- {gptdiff-0.1.20 → gptdiff-0.1.22}/gptdiff/gptdiff.py +66 -18
- {gptdiff-0.1.20 → gptdiff-0.1.22}/gptdiff.egg-info/PKG-INFO +2 -2
- {gptdiff-0.1.20 → gptdiff-0.1.22}/gptdiff.egg-info/SOURCES.txt +1 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/gptdiff.egg-info/requires.txt +1 -1
- {gptdiff-0.1.20 → gptdiff-0.1.22}/setup.py +2 -2
- gptdiff-0.1.22/tests/test_strip_bad_ouput.py +90 -0
- gptdiff-0.1.22/tests/test_swallow_reasoning.py +156 -0
- gptdiff-0.1.20/tests/test_swallow_reasoning.py +0 -51
- {gptdiff-0.1.20 → gptdiff-0.1.22}/LICENSE.txt +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/README.md +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/gptdiff/__init__.py +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/gptdiff/gptpatch.py +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/gptdiff.egg-info/dependency_links.txt +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/gptdiff.egg-info/entry_points.txt +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/gptdiff.egg-info/top_level.txt +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/setup.cfg +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/tests/test_applydiff.py +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/tests/test_applydiff_edgecases.py +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/tests/test_diff_parse.py +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/tests/test_failing_case.py +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/tests/test_parse_diff_per_file.py +0 -0
- {gptdiff-0.1.20 → gptdiff-0.1.22}/tests/test_smartapply.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: gptdiff
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.22
|
4
4
|
Summary: A tool to generate and apply git diffs using LLMs
|
5
5
|
Author: 255labs
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
@@ -10,7 +10,7 @@ Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE.txt
|
11
11
|
Requires-Dist: openai>=1.0.0
|
12
12
|
Requires-Dist: tiktoken>=0.5.0
|
13
|
-
Requires-Dist:
|
13
|
+
Requires-Dist: ai-agent-toolbox>=0.1.15
|
14
14
|
Provides-Extra: test
|
15
15
|
Requires-Dist: pytest; extra == "test"
|
16
16
|
Requires-Dist: pytest-mock; extra == "test"
|
@@ -345,7 +345,8 @@ def smartapply(diff_text, files, model=None, api_key=None, base_url=None):
|
|
345
345
|
del files[path]
|
346
346
|
else:
|
347
347
|
updated = call_llm_for_apply_with_think_tool_available(path, original, patch, model, api_key=api_key, base_url=base_url)
|
348
|
-
|
348
|
+
cleaned = strip_bad_output(updated, original)
|
349
|
+
files[path] = cleaned
|
349
350
|
|
350
351
|
threads = []
|
351
352
|
|
@@ -585,7 +586,7 @@ def parse_diff_per_file(diff_text):
|
|
585
586
|
for line in lines:
|
586
587
|
if header_line_re.match(line):
|
587
588
|
if current_file is not None and current_lines:
|
588
|
-
if deletion_mode and not any(l.startswith("+++ ") for l in current_lines):
|
589
|
+
if deletion_mode and not any(l.startswith("+++ /dev/null") for l in current_lines):
|
589
590
|
current_lines.append("+++ /dev/null")
|
590
591
|
diffs.append((current_file, "\n".join(current_lines)))
|
591
592
|
current_lines = [line]
|
@@ -778,24 +779,41 @@ def smart_apply_patch(project_dir, diff_text, user_prompt, args):
|
|
778
779
|
else:
|
779
780
|
print(f"\033[1;33mFile {file_path} not found - skipping deletion\033[0m")
|
780
781
|
return
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
if
|
791
|
-
|
782
|
+
|
783
|
+
try:
|
784
|
+
original_content = full_path.read_text()
|
785
|
+
except (UnicodeDecodeError, IOError):
|
786
|
+
print(f"Skipping file {file_path} due to read error")
|
787
|
+
return
|
788
|
+
|
789
|
+
# Use SMARTAPPLY-specific environment variables if set, otherwise fallback.
|
790
|
+
smart_apply_model = os.getenv("GPTDIFF_SMARTAPPLY_MODEL")
|
791
|
+
if smart_apply_model and smart_apply_model.strip():
|
792
|
+
model = smart_apply_model
|
793
|
+
elif hasattr(args, "applymodel") and args.applymodel:
|
794
|
+
model = args.applymodel
|
795
|
+
else:
|
796
|
+
model = os.getenv("GPTDIFF_MODEL", "deepseek-reasoner")
|
797
|
+
|
798
|
+
smart_api_key = os.getenv("GPTDIFF_SMARTAPPLY_API_KEY")
|
799
|
+
if smart_api_key and smart_api_key.strip():
|
800
|
+
api_key = smart_api_key
|
801
|
+
else:
|
802
|
+
api_key = os.getenv("GPTDIFF_LLM_API_KEY")
|
803
|
+
|
804
|
+
smart_base_url = os.getenv("GPTDIFF_SMARTAPPLY_BASE_URL")
|
805
|
+
if smart_base_url and smart_base_url.strip():
|
806
|
+
base_url = smart_base_url
|
807
|
+
else:
|
808
|
+
base_url = os.getenv("GPTDIFF_LLM_BASE_URL", "https://nano-gpt.com/api/v1/")
|
792
809
|
|
793
810
|
print("-" * 40)
|
794
|
-
print("Running smartapply with",
|
811
|
+
print("Running smartapply with", model, "on", file_path)
|
795
812
|
print("-" * 40)
|
796
813
|
try:
|
797
814
|
updated_content = call_llm_for_apply_with_think_tool_available(
|
798
|
-
file_path, original_content, file_diff,
|
815
|
+
file_path, original_content, file_diff, model,
|
816
|
+
api_key=api_key, base_url=base_url,
|
799
817
|
extra_prompt=f"This changeset is from the following instructions:\n{user_prompt}",
|
800
818
|
max_tokens=args.max_tokens)
|
801
819
|
if updated_content.strip() == "":
|
@@ -985,17 +1003,47 @@ def swallow_reasoning(full_response: str) -> (str, str):
|
|
985
1003
|
- reasoning: The extracted reasoning block, or an empty string if not found.
|
986
1004
|
"""
|
987
1005
|
pattern = re.compile(
|
988
|
-
r"(?P<reasoning>>\s*Reasoning.*?Reasoned
|
1006
|
+
r"(?P<reasoning>>\s*Reasoning.*?Reasoned.*?seconds)",
|
989
1007
|
re.DOTALL
|
990
1008
|
)
|
991
1009
|
match = pattern.search(full_response)
|
992
1010
|
if match:
|
993
|
-
|
994
|
-
|
1011
|
+
raw_reasoning = match.group("reasoning")
|
1012
|
+
# Remove any leading '+' characters and extra whitespace from each line
|
1013
|
+
reasoning_lines = [line.lstrip('+').strip() for line in raw_reasoning.splitlines()]
|
1014
|
+
reasoning = "\n".join(reasoning_lines).strip()
|
1015
|
+
|
1016
|
+
# Remove the reasoning block from the response using its exact span
|
1017
|
+
final_content = full_response[:match.start()] + full_response[match.end():]
|
1018
|
+
final_content = final_content.strip()
|
995
1019
|
else:
|
996
1020
|
reasoning = ""
|
997
1021
|
final_content = full_response.strip()
|
998
1022
|
return final_content, reasoning
|
999
1023
|
|
1024
|
+
def strip_bad_output(updated: str, original: str) -> str:
|
1025
|
+
"""
|
1026
|
+
If the original file content does not start with a code fence but the LLM’s updated output
|
1027
|
+
starts with triple backticks (possibly with an introductory message), extract and return only
|
1028
|
+
the content within the first code block.
|
1029
|
+
"""
|
1030
|
+
updated_stripped = updated.strip()
|
1031
|
+
# If the original file does not start with a code fence, but the updated output contains a code block,
|
1032
|
+
# extract and return only the content inside the first code block.
|
1033
|
+
if not original.lstrip().startswith("```"):
|
1034
|
+
# Search for the first code block in the updated output.
|
1035
|
+
m = re.search(r"```(.*?)```", updated_stripped, re.DOTALL)
|
1036
|
+
if m:
|
1037
|
+
content = m.group(1).strip()
|
1038
|
+
lines = content.splitlines()
|
1039
|
+
if len(lines) > 1:
|
1040
|
+
first_line = lines[0].strip()
|
1041
|
+
# If the first line appears to be a language specifier (i.e., a single word)
|
1042
|
+
# and is not "diff", then drop it.
|
1043
|
+
if " " not in first_line and first_line.lower() != "diff":
|
1044
|
+
content = "\n".join(lines[1:]).strip()
|
1045
|
+
return content
|
1046
|
+
return updated_stripped
|
1047
|
+
|
1000
1048
|
if __name__ == "__main__":
|
1001
1049
|
main()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: gptdiff
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.22
|
4
4
|
Summary: A tool to generate and apply git diffs using LLMs
|
5
5
|
Author: 255labs
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
@@ -10,7 +10,7 @@ Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE.txt
|
11
11
|
Requires-Dist: openai>=1.0.0
|
12
12
|
Requires-Dist: tiktoken>=0.5.0
|
13
|
-
Requires-Dist:
|
13
|
+
Requires-Dist: ai-agent-toolbox>=0.1.15
|
14
14
|
Provides-Extra: test
|
15
15
|
Requires-Dist: pytest; extra == "test"
|
16
16
|
Requires-Dist: pytest-mock; extra == "test"
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
2
2
|
|
3
3
|
setup(
|
4
4
|
name='gptdiff',
|
5
|
-
version='0.1.
|
5
|
+
version='0.1.22',
|
6
6
|
description='A tool to generate and apply git diffs using LLMs',
|
7
7
|
author='255labs',
|
8
8
|
packages=find_packages(), # Use find_packages() to automatically discover packages
|
@@ -12,7 +12,7 @@ setup(
|
|
12
12
|
install_requires=[
|
13
13
|
'openai>=1.0.0',
|
14
14
|
'tiktoken>=0.5.0',
|
15
|
-
'
|
15
|
+
'ai-agent-toolbox>=0.1.15'
|
16
16
|
],
|
17
17
|
extras_require={
|
18
18
|
'test': ['pytest', 'pytest-mock'],
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# File: tests/test_strip_bad_output.py
|
2
|
+
import pytest
|
3
|
+
from gptdiff.gptdiff import strip_bad_output
|
4
|
+
|
5
|
+
def test_strip_bad_output_removes_wrapping():
|
6
|
+
"""
|
7
|
+
If the original file content does not start with a code fence,
|
8
|
+
but the LLM output starts with a code block and extra text,
|
9
|
+
then only the content inside the first code block should be returned.
|
10
|
+
"""
|
11
|
+
# Original file content does not start with a code fence.
|
12
|
+
original = "def hello():\n print('Hello')\n"
|
13
|
+
# Simulated LLM output with extraneous text and a code block.
|
14
|
+
updated = (
|
15
|
+
"This is the file you requested:\n"
|
16
|
+
"```diff\n"
|
17
|
+
"def hello():\n"
|
18
|
+
" print('Goodbye')\n"
|
19
|
+
"```\n"
|
20
|
+
"Thank you!"
|
21
|
+
)
|
22
|
+
# We expect the function to extract only the content inside the code block.
|
23
|
+
expected = "diff\ndef hello():\n print('Goodbye')"
|
24
|
+
result = strip_bad_output(updated, original)
|
25
|
+
assert result == expected, f"Expected:\n{expected}\nGot:\n{result}"
|
26
|
+
|
27
|
+
def test_strip_bad_output_no_change_when_original_has_code_block():
|
28
|
+
"""
|
29
|
+
If the original file already starts with a code fence,
|
30
|
+
the function should leave the updated output unchanged.
|
31
|
+
"""
|
32
|
+
original = "```diff\ndef hello():\n print('Hello')\n```"
|
33
|
+
updated = "```diff\ndef hello():\n print('Modified')\n```"
|
34
|
+
expected = updated.strip()
|
35
|
+
result = strip_bad_output(updated, original)
|
36
|
+
assert result == expected, "Expected no changes when original already starts with a code fence"
|
37
|
+
|
38
|
+
def test_strip_bad_output_no_wrapping_detected():
|
39
|
+
"""
|
40
|
+
If the updated output does not start with a code fence,
|
41
|
+
the function should return the updated output unchanged.
|
42
|
+
"""
|
43
|
+
original = "def hello():\n print('Hello')\n"
|
44
|
+
updated = "def hello():\n print('Modified')\n"
|
45
|
+
expected = updated.strip()
|
46
|
+
result = strip_bad_output(updated, original)
|
47
|
+
assert result == expected, "Expected output to remain unchanged if no code block is detected"
|
48
|
+
|
49
|
+
|
50
|
+
def test_strip_bad_output_prod_case():
|
51
|
+
"""
|
52
|
+
Test that when the updated output includes extraneous introductory text and
|
53
|
+
a language specifier in the code block, the function extracts only the content
|
54
|
+
within the code block (without the language tag or extra text).
|
55
|
+
|
56
|
+
For example, given an updated output like:
|
57
|
+
|
58
|
+
Here's the entire file after applying the diff:
|
59
|
+
|
60
|
+
```typescript
|
61
|
+
def foo():
|
62
|
+
print('Modified')
|
63
|
+
```
|
64
|
+
Some trailing text that should be ignored.
|
65
|
+
|
66
|
+
the expected extracted content is:
|
67
|
+
|
68
|
+
def foo():
|
69
|
+
print('Modified')
|
70
|
+
"""
|
71
|
+
# Original file content does not start with a code fence.
|
72
|
+
original = "def foo():\n pass\n"
|
73
|
+
|
74
|
+
# Simulated LLM output with extraneous text, a language specifier ("typescript"),
|
75
|
+
# and trailing text.
|
76
|
+
updated = (
|
77
|
+
"Here's the entire file after applying the diff:\n\n"
|
78
|
+
"```typescript\n"
|
79
|
+
"def foo():\n"
|
80
|
+
" print('Modified')\n"
|
81
|
+
"```\n"
|
82
|
+
"Some trailing text that should be ignored."
|
83
|
+
)
|
84
|
+
|
85
|
+
# We expect the function to extract only the content inside the first code block,
|
86
|
+
# ignoring the language specifier and any text outside the code block.
|
87
|
+
expected = "def foo():\n print('Modified')"
|
88
|
+
|
89
|
+
result = strip_bad_output(updated, original)
|
90
|
+
assert result == expected, f"Expected:\n{expected}\nGot:\n{result}"
|
@@ -0,0 +1,156 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from gptdiff.gptdiff import swallow_reasoning
|
4
|
+
|
5
|
+
def test_swallow_reasoning_extraction():
|
6
|
+
llm_response = (
|
7
|
+
"+> Reasoning\n"
|
8
|
+
"+None\n"
|
9
|
+
"+Reasoned about summary drawer button 변경 for 15 seconds\n"
|
10
|
+
"+def new():\n"
|
11
|
+
"```"
|
12
|
+
)
|
13
|
+
final_content, reasoning = swallow_reasoning(llm_response)
|
14
|
+
expected_reasoning = (
|
15
|
+
"> Reasoning\n"
|
16
|
+
"**Applying the diff**\n"
|
17
|
+
"I'm piecing together how to efficiently apply a diff to a file...\n"
|
18
|
+
"**Returning the result**\n"
|
19
|
+
"I'm finalizing the method to apply the diff updates...\n"
|
20
|
+
"Reasoned for 6 seconds"
|
21
|
+
)
|
22
|
+
assert reasoning == expected_reasoning
|
23
|
+
# The final content should no longer contain the reasoning block.
|
24
|
+
assert expected_reasoning not in final_content
|
25
|
+
# And it should contain the diff block.
|
26
|
+
assert "```diff" in final_content
|
27
|
+
|
28
|
+
|
29
|
+
def test_swallow_reasoning_with_untested_response():
|
30
|
+
llm_response = (
|
31
|
+
"> Reasoning\n"
|
32
|
+
"**Considering the request**\n"
|
33
|
+
"I’m noting that the user wants me to apply a diff to a file and return the result in a block, ensuring the entire file is included.\n"
|
34
|
+
"**Ensuring comprehensive inclusion**\n"
|
35
|
+
"I'm making sure the entire file is included when presenting the result in a block, following the user's request carefully.\n"
|
36
|
+
"**Ensuring clarity**\n"
|
37
|
+
"I’m integrating the diff into the file and ensuring the entire file is returned as requested. This approach maintains precision and clarity in the response.\n"
|
38
|
+
"**Refining the response**\n"
|
39
|
+
"I’m focusing on how to structure the response by carefully integrating the diff and ensuring the entire file is included in a clear block format.\n"
|
40
|
+
"**Connecting the pieces**\n"
|
41
|
+
"I'm mapping out how to apply the diff to the file carefully and ensure the entire file is incorporated into the final block.\n"
|
42
|
+
"Reasoned for a few seconds\n"
|
43
|
+
"\n"
|
44
|
+
"```diff\n"
|
45
|
+
"--- a/file.py\n"
|
46
|
+
"+++ b/file.py\n"
|
47
|
+
"@@ -1,2 +1,2 @@\n"
|
48
|
+
"-def old():\n"
|
49
|
+
"+def new():\n"
|
50
|
+
"```"
|
51
|
+
)
|
52
|
+
final_content, reasoning = swallow_reasoning(llm_response)
|
53
|
+
|
54
|
+
expected_reasoning = (
|
55
|
+
"> Reasoning\n"
|
56
|
+
"**Considering the request**\n"
|
57
|
+
"I’m noting that the user wants me to apply a diff to a file and return the result in a block, ensuring the entire file is included.\n"
|
58
|
+
"**Ensuring comprehensive inclusion**\n"
|
59
|
+
"I'm making sure the entire file is included when presenting the result in a block, following the user's request carefully.\n"
|
60
|
+
"**Ensuring clarity**\n"
|
61
|
+
"I’m integrating the diff into the file and ensuring the entire file is returned as requested. This approach maintains precision and clarity in the response.\n"
|
62
|
+
"**Refining the response**\n"
|
63
|
+
"I’m focusing on how to structure the response by carefully integrating the diff and ensuring the entire file is included in a clear block format.\n"
|
64
|
+
"**Connecting the pieces**\n"
|
65
|
+
"I'm mapping out how to apply the diff to the file carefully and ensure the entire file is incorporated into the final block.\n"
|
66
|
+
"Reasoned for a few seconds"
|
67
|
+
)
|
68
|
+
|
69
|
+
assert reasoning == expected_reasoning
|
70
|
+
# The final content should no longer contain the reasoning block.
|
71
|
+
assert expected_reasoning not in final_content
|
72
|
+
# And it should contain the diff block.
|
73
|
+
assert "```diff" in final_content
|
74
|
+
|
75
|
+
def test_swallow_reasoning_extraction():
|
76
|
+
llm_response = (
|
77
|
+
"> Reasoning\n"
|
78
|
+
"**Applying the diff**\n"
|
79
|
+
"I'm piecing together how to efficiently apply a diff to a file...\n"
|
80
|
+
"**Returning the result**\n"
|
81
|
+
"I'm finalizing the method to apply the diff updates...\n"
|
82
|
+
"Reasoned for 6 seconds\n"
|
83
|
+
"\n"
|
84
|
+
"```diff\n"
|
85
|
+
"--- a/file.py\n"
|
86
|
+
"+++ b/file.py\n"
|
87
|
+
"@@ -1,2 +1,2 @@\n"
|
88
|
+
"-def old():\n"
|
89
|
+
"+def new():\n"
|
90
|
+
"```"
|
91
|
+
)
|
92
|
+
final_content, reasoning = swallow_reasoning(llm_response)
|
93
|
+
expected_reasoning = (
|
94
|
+
"> Reasoning\n"
|
95
|
+
"**Applying the diff**\n"
|
96
|
+
"I'm piecing together how to efficiently apply a diff to a file...\n"
|
97
|
+
"**Returning the result**\n"
|
98
|
+
"I'm finalizing the method to apply the diff updates...\n"
|
99
|
+
"Reasoned for 6 seconds"
|
100
|
+
)
|
101
|
+
assert reasoning == expected_reasoning
|
102
|
+
# The final content should no longer contain the reasoning block.
|
103
|
+
assert expected_reasoning not in final_content
|
104
|
+
# And it should contain the diff block.
|
105
|
+
assert "```diff" in final_content
|
106
|
+
|
107
|
+
|
108
|
+
def test_swallow_reasoning_no_reasoning():
|
109
|
+
llm_response = (
|
110
|
+
"```diff\n"
|
111
|
+
"--- a/file.py\n"
|
112
|
+
"+++ b/file.py\n"
|
113
|
+
"@@ -1,2 +1,2 @@\n"
|
114
|
+
"-def old():\n"
|
115
|
+
"+def new():\n"
|
116
|
+
"```"
|
117
|
+
)
|
118
|
+
final_content, reasoning = swallow_reasoning(llm_response)
|
119
|
+
assert reasoning == ""
|
120
|
+
assert final_content == llm_response.strip()
|
121
|
+
|
122
|
+
def test_swallow_reasoning_inline_newlines():
|
123
|
+
llm_response = (
|
124
|
+
"Prefix text before reasoning and some inline content "
|
125
|
+
"> Reasoning\n"
|
126
|
+
"Inline line 1\n"
|
127
|
+
"Inline line 2\n"
|
128
|
+
"Reasoned for 2 seconds "
|
129
|
+
"and then suffix text.\n"
|
130
|
+
"```diff\n"
|
131
|
+
"--- a/inline.py\n"
|
132
|
+
"+++ b/inline.py\n"
|
133
|
+
"@@ -1,2 +1,2 @@\n"
|
134
|
+
"-print('Old')\n"
|
135
|
+
"+print('New')\n"
|
136
|
+
"```"
|
137
|
+
)
|
138
|
+
final_content, reasoning = swallow_reasoning(llm_response)
|
139
|
+
expected_reasoning = (
|
140
|
+
"> Reasoning\n"
|
141
|
+
"Inline line 1\n"
|
142
|
+
"Inline line 2\n"
|
143
|
+
"Reasoned for 2 seconds"
|
144
|
+
)
|
145
|
+
# Count the newlines in the extracted reasoning block.
|
146
|
+
newline_count = reasoning.count('\n')
|
147
|
+
# There should be 3 newline characters: after "> Reasoning", after "Inline line 1", and after "Inline line 2"
|
148
|
+
assert newline_count == 3, f"Expected 3 newlines, got {newline_count}"
|
149
|
+
assert reasoning == expected_reasoning
|
150
|
+
# Ensure the reasoning block is removed from the final content.
|
151
|
+
assert expected_reasoning not in final_content
|
152
|
+
# Verify that surrounding content remains.
|
153
|
+
assert "Prefix text before reasoning" in final_content
|
154
|
+
assert "and then suffix text." in final_content
|
155
|
+
# Verify that the diff block is still present.
|
156
|
+
assert "```diff" in final_content
|
@@ -1,51 +0,0 @@
|
|
1
|
-
import pytest
|
2
|
-
|
3
|
-
from gptdiff.gptdiff import swallow_reasoning
|
4
|
-
|
5
|
-
|
6
|
-
def test_swallow_reasoning_extraction():
|
7
|
-
llm_response = (
|
8
|
-
"> Reasoning\n"
|
9
|
-
"**Applying the diff**\n"
|
10
|
-
"I'm piecing together how to efficiently apply a diff to a file...\n"
|
11
|
-
"**Returning the result**\n"
|
12
|
-
"I'm finalizing the method to apply the diff updates...\n"
|
13
|
-
"Reasoned for 6 seconds\n"
|
14
|
-
"\n"
|
15
|
-
"```diff\n"
|
16
|
-
"--- a/file.py\n"
|
17
|
-
"+++ b/file.py\n"
|
18
|
-
"@@ -1,2 +1,2 @@\n"
|
19
|
-
"-def old():\n"
|
20
|
-
"+def new():\n"
|
21
|
-
"```"
|
22
|
-
)
|
23
|
-
final_content, reasoning = swallow_reasoning(llm_response)
|
24
|
-
expected_reasoning = (
|
25
|
-
"> Reasoning\n"
|
26
|
-
"**Applying the diff**\n"
|
27
|
-
"I'm piecing together how to efficiently apply a diff to a file...\n"
|
28
|
-
"**Returning the result**\n"
|
29
|
-
"I'm finalizing the method to apply the diff updates...\n"
|
30
|
-
"Reasoned for 6 seconds"
|
31
|
-
)
|
32
|
-
assert reasoning == expected_reasoning
|
33
|
-
# The final content should no longer contain the reasoning block.
|
34
|
-
assert expected_reasoning not in final_content
|
35
|
-
# And it should contain the diff block.
|
36
|
-
assert "```diff" in final_content
|
37
|
-
|
38
|
-
|
39
|
-
def test_swallow_reasoning_no_reasoning():
|
40
|
-
llm_response = (
|
41
|
-
"```diff\n"
|
42
|
-
"--- a/file.py\n"
|
43
|
-
"+++ b/file.py\n"
|
44
|
-
"@@ -1,2 +1,2 @@\n"
|
45
|
-
"-def old():\n"
|
46
|
-
"+def new():\n"
|
47
|
-
"```"
|
48
|
-
)
|
49
|
-
final_content, reasoning = swallow_reasoning(llm_response)
|
50
|
-
assert reasoning == ""
|
51
|
-
assert final_content == llm_response.strip()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|