patchling 0.8.1__tar.gz → 0.9.0__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.
Files changed (41) hide show
  1. {patchling-0.8.1 → patchling-0.9.0}/PKG-INFO +17 -26
  2. {patchling-0.8.1 → patchling-0.9.0}/README.md +13 -14
  3. patchling-0.9.0/patchling/__init__.py +61 -0
  4. patchling-0.9.0/patchling/applydiff.py +1017 -0
  5. {patchling-0.8.1 → patchling-0.9.0}/patchling/core.py +433 -55
  6. patchling-0.9.0/patchling/env.py +35 -0
  7. {patchling-0.8.1 → patchling-0.9.0}/patchling/gptpatch.py +2 -2
  8. patchling-0.9.0/patchling/py.typed +0 -0
  9. patchling-0.9.0/patchling/relevance.py +1297 -0
  10. {patchling-0.8.1 → patchling-0.9.0}/patchling.egg-info/PKG-INFO +17 -26
  11. {patchling-0.8.1 → patchling-0.9.0}/patchling.egg-info/SOURCES.txt +13 -1
  12. patchling-0.9.0/pyproject.toml +60 -0
  13. patchling-0.9.0/setup.py +5 -0
  14. patchling-0.9.0/tests/test_argparse_interleaving.py +40 -0
  15. patchling-0.9.0/tests/test_extract_diff_blocks.py +218 -0
  16. patchling-0.9.0/tests/test_live_llm.py +77 -0
  17. patchling-0.9.0/tests/test_packaging.py +34 -0
  18. patchling-0.9.0/tests/test_public_api.py +216 -0
  19. patchling-0.9.0/tests/test_relevance.py +1631 -0
  20. patchling-0.9.0/tests/test_relevance_bench.py +329 -0
  21. patchling-0.9.0/tests/test_relevance_live.py +40 -0
  22. {patchling-0.8.1 → patchling-0.9.0}/tests/test_smartapply.py +7 -3
  23. patchling-0.9.0/tests/test_smartapply_bugs.py +364 -0
  24. patchling-0.8.1/patchling/__init__.py +0 -3
  25. patchling-0.8.1/patchling/applydiff.py +0 -327
  26. patchling-0.8.1/patchling/gptsummarize.py +0 -196
  27. patchling-0.8.1/setup.py +0 -46
  28. {patchling-0.8.1 → patchling-0.9.0}/LICENSE.txt +0 -0
  29. {patchling-0.8.1 → patchling-0.9.0}/patchling.egg-info/dependency_links.txt +0 -0
  30. {patchling-0.8.1 → patchling-0.9.0}/patchling.egg-info/entry_points.txt +0 -0
  31. {patchling-0.8.1 → patchling-0.9.0}/patchling.egg-info/requires.txt +0 -0
  32. {patchling-0.8.1 → patchling-0.9.0}/patchling.egg-info/top_level.txt +0 -0
  33. {patchling-0.8.1 → patchling-0.9.0}/setup.cfg +0 -0
  34. {patchling-0.8.1 → patchling-0.9.0}/tests/test_applydiff.py +0 -0
  35. {patchling-0.8.1 → patchling-0.9.0}/tests/test_applydiff_edgecases.py +0 -0
  36. {patchling-0.8.1 → patchling-0.9.0}/tests/test_diff_parse.py +0 -0
  37. {patchling-0.8.1 → patchling-0.9.0}/tests/test_failing_case.py +0 -0
  38. {patchling-0.8.1 → patchling-0.9.0}/tests/test_multidiff.py +0 -0
  39. {patchling-0.8.1 → patchling-0.9.0}/tests/test_parse_diff_per_file.py +0 -0
  40. {patchling-0.8.1 → patchling-0.9.0}/tests/test_strip_bad_ouput.py +0 -0
  41. {patchling-0.8.1 → patchling-0.9.0}/tests/test_swallow_reasoning.py +0 -0
@@ -1,9 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patchling
3
- Version: 0.8.1
3
+ Version: 0.9.0
4
4
  Summary: Natural-language code transformation as a library: generate unified diffs with LLMs and apply them resiliently with smartapply. Formerly gptdiff.
5
- Home-page: https://github.com/255BITS/patchling-py
6
5
  Author: 255labs
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/255BITS/patchling-py
7
8
  Project-URL: Documentation, https://255bits.github.io/patchling-py
8
9
  Project-URL: Source, https://github.com/255BITS/patchling-py
9
10
  Project-URL: Browser/Node runtime (npm), https://www.npmjs.com/package/patchling
