gptdiff 0.1.0__py3-none-any.whl → 0.1.3__py3-none-any.whl

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/gptdiff.py CHANGED
@@ -160,9 +160,9 @@ def call_gpt4_api(system_prompt, user_prompt, files_content, model, temperature=
160
160
  print(user_prompt, "+", len(files_content), "characters of file content")
161
161
 
162
162
  if api_key is None:
163
- api_key = os.getenv('NANOGPT_API_KEY')
163
+ api_key = os.getenv('GPTDIFF_LLM_API_KEY')
164
164
  if base_url is None:
165
- base_url = os.getenv('NANOGPT_BASE_URL', "https://nano-gpt.com/api/v1/")
165
+ base_url = os.getenv('GPTDIFF_LLM_BASE_URL', "https://nano-gpt.com/api/v1/")
166
166
  client = OpenAI(api_key=api_key, base_url=base_url)
167
167
  response = client.chat.completions.create(model=model,
168
168
  messages=messages,
@@ -198,15 +198,17 @@ def build_environment(files_dict):
198
198
  env.append(content)
199
199
  return '\n'.join(env)
200
200
 
201
- def generate_diff(environment, goal, model='deepseek-reasoner', temperature=0.7, max_tokens=32000, api_key=None, base_url=None, prepend=None):
201
+ def generate_diff(environment, goal, model=None, temperature=0.7, max_tokens=32000, api_key=None, base_url=None, prepend=None):
202
202
  """API: Generate diff from environment and goal"""
203
+ if model is None:
204
+ model = os.getenv('GPTDIFF_MODEL', 'deepseek-reasoner')
203
205
  if prepend:
204
206
  prepend = load_prepend_file(args.prepend)
205
207
  print("Including prepend",len(enc.encode(json.dumps(prepend))), "tokens")
206
208
  else:
207
209
  prepend = ""
208
210
 
209
- system_prompt = f"Output a git diff into a <diff> block."
211
+ system_prompt = prepend+f"Output a git diff into a <diff> block."
210
212
  _, diff_text, _, _, _, _ = call_gpt4_api(
211
213
  system_prompt,
212
214
  goal,
@@ -219,7 +221,7 @@ def generate_diff(environment, goal, model='deepseek-reasoner', temperature=0.7,
219
221
  )
220
222
  return diff_text
221
223
 
222
- def smartapply(diff_text, files, model='deepseek-reasoner', api_key=None, base_url=None):
224
+ def smartapply(diff_text, files, model=None, api_key=None, base_url=None):
223
225
  """Applies unified diffs to file contents with AI-powered conflict resolution.
224
226
 
225
227
  Key features:
@@ -254,6 +256,8 @@ def smartapply(diff_text, files, model='deepseek-reasoner', api_key=None, base_u
254
256
  def new():
255
257
  pass
256
258
  """
259
+ if model is None:
260
+ model = os.getenv('GPTDIFF_MODEL', 'deepseek-reasoner')
257
261
  parsed_diffs = parse_diff_per_file(diff_text)
258
262
  print("SMARTAPPLY", diff_text)
259
263
 
@@ -278,7 +282,6 @@ def apply_diff(project_dir, diff_text):
278
282
  with open(diff_file, 'w') as f:
279
283
  f.write(diff_text)
280
284
 
281
- return False
282
285
  result = subprocess.run(["patch", "-p1", "--remove-empty-files", "--input", str(diff_file)], cwd=project_dir, capture_output=True, text=True)
283
286
  if result.returncode != 0:
284
287
  return False
@@ -297,7 +300,7 @@ def parse_arguments():
297
300
  help='Call the GPT-4 API. Writes the full prompt to prompt.txt if not specified.')
298
301
  parser.add_argument('files', nargs='*', default=[], help='Specify additional files or directories to include.')
299
302
  parser.add_argument('--temperature', type=float, default=0.7, help='Temperature parameter for model creativity (0.0 to 2.0)')
300
- parser.add_argument('--model', type=str, default='deepseek-reasoner', help='Model to use for the API call.')
303
+ parser.add_argument('--model', type=str, default=None, help='Model to use for the API call.')
301
304
 
302
305
  parser.add_argument('--nowarn', action='store_true', help='Disable large token warning')
303
306
 
@@ -420,9 +423,9 @@ Diff to apply:
420
423
  ]
421
424
 
422
425
  if api_key is None:
423
- api_key = os.getenv('NANOGPT_API_KEY')
426
+ api_key = os.getenv('GPTDIFF_LLM_API_KEY')
424
427
  if base_url is None:
425
- base_url = os.getenv('NANOGPT_BASE_URL', "https://nano-gpt.com/api/v1/")
428
+ base_url = os.getenv('GPTDIFF_LLM_BASE_URL', "https://nano-gpt.com/api/v1/")
426
429
  client = OpenAI(api_key=api_key, base_url=base_url)
427
430
  response = client.chat.completions.create(model=model,
428
431
  messages=messages,
@@ -496,6 +499,8 @@ def main():
496
499
 
497
500
  full_prompt = f"{system_prompt}\n\n{user_prompt}\n\n{files_content}"
498
501
  token_count = len(enc.encode(full_prompt))
502
+ if args.model is None:
503
+ args.model = os.getenv('GPTDIFF_MODEL', 'deepseek-reasoner')
499
504
 
500
505
  if not args.call and not args.apply:
501
506
  with open('prompt.txt', 'w') as f:
@@ -507,23 +512,23 @@ def main():
507
512
  exit(0)
508
513
  else:
509
514
  # Validate API key presence before any API operations
510
- if not os.getenv('NANOGPT_API_KEY'):
511
- print("\033[1;31mError: NANOGPT_API_KEY environment variable required\033[0m")
512
- print("Set it with: export NANOGPT_API_KEY='your-key'")
515
+ if not os.getenv('GPTDIFF_LLM_API_KEY'):
516
+ print("\033[1;31mError: GPTDIFF_LLM_API_KEY environment variable required\033[0m")
517
+ print("Set it with: export GPTDIFF_LLM_API_KEY='your-key'")
513
518
  sys.exit(1)
514
519
 
515
520
  # Confirm large requests without specified files
516
521
  if (not args.nowarn) and (not args.files) and token_count > 10000 and (args.call or args.apply):
517
- print(f"\033[1;33mThis is a larger request ({token_count} tokens). Are you sure you want to send it? [y/N]\033[0m")
522
+ print(f"\033[1;33mThis is a larger request ({token_count} tokens). Disable this warning with --nowarn. Are you sure you want to send it? [y/N]\033[0m")
518
523
  confirmation = input().strip().lower()
519
524
  if confirmation != 'y':
520
525
  print("Request canceled")
521
526
  sys.exit(0)
522
527
  full_text, diff_text, prompt_tokens, completion_tokens, total_tokens, cost = call_gpt4_api(system_prompt, user_prompt, files_content, args.model,
523
528
  temperature=args.temperature,
524
- api_key=os.getenv('NANOGPT_API_KEY'),
525
- base_url=os.getenv('NANOGPT_BASE_URL', "https://nano-gpt.com/api/v1/")
526
- )
529
+ api_key=os.getenv('GPTDIFF_LLM_API_KEY'),
530
+ base_url=os.getenv('GPTDIFF_LLM_BASE_URL', "https://nano-gpt.com/api/v1/")
531
+ )
527
532
 
528
533
  if(diff_text.strip() == ""):
529
534
  print(f"\033[1;33mThere was no data in this diff. The LLM may have returned something invalid.\033[0m")
@@ -0,0 +1,10 @@
1
+ # We help companies adapt to the AI age through product development and consulting. 255labs.xyz
2
+ This is free and unencumbered software released into the public domain.
3
+
4
+ Copyright 2025 255labs.xyz
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7
+
8
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
+
10
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,273 @@
1
+ Metadata-Version: 2.2
2
+ Name: gptdiff
3
+ Version: 0.1.3
4
+ Summary: A tool to generate and apply git diffs using LLMs
5
+ Author: 255labs
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Operating System :: OS Independent
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE.txt
11
+ Requires-Dist: openai>=1.0.0
12
+ Requires-Dist: tiktoken>=0.5.0
13
+ Requires-Dist: ai_agent_toolbox>=0.1.0
14
+ Provides-Extra: test
15
+ Requires-Dist: pytest; extra == "test"
16
+ Requires-Dist: pytest-mock; extra == "test"
17
+ Provides-Extra: docs
18
+ Requires-Dist: mkdocs; extra == "docs"
19
+ Requires-Dist: mkdocs-material; extra == "docs"
20
+ Dynamic: author
21
+ Dynamic: classifier
22
+ Dynamic: description
23
+ Dynamic: description-content-type
24
+ Dynamic: provides-extra
25
+ Dynamic: requires-dist
26
+ Dynamic: summary
27
+
28
+ # GPTDiff
29
+
30
+ 🚀 **AI-Powered Code Evolution** - Transform your codebase with natural language instructions
31
+
32
+ ```bash
33
+ cd myproject
34
+ gptdiff 'add hover effects to the buttons'
35
+ ```
36
+
37
+ Generates a prompt.txt file that you can copy and paste into a large context gpt to have a conversation with suggested changes. You can also invoke the API and try to directly apply the patch using a smartapply if the git apply fails.
38
+
39
+ ## Value Proposition
40
+
41
+ ```bash
42
+ gptdiff "Update the readme with an api section" --apply
43
+ ```
44
+ <span style="color: #00ff00;">Patch applied successfully.</span>
45
+
46
+ ### Why GPTDiff?
47
+
48
+ - **Understands Your Code** - Describe changes in plain English
49
+ - **Safe Modifications** - Keeps existing code working
50
+ - **Auto-Fix** - `--apply` fixes mistakes in generated changes
51
+ - **Works Instantly** - No complex setup needed
52
+ - **Whole Project View** - Handles multiple files together
53
+
54
+ ## Core Capabilities
55
+
56
+ ### ⚡ CLI Excellence
57
+ - **Target Specific Files** - Change just what you need
58
+ - **Live Updates** - See changes as they're made
59
+ - **Try Before Applying** - Test changes safely first
60
+ - **Clear Pricing** - Know costs upfront
61
+ - **Preview Changes** - See what will change with `--call`
62
+ - **Fix Mistakes** - Automatic error correction
63
+
64
+ ### ✨ Magic Diff Generation
65
+ ```bash
66
+ gptdiff "Convert class components to React hooks" --model deepseek-reasoner
67
+ ```
68
+ - Full project context awareness
69
+ - Cross-file refactoring support
70
+ - Automatic conflict prevention
71
+
72
+ ### 🧠 Smart Apply System
73
+
74
+ **Git-native Workflow:**
75
+ ```bash
76
+ # 1. Apply AI-generated changes
77
+ gptdiff "Improve error handling" --apply
78
+
79
+ # 2. Review each change interactively
80
+ git add -p
81
+
82
+ # 3. Commit or discard
83
+ git commit -m "Enhanced error handling"
84
+ git reset --hard # To undo all changes
85
+ ```
86
+
87
+ ```bash
88
+ gptdiff "Refactor authentication to use OAuth 2.0" --apply
89
+ ```
90
+ <span style="color: #00ff00;">✅ Successfully applied complex changes across 5 files</span>
91
+
92
+ ## Get Started
93
+
94
+ ### Installation
95
+
96
+ Requires Python 3.8+. Install from PyPI:
97
+
98
+ ```bash
99
+ pip install gptdiff
100
+ pip install tiktoken # For token counting
101
+ ```
102
+
103
+ Development install (no pip package yet)
104
+ ```bash
105
+ python setup.py install
106
+ ```
107
+
108
+ ### Configuration
109
+
110
+ First sign up for an API key at https://nano-gpt.com/api and generate your key. Then configure your environment:
111
+
112
+ #### Linux/MacOS
113
+ ```bash
114
+ export GPTDIFF_LLM_API_KEY='your-api-key'
115
+ # Optional: For switching API providers
116
+ export GPTDIFF_MODEL='deepseek-reasoner' # Set default model for all commands
117
+ export GPTDIFF_LLM_BASE_URL='https://nano-gpt.com/api/v1/
118
+ ```
119
+
120
+ #### Windows
121
+ ```cmd
122
+ set GPTDIFF_LLM_API_KEY=your-api-key
123
+ rem Optional: For switching API providers
124
+ set GPTDIFF_MODEL=deepseek-reasoner
125
+ set GPTDIFF_LLM_BASE_URL=https://nano-gpt.com/api/v1/
126
+ ```
127
+
128
+ The default base URL points to nano-gpt.com's API. Supported models can be specified with:
129
+
130
+ ```bash
131
+ gptdiff 'your prompt' --model deepseek-reasoner
132
+ # Default model can be set via GPTDIFF_MODEL environment variable
133
+ ```
134
+
135
+ OpenAI will not be called unless you specify `--call` or `--apply`
136
+
137
+ Prevent files being appended to the prompt by adding them to `.gitignore` or `.gptignore`
138
+
139
+ ### Command Line Usage
140
+
141
+ After installing the package, you can use the `gptdiff` command in your terminal. cd into your codebase and run:
142
+
143
+ ```bash
144
+ gptdiff '<user_prompt>'
145
+ ```
146
+
147
+ any files that are included in .gitignore are ignored when generating prompt.txt.
148
+
149
+ #### Specifying Additional Files
150
+
151
+ You can specify additional files or directories to include in the prompt by adding them as arguments to the `gptdiff` command. If no additional files or directories are specified, the tool will default to using the current working directory.
152
+
153
+ Example usage:
154
+
155
+ ```bash
156
+ gptdiff 'make this change' src test
157
+ ```
158
+
159
+ #### Autopatch Changes
160
+
161
+ You can also call openai and automatically apply the generated git diff with the `--apply` flag:
162
+
163
+ ```bash
164
+ gptdiff '<user_prompt>' --apply
165
+ ```
166
+
167
+ ### Dry-Run Validation
168
+ Preview changes without applying them by omitting the `--apply` flag when using `--call`:
169
+ ```bash
170
+ gptdiff "Modernize database queries" --call
171
+ ```
172
+ <span style="color: #0066cc;">ℹ️ Diff preview generated - review changes before applying</span>
173
+
174
+ This often generates incorrect diffs that need to be manually merged.
175
+
176
+ #### Smart Apply
177
+
178
+ For more reliable patching of complex changes, use `smartapply` which processes each file's diff individually with the LLM:
179
+
180
+ ```bash
181
+ gptdiff 'refactor authentication system' --apply
182
+ ```
183
+
184
+ ### Completion Notification
185
+
186
+ Use the `--nobeep` option to disable the default completion beep:
187
+
188
+ ```bash
189
+ gptdiff '<user_prompt>' --beep
190
+ ```
191
+
192
+ ## Local API Documentation
193
+
194
+ Preview API docs locally using MkDocs:
195
+
196
+ ```bash
197
+ pip install .[docs]
198
+ mkdocs serve
199
+ ```
200
+ Open http://localhost:8000 to view the documentation
201
+
202
+ ## Python API
203
+
204
+ Integrate GPTDiff directly into your Python workflows:
205
+
206
+ ```python
207
+ from gptdiff import generate_diff, smartapply
208
+ import os
209
+
210
+ os.environ['GPTDIFF_LLM_API_KEY'] = 'your-api-key'
211
+
212
+ # Create environment representation
213
+ environment = '''
214
+ File: main.py
215
+ Content:
216
+ def old_name():
217
+ print("Need renaming")
218
+ '''
219
+
220
+ # Generate transformation diff
221
+ diff = generate_diff(
222
+ environment=environment,
223
+ goal='Rename function to new_name()',
224
+ model='deepseek-reasoner'
225
+ )
226
+
227
+ # Apply changes safely
228
+ updated_environment = smartapply(
229
+ diff_text=diff,
230
+ environment_str=environment
231
+ )
232
+
233
+ print("Transformed codebase:")
234
+ print(updated_environment)
235
+ ```
236
+
237
+ **Batch Processing Example:**
238
+ ```python
239
+ from gptdiff import generate_diff, smartapply
240
+
241
+ files = load_your_codebase() # Dict of {path: content}
242
+
243
+ transformations = [
244
+ "Add python type annotations",
245
+ "Convert string formatting to f-strings",
246
+ "Update deprecated API calls"
247
+ ]
248
+
249
+ for task in transformations:
250
+ files = smartapply(generate_diff(build_environment(files), task), files)
251
+ ```
252
+
253
+ **Integration Note:** GPTDiff leverages the [AI Agent Toolbox](https://github.com/255BITS/ai-agent-toolbox) for seamless tool usage across AI models and frameworks, making it ideal for both single responses and complex agent workflows.
254
+
255
+ ### Core Functions
256
+
257
+ - `generate_diff(environment: str, goal: str, model: str) -> str`
258
+ Generates a git diff implementing the requested changes
259
+
260
+ *`model` parameter defaults to `GPTDIFF_MODEL` environment variable*
261
+ - `smartapply(diff_text: str, environment_str: str, model: str) -> str`
262
+ Applies complex diffs while preserving file context
263
+
264
+ ## Testing
265
+
266
+ To run the test suite:
267
+
268
+ ```bash
269
+ pip install -e .[test]
270
+ pytest tests/
271
+ ```
272
+
273
+ This will execute all unit tests verifying core diff generation and application logic.
@@ -0,0 +1,8 @@
1
+ gptdiff/__init__.py,sha256=yGjgwv7tNvH1ZLPsQyoo1CxpTOl1iCAwwDBp-_17ksQ,89
2
+ gptdiff/gptdiff.py,sha256=40LKJt8GfGpk6J0mhQgM88DA6w5QdWmEUXtys1keatk,23253
3
+ gptdiff-0.1.3.dist-info/LICENSE.txt,sha256=zCJk7yUYpMjFvlipi1dKtaljF8WdZ2NASndBYYbU8BY,1228
4
+ gptdiff-0.1.3.dist-info/METADATA,sha256=fNSt-T3KcFGl43bNHcRw-NWyjuV0pqSzPtJSRInCyiw,7316
5
+ gptdiff-0.1.3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
6
+ gptdiff-0.1.3.dist-info/entry_points.txt,sha256=0yvXYEVAZFI-p32kQ4-h3qKVWS0a86jsM9FAwF89t9w,49
7
+ gptdiff-0.1.3.dist-info/top_level.txt,sha256=XNkQkQGINaDndEwRxg8qToOrJ9coyfAb-EHrSUXzdCE,8
8
+ gptdiff-0.1.3.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: gptdiff
3
- Version: 0.1.0
4
- Summary: A tool to generate git diffs using GPT-4
5
- Author: 255labs
6
- Requires-Dist: openai>=1.0.0
7
- Requires-Dist: tiktoken>=0.5.0
8
- Requires-Dist: ai_agent_toolbox>=0.1.0
9
- Provides-Extra: test
10
- Requires-Dist: pytest; extra == "test"
11
- Requires-Dist: pytest-mock; extra == "test"
12
- Provides-Extra: docs
13
- Requires-Dist: mkdocs; extra == "docs"
14
- Requires-Dist: mkdocs-material; extra == "docs"
15
- Dynamic: author
16
- Dynamic: provides-extra
17
- Dynamic: requires-dist
18
- Dynamic: summary
@@ -1,7 +0,0 @@
1
- gptdiff/__init__.py,sha256=yGjgwv7tNvH1ZLPsQyoo1CxpTOl1iCAwwDBp-_17ksQ,89
2
- gptdiff/gptdiff.py,sha256=MBSZgt43Qq3SRqGzlKwBawwIv1Uewm2NaA_DBx_IPB8,22965
3
- gptdiff-0.1.0.dist-info/METADATA,sha256=pf6BzIRLbLCeqVX3u_dwAG91WmPXKmVReTkwUWagPyk,508
4
- gptdiff-0.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
5
- gptdiff-0.1.0.dist-info/entry_points.txt,sha256=0yvXYEVAZFI-p32kQ4-h3qKVWS0a86jsM9FAwF89t9w,49
6
- gptdiff-0.1.0.dist-info/top_level.txt,sha256=XNkQkQGINaDndEwRxg8qToOrJ9coyfAb-EHrSUXzdCE,8
7
- gptdiff-0.1.0.dist-info/RECORD,,