@@ -12,6 +13,7 @@ Keywords: patchling,smartapply,llm,diff,unified-diff,patch,code-transformation,a
12
13
  Classifier: License :: OSI Approved :: MIT License
13
14
  Classifier: Programming Language :: Python :: 3
14
15
  Classifier: Operating System :: OS Independent
16
+ Requires-Python: >=3.10
15
17
  Description-Content-Type: text/markdown
16
18
  License-File: LICENSE.txt
17
19
  Requires-Dist: openai>=1.0.0
@@ -23,17 +25,7 @@ Requires-Dist: pytest-mock; extra == "test"
23
25
  Provides-Extra: docs
24
26
  Requires-Dist: mkdocs; extra == "docs"
25
27
  Requires-Dist: mkdocs-material; extra == "docs"
26
- Dynamic: author
27
- Dynamic: classifier
28
- Dynamic: description
29
- Dynamic: description-content-type
30
- Dynamic: home-page
31
- Dynamic: keywords
32
28
  Dynamic: license-file
33
- Dynamic: project-url
34
- Dynamic: provides-extra
35
- Dynamic: requires-dist
36
- Dynamic: summary
37
29
 
38
30
  # Patchling
39
31
 
@@ -54,15 +46,10 @@ print(updated["main.py"])
54
46
 
55
47
  Files in, files out. No filesystem access required, no agent harness. The hard part — applying an LLM-generated diff that `git apply` would reject — is what `smartapply` solves: per-file, AI-assisted patch resolution that survives fuzzy hunks, renames, new files, and deletions.
56
48
 
57
- 📚 Full documentation at [255bits.github.io/patchling-py](https://255bits.github.io/patchling-py)
49
+ 🌐 Project home: [patchling.app](https://patchling.app) — try it live in your browser · 📚 Full documentation at [255bits.github.io/patchling-py](https://255bits.github.io/patchling-py)
58
50
 
59
- Prefer the browser? **[patchling](https://github.com/255BITS/patchling)** is a JavaScript port of
60
- `generateDiff` + `smartapply` — try the **[live demos →](https://255bits.github.io/patchling-examples/)**.
61
-
62
- > **The patchling family** —
63
- > **patchling** (you are here) ·
64
- > [**patchling**](https://github.com/255BITS/patchling) (browser-first JS port) ·
65
- > [**patchling-examples**](https://github.com/255BITS/patchling-examples) (live browser demos)
51
+ Prefer the browser? The same primitive ships on npm as **[patchling for JS](https://github.com/255BITS/patchling)**
52
+ (`generateDiff` + `smartapply`, zero-dependency ESM) — try the **[live demos →](https://255bits.github.io/patchling-examples/)**.
66
53
 
67
54
  ---
68
55
 
@@ -72,12 +59,13 @@ The same primitive exists for every runtime, and it powers a real product:
72
59
 
73
60
  | Project | What it is |
74
61
  |---------|------------|
75
- | **patchling** (this repo) | Python library + CLI tools — [PyPI](https://pypi.org/project/patchling/) |
76
- | **[patchling](https://github.com/255BITS/patchling)** | Zero-dependency ESM port for browser and Node — `generateDiff` + `smartapply` on in-memory file maps |
62
+ | **patchling for Python** (this repo) | Python library + CLI tools — [PyPI](https://pypi.org/project/patchling/) |
63
+ | **[patchling for JS](https://github.com/255BITS/patchling)** | Zero-dependency ESM package for browser and Node — `generateDiff` + `smartapply` on in-memory file maps — [npm](https://www.npmjs.com/package/patchling) |
64
+ | **[patchling.app](https://patchling.app)** | Project homepage with a live in-browser demo of the whole diff → smartapply loop |
77
65
  | **[nanoodle.com](https://nanoodle.com)** | Visual AI workflow editor built on patchling — no server, no signup, bring your own key. See the primitive working in production |
78
66
  | **[Live demos](https://255bits.github.io/patchling-examples/)** | Browser examples: LLM-edited games, 3D scenes, stream overlays, AI characters |
79
67
 
80
- Building for the browser? Start with [patchling](https://github.com/255BITS/patchling). Building a Python backend, pipeline, or your own agent? You're in the right repo.
68
+ Building for the browser? Start with [patchling for JS](https://github.com/255BITS/patchling). Building a Python backend, pipeline, or your own agent? You're in the right repo.
81
69
 
82
70
  ---
83
71
 
@@ -128,7 +116,8 @@ See [examples/usage_example.py](examples/usage_example.py) for a runnable versio
128
116
 
129
117
  - `generate_diff(environment: str, goal: str, model: str = ...) -> str` — generates a unified diff implementing the goal. `model` defaults to the `GPTDIFF_MODEL` env var.
130
118
  - `smartapply(diff_text: str, files: dict[str, str], model: str = ...) -> dict[str, str]` — applies a diff with AI-powered conflict resolution. Handles new files, deletions, and hunks that standard patching rejects. Returns a new dict; input is not mutated.
131
- - `build_environment(files: dict[str, str]) -> str` — serializes a files dict into the environment string `generate_diff` expects.
119
+ - `build_environment(files: dict[str, str]) -> str` — serializes a files dict into the environment string `generate_diff` expects. Pass `filter_relevant=True` and `task=` to drop files a cheap model marks irrelevant first.
120
+ - `filter_relevant(files, task, model=..., concurrency=..., cache=...) -> FilterRelevantResult` — opt-in relevance filter for large directories. Each file is sent, with the task, to a cheap OpenAI-compatible model that answers yes/no. Only the `yes` files are returned for `generate_diff` and `smartapply`. The default model is `xiaomi/mimo-v2.6-flash` (Flask recall 1.0 and ~0.8x overhead figures are UNVERIFIED). The JS counterpart is `filterRelevant`.
132
121
  - `load_project_files(path, cwd) -> dict` / `save_files(files, base_dir)` — optional filesystem helpers for when you *do* want to read/write a real project (respects `.gitignore` and `.gptignore`).
133
122
 
134
123
  Full signatures, error handling, and edge cases: [API Reference](https://255bits.github.io/patchling-py/api).
@@ -176,6 +165,7 @@ export GPTDIFF_SMARTAPPLY_MODEL='gpt5-mini'
176
165
  | `GPTDIFF_MODEL` | Model for diff generation | `gemini-3-pro-preview` |
177
166
  | `GPTDIFF_SMARTAPPLY_MODEL` | Model for applying diffs | `GPTDIFF_MODEL` |
178
167
  | `GPTDIFF_LLM_BASE_URL` | OpenAI-compatible endpoint | `https://nano-gpt.com/api/v1/` |
168
+ | `GPTDIFF_FILTER_MODEL` | Cheap model for `filter_relevant` | `xiaomi/mimo-v2.6-flash` (Flask recall 1.0 / ~0.8x overhead: UNVERIFIED) |
179
169
 
180
170
  ---
181
171
 
@@ -203,7 +193,7 @@ patchling "Add type hints to all functions" --apply
203
193
  patchling "Add logging" src/api/ src/utils/helpers.py
204
194
  ```
205
195
 
206
- Useful flags: `--model`, `--temperature`, `--prepend <file>` (custom instructions), `--image <path>` (visual context), `--nobeep`. Full list: [CLI Reference](https://255bits.github.io/patchling-py/cli).
196
+ Useful flags: `--model`, `--temperature`, `--prepend <file>` (custom instructions), `--image <path>` (visual context), `--filter-relevant` (ask a cheap model which files to send; `--filter-model` picks that model), `--nobeep`. Full list: [CLI Reference](https://255bits.github.io/patchling-py/cli).
207
197
 
208
198
  Because changes arrive as diffs, the CLI is git-native: review with `git diff`, keep with `git add -p`, discard with `git checkout .`.
209
199
 
@@ -252,7 +242,8 @@ mkdocs serve
252
242
 
253
243
  ## Related projects
254
244
 
255
- - [patchling](https://github.com/255BITS/patchling) — the browser/Node port
245
+ - [patchling.app](https://patchling.app) — project home, with a live in-browser demo
246
+ - [patchling for JS](https://github.com/255BITS/patchling) — the browser/Node package on [npm](https://www.npmjs.com/package/patchling)
256
247
  - [nanoodle.com](https://nanoodle.com) — visual AI workflow editor built on patchling
257
248
  - [patchling live demos](https://255bits.github.io/patchling-examples/)
258
249
  - [AI Agent Toolbox](https://github.com/255BITS/ai-agent-toolbox) — powers Patchling's tool-call parsing across models
@@ -17,15 +17,10 @@ print(updated["main.py"])
17
17
 
18
18
  Files in, files out. No filesystem access required, no agent harness. The hard part — applying an LLM-generated diff that `git apply` would reject — is what `smartapply` solves: per-file, AI-assisted patch resolution that survives fuzzy hunks, renames, new files, and deletions.
19
19
 
20
- 📚 Full documentation at [255bits.github.io/patchling-py](https://255bits.github.io/patchling-py)
20
+ 🌐 Project home: [patchling.app](https://patchling.app) — try it live in your browser · 📚 Full documentation at [255bits.github.io/patchling-py](https://255bits.github.io/patchling-py)
21
21
 
22
- Prefer the browser? **[patchling](https://github.com/255BITS/patchling)** is a JavaScript port of
23
- `generateDiff` + `smartapply` — try the **[live demos →](https://255bits.github.io/patchling-examples/)**.
24
-
25
- > **The patchling family** —
26
- > **patchling** (you are here) ·
27
- > [**patchling**](https://github.com/255BITS/patchling) (browser-first JS port) ·
28
- > [**patchling-examples**](https://github.com/255BITS/patchling-examples) (live browser demos)
22
+ Prefer the browser? The same primitive ships on npm as **[patchling for JS](https://github.com/255BITS/patchling)**
23
+ (`generateDiff` + `smartapply`, zero-dependency ESM) — try the **[live demos →](https://255bits.github.io/patchling-examples/)**.
29
24
 
30
25
  ---
31
26
 
@@ -35,12 +30,13 @@ The same primitive exists for every runtime, and it powers a real product:
35
30
 
36
31
  | Project | What it is |
37
32
  |---------|------------|
38
- | **patchling** (this repo) | Python library + CLI tools — [PyPI](https://pypi.org/project/patchling/) |
39
- | **[patchling](https://github.com/255BITS/patchling)** | Zero-dependency ESM port for browser and Node — `generateDiff` + `smartapply` on in-memory file maps |
33
+ | **patchling for Python** (this repo) | Python library + CLI tools — [PyPI](https://pypi.org/project/patchling/) |
34
+ | **[patchling for JS](https://github.com/255BITS/patchling)** | Zero-dependency ESM package for browser and Node — `generateDiff` + `smartapply` on in-memory file maps — [npm](https://www.npmjs.com/package/patchling) |
35
+ | **[patchling.app](https://patchling.app)** | Project homepage with a live in-browser demo of the whole diff → smartapply loop |
40
36
  | **[nanoodle.com](https://nanoodle.com)** | Visual AI workflow editor built on patchling — no server, no signup, bring your own key. See the primitive working in production |
41
37
  | **[Live demos](https://255bits.github.io/patchling-examples/)** | Browser examples: LLM-edited games, 3D scenes, stream overlays, AI characters |
42
38
 
43
- Building for the browser? Start with [patchling](https://github.com/255BITS/patchling). Building a Python backend, pipeline, or your own agent? You're in the right repo.
39
+ Building for the browser? Start with [patchling for JS](https://github.com/255BITS/patchling). Building a Python backend, pipeline, or your own agent? You're in the right repo.
44
40
 
45
41
  ---
46
42
 
@@ -91,7 +87,8 @@ See [examples/usage_example.py](examples/usage_example.py) for a runnable versio
91
87
 
92
88
  - `generate_diff(environment: str, goal: str, model: str = ...) -> str` — generates a unified diff implementing the goal. `model` defaults to the `GPTDIFF_MODEL` env var.
93
89
  - `smartapply(diff_text: str, files: dict[str, str], model: str = ...) -> dict[str, str]` — applies a diff with AI-powered conflict resolution. Handles new files, deletions, and hunks that standard patching rejects. Returns a new dict; input is not mutated.
94
- - `build_environment(files: dict[str, str]) -> str` — serializes a files dict into the environment string `generate_diff` expects.
90
+ - `build_environment(files: dict[str, str]) -> str` — serializes a files dict into the environment string `generate_diff` expects. Pass `filter_relevant=True` and `task=` to drop files a cheap model marks irrelevant first.
91
+ - `filter_relevant(files, task, model=..., concurrency=..., cache=...) -> FilterRelevantResult` — opt-in relevance filter for large directories. Each file is sent, with the task, to a cheap OpenAI-compatible model that answers yes/no. Only the `yes` files are returned for `generate_diff` and `smartapply`. The default model is `xiaomi/mimo-v2.6-flash` (Flask recall 1.0 and ~0.8x overhead figures are UNVERIFIED). The JS counterpart is `filterRelevant`.
95
92
  - `load_project_files(path, cwd) -> dict` / `save_files(files, base_dir)` — optional filesystem helpers for when you *do* want to read/write a real project (respects `.gitignore` and `.gptignore`).
96
93
 
97
94
  Full signatures, error handling, and edge cases: [API Reference](https://255bits.github.io/patchling-py/api).
@@ -139,6 +136,7 @@ export GPTDIFF_SMARTAPPLY_MODEL='gpt5-mini'
139
136
  | `GPTDIFF_MODEL` | Model for diff generation | `gemini-3-pro-preview` |
140
137
  | `GPTDIFF_SMARTAPPLY_MODEL` | Model for applying diffs | `GPTDIFF_MODEL` |
141
138
  | `GPTDIFF_LLM_BASE_URL` | OpenAI-compatible endpoint | `https://nano-gpt.com/api/v1/` |
139
+ | `GPTDIFF_FILTER_MODEL` | Cheap model for `filter_relevant` | `xiaomi/mimo-v2.6-flash` (Flask recall 1.0 / ~0.8x overhead: UNVERIFIED) |
142
140
 
143
141
  ---
144
142
 
@@ -166,7 +164,7 @@ patchling "Add type hints to all functions" --apply
166
164
  patchling "Add logging" src/api/ src/utils/helpers.py
167
165
  ```
168
166
 
169
- Useful flags: `--model`, `--temperature`, `--prepend <file>` (custom instructions), `--image <path>` (visual context), `--nobeep`. Full list: [CLI Reference](https://255bits.github.io/patchling-py/cli).
167
+ Useful flags: `--model`, `--temperature`, `--prepend <file>` (custom instructions), `--image <path>` (visual context), `--filter-relevant` (ask a cheap model which files to send; `--filter-model` picks that model), `--nobeep`. Full list: [CLI Reference](https://255bits.github.io/patchling-py/cli).
170
168
 
171
169
  Because changes arrive as diffs, the CLI is git-native: review with `git diff`, keep with `git add -p`, discard with `git checkout .`.
172
170
 
@@ -215,7 +213,8 @@ mkdocs serve
215
213
 
216
214
  ## Related projects
217
215
 
218
- - [patchling](https://github.com/255BITS/patchling) — the browser/Node port
216
+ - [patchling.app](https://patchling.app) — project home, with a live in-browser demo
217
+ - [patchling for JS](https://github.com/255BITS/patchling) — the browser/Node package on [npm](https://www.npmjs.com/package/patchling)
219
218
  - [nanoodle.com](https://nanoodle.com) — visual AI workflow editor built on patchling
220
219
  - [patchling live demos](https://255bits.github.io/patchling-examples/)
221
220
  - [AI Agent Toolbox](https://github.com/255BITS/ai-agent-toolbox) — powers Patchling's tool-call parsing across models
@@ -0,0 +1,61 @@
1
+ """Natural-language diffs and resilient patch application.
2
+
3
+ Public names mirror 255BITS/patchling (the JavaScript package) in snake_case.
4
+ Existing names such as ``generate_diff`` and ``smartapply`` stay in place.
5
+ """
6
+
7
+ from .applydiff import apply_diff, extract_diff_blocks, parse_diff_per_file
8
+ from .core import (
9
+ SmartApplyError,
10
+ build_environment,
11
+ call_llm,
12
+ call_llm_for_diff,
13
+ color_code_diff,
14
+ generate_diff,
15
+ load_project_files,
16
+ resolve_api_key,
17
+ resolve_base_url,
18
+ save_files,
19
+ smartapply,
20
+ strip_bad_output,
21
+ strip_think_tags,
22
+ swallow_reasoning,
23
+ )
24
+ from .env import DEFAULT_BASE_URL, DEFAULT_MODEL, get_env, set_env
25
+ from .relevance import (
26
+ FilterRelevantResult,
27
+ RelevanceCache,
28
+ RelevanceDecision,
29
+ filter_relevant,
30
+ )
31
+
32
+ __version__ = "0.9.0"
33
+
34
+ __all__ = [
35
+ "__version__",
36
+ "DEFAULT_BASE_URL",
37
+ "DEFAULT_MODEL",
38
+ "FilterRelevantResult",
39
+ "RelevanceCache",
40
+ "RelevanceDecision",
41
+ "SmartApplyError",
42
+ "apply_diff",
43
+ "build_environment",
44
+ "call_llm",
45
+ "call_llm_for_diff",
46
+ "color_code_diff",
47
+ "extract_diff_blocks",
48
+ "filter_relevant",
49
+ "generate_diff",
50
+ "get_env",
51
+ "load_project_files",
52
+ "parse_diff_per_file",
53
+ "resolve_api_key",
54
+ "resolve_base_url",
55
+ "save_files",
56
+ "set_env",
57
+ "smartapply",
58
+ "strip_bad_output",
59
+ "strip_think_tags",
60
+ "swallow_reasoning",
61
+ ]