From a7b108a0e9f39eafcf8e046dc0269e476d9c8424 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Tue, 13 Aug 2024 13:47:59 -0700 Subject: [PATCH 001/105] feat: Change x-axis to show version number --- aider/website/_includes/blame.md | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/aider/website/_includes/blame.md b/aider/website/_includes/blame.md index d3fbbacdf..d4d2d5a09 100644 --- a/aider/website/_includes/blame.md +++ b/aider/website/_includes/blame.md @@ -6,49 +6,31 @@ document.addEventListener('DOMContentLoaded', function () { var ctx = document.getElementById('blameChart').getContext('2d'); var blameData = { + labels: [{% for row in site.data.blame %}'{{ row.end_tag }}',{% endfor %}], datasets: [{ label: 'Aider\'s Contribution to Each Release', - data: [ - {% for row in site.data.blame %} - { - x: '{{ row.end_date }}', - y: {{ row.aider_percentage }}, - r: Math.sqrt({{ row.aider_total }}) * 1.5, - label: '{{ row.end_tag }}', - percentage: {{ row.aider_percentage }}, - lines: {{ row.aider_total }} - }, - {% endfor %} - ], - backgroundColor: 'rgba(54, 162, 235, 0.2)', + data: [{% for row in site.data.blame %}{{ row.aider_percentage }},{% endfor %}], + backgroundColor: 'rgba(54, 162, 235, 0.8)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1 }] }; var blameChart = new Chart(ctx, { - type: 'bubble', + type: 'bar', data: blameData, options: { scales: { x: { - type: 'time', - time: { - unit: 'month', - displayFormats: { - month: 'MMM YYYY' - } - }, + type: 'category', title: { display: true, - text: 'Release date' + text: 'Version' }, ticks: { maxRotation: 45, minRotation: 45 - }, - min: moment('{{ site.data.blame | first | map: "end_date" | first }}').subtract(1, 'month'), - max: moment('{{ site.data.blame | last | map: "end_date" | first }}').add(1, 'month') + } }, y: { title: { From b38b92dbbcfe10b78fad4056f1af5cf40ccbf6b6 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Tue, 13 Aug 2024 13:52:56 -0700 Subject: [PATCH 002/105] fix: Update tooltip callback to display correct data --- aider/website/_includes/blame.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aider/website/_includes/blame.md b/aider/website/_includes/blame.md index d4d2d5a09..12903c33c 100644 --- a/aider/website/_includes/blame.md +++ b/aider/website/_includes/blame.md @@ -44,7 +44,10 @@ document.addEventListener('DOMContentLoaded', function () { tooltip: { callbacks: { label: function(context) { - return `${context.raw.label}: ${Math.round(context.raw.percentage)}% (${context.raw.lines} lines)`; + var label = context.dataset.label || ''; + var value = context.parsed.y || 0; + var lines = context.raw || 0; + return `${label}: ${Math.round(value)}% (${lines} lines)`; } } }, From 34fbf5252ee298c99b9b41ae616115237cd3c008 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Tue, 13 Aug 2024 14:05:16 -0700 Subject: [PATCH 003/105] fix: Add console.log statement to debug tooltip label --- aider/website/_includes/blame.md | 1 + 1 file changed, 1 insertion(+) diff --git a/aider/website/_includes/blame.md b/aider/website/_includes/blame.md index 12903c33c..4e1b60d1e 100644 --- a/aider/website/_includes/blame.md +++ b/aider/website/_includes/blame.md @@ -44,6 +44,7 @@ document.addEventListener('DOMContentLoaded', function () { tooltip: { callbacks: { label: function(context) { + console.log(context); var label = context.dataset.label || ''; var value = context.parsed.y || 0; var lines = context.raw || 0; From 99d7c7983f5bac75abc7a21f5c6d591e656cb2cc Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Tue, 13 Aug 2024 14:05:17 -0700 Subject: [PATCH 004/105] feat: Add aider_total to tooltip --- aider/website/_includes/blame.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/aider/website/_includes/blame.md b/aider/website/_includes/blame.md index 4e1b60d1e..bbd354938 100644 --- a/aider/website/_includes/blame.md +++ b/aider/website/_includes/blame.md @@ -9,7 +9,7 @@ document.addEventListener('DOMContentLoaded', function () { labels: [{% for row in site.data.blame %}'{{ row.end_tag }}',{% endfor %}], datasets: [{ label: 'Aider\'s Contribution to Each Release', - data: [{% for row in site.data.blame %}{{ row.aider_percentage }},{% endfor %}], + data: [{% for row in site.data.blame %}{ x: '{{ row.end_tag }}', y: {{ row.aider_percentage }}, lines: {{ row.aider_total }} },{% endfor %}], backgroundColor: 'rgba(54, 162, 235, 0.8)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1 @@ -44,10 +44,9 @@ document.addEventListener('DOMContentLoaded', function () { tooltip: { callbacks: { label: function(context) { - console.log(context); var label = context.dataset.label || ''; var value = context.parsed.y || 0; - var lines = context.raw || 0; + var lines = context.raw.lines || 0; return `${label}: ${Math.round(value)}% (${lines} lines)`; } } From 44739409d52d2ffe7acf117609d73b478013b4e8 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Tue, 13 Aug 2024 14:11:05 -0700 Subject: [PATCH 005/105] fix: Update blame.md to improve tooltip and label text --- aider/website/_includes/blame.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aider/website/_includes/blame.md b/aider/website/_includes/blame.md index bbd354938..62601dc0f 100644 --- a/aider/website/_includes/blame.md +++ b/aider/website/_includes/blame.md @@ -44,7 +44,7 @@ document.addEventListener('DOMContentLoaded', function () { tooltip: { callbacks: { label: function(context) { - var label = context.dataset.label || ''; + var label = 'Aider\'s contribution'; var value = context.parsed.y || 0; var lines = context.raw.lines || 0; return `${label}: ${Math.round(value)}% (${lines} lines)`; @@ -57,7 +57,7 @@ document.addEventListener('DOMContentLoaded', function () { labels: { generateLabels: function(chart) { return [{ - text: 'Y-axis is percent of code, bubble size is lines of code', + text: 'Percent of new code written', fillStyle: 'rgba(54, 162, 235, 0.2)', strokeStyle: 'rgba(54, 162, 235, 1)', lineWidth: 1, From 4ea4fb47938fa346b333233d1f6d92ff0ac8d82b Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Tue, 13 Aug 2024 14:11:06 -0700 Subject: [PATCH 006/105] feat: Add a new bar chart to plot the aider_total number of lines by release --- aider/website/_includes/blame.md | 83 ++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/aider/website/_includes/blame.md b/aider/website/_includes/blame.md index 62601dc0f..4dc0fc3d9 100644 --- a/aider/website/_includes/blame.md +++ b/aider/website/_includes/blame.md @@ -1,12 +1,17 @@ + From 38700b68d24177d26e918f3516fde90193354f78 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Tue, 13 Aug 2024 14:18:01 -0700 Subject: [PATCH 007/105] fix: Update chart labels and titles for better clarity --- aider/website/_includes/blame.md | 46 +++++--------------------------- 1 file changed, 7 insertions(+), 39 deletions(-) diff --git a/aider/website/_includes/blame.md b/aider/website/_includes/blame.md index 4dc0fc3d9..4eb96f08c 100644 --- a/aider/website/_includes/blame.md +++ b/aider/website/_includes/blame.md @@ -13,7 +13,7 @@ document.addEventListener('DOMContentLoaded', function () { var blameData = { labels: labels, datasets: [{ - label: 'Aider\'s Contribution to Each Release', + label: 'Aider\'s percent of new code by release', data: [{% for row in site.data.blame %}{ x: '{{ row.end_tag }}', y: {{ row.aider_percentage }}, lines: {{ row.aider_total }} },{% endfor %}], backgroundColor: 'rgba(54, 162, 235, 0.8)', borderColor: 'rgba(54, 162, 235, 1)', @@ -24,7 +24,7 @@ document.addEventListener('DOMContentLoaded', function () { var linesData = { labels: labels, datasets: [{ - label: 'Aider\'s Total Lines of Code', + label: 'Aider\'s lines of new code', data: [{% for row in site.data.blame %}{ x: '{{ row.end_tag }}', y: {{ row.aider_total }} },{% endfor %}], backgroundColor: 'rgba(255, 99, 132, 0.8)', borderColor: 'rgba(255, 99, 132, 1)', @@ -51,7 +51,7 @@ document.addEventListener('DOMContentLoaded', function () { y: { title: { display: true, - text: 'Aider Contribution (% of code)' + text: 'Percent of new code' }, beginAtZero: true } @@ -67,25 +67,9 @@ document.addEventListener('DOMContentLoaded', function () { } } }, - legend: { - display: true, - position: 'top', - labels: { - generateLabels: function(chart) { - return [{ - text: 'Percent of new code written', - fillStyle: 'rgba(54, 162, 235, 0.2)', - strokeStyle: 'rgba(54, 162, 235, 1)', - lineWidth: 1, - hidden: false, - index: 0 - }]; - } - } - }, title: { display: true, - text: 'Aider\'s Contribution to Each Release', + text: 'Percent of new code written by aider, by release', font: { size: 16 } @@ -113,7 +97,7 @@ document.addEventListener('DOMContentLoaded', function () { y: { title: { display: true, - text: 'Total Lines of Code' + text: 'Lines of new code' }, beginAtZero: true } @@ -122,31 +106,15 @@ document.addEventListener('DOMContentLoaded', function () { tooltip: { callbacks: { label: function(context) { - var label = 'Aider\'s total lines'; + var label = 'New lines of code by aider'; var value = context.parsed.y || 0; return `${label}: ${value}`; } } }, - legend: { - display: true, - position: 'top', - labels: { - generateLabels: function(chart) { - return [{ - text: 'Total lines of code written', - fillStyle: 'rgba(255, 99, 132, 0.2)', - strokeStyle: 'rgba(255, 99, 132, 1)', - lineWidth: 1, - hidden: false, - index: 0 - }]; - } - } - }, title: { display: true, - text: 'Aider\'s Total Lines of Code by Release', + text: 'Lines of new code written by aider, by release', font: { size: 16 } From 8c4458413821e12e6dd8952f775ad7d49ad67343 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Tue, 13 Aug 2024 14:18:02 -0700 Subject: [PATCH 008/105] feat: Hide legends for both charts --- aider/website/_includes/blame.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aider/website/_includes/blame.md b/aider/website/_includes/blame.md index 4eb96f08c..d7ca0877f 100644 --- a/aider/website/_includes/blame.md +++ b/aider/website/_includes/blame.md @@ -57,6 +57,9 @@ document.addEventListener('DOMContentLoaded', function () { } }, plugins: { + legend: { + display: false + }, tooltip: { callbacks: { label: function(context) { @@ -103,6 +106,9 @@ document.addEventListener('DOMContentLoaded', function () { } }, plugins: { + legend: { + display: false + }, tooltip: { callbacks: { label: function(context) { From 4f54ed5abd6831a6cff3436e921cb0676589bbbb Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Tue, 13 Aug 2024 14:18:37 -0700 Subject: [PATCH 009/105] feat: Reduce chart height by 20% --- aider/website/_includes/blame.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aider/website/_includes/blame.md b/aider/website/_includes/blame.md index d7ca0877f..3973ea812 100644 --- a/aider/website/_includes/blame.md +++ b/aider/website/_includes/blame.md @@ -1,5 +1,5 @@ - - + + From 8115cbbd3adc7b4cbbd7dbd1ed70aa41914c1e18 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Tue, 13 Aug 2024 14:20:45 -0700 Subject: [PATCH 010/105] copy --- aider/website/assets/blame.jpg | Bin 65930 -> 161825 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/aider/website/assets/blame.jpg b/aider/website/assets/blame.jpg index c9312fd704a8587b20aabad958984ad77724557d..95b959720080e95ea6a4dba2ca415205a0136bf8 100644 GIT binary patch literal 161825 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�AGGDS+;(RAt? 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 literal 65930 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
U|$=c`OZ?{6b^%H*EA8Nwq{!)D0ZT&`1 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 Date: Tue, 13 Aug 2024 17:31:27 -0700 Subject: [PATCH 011/105] fix: Handle exceptions in the send method of base_coder.py --- aider/coders/base_coder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index da386a197..3fdc12260 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -1244,6 +1244,7 @@ class Coder: self.io.log_llm_history("TO LLM", format_messages(messages)) + completion = None try: hash_object, completion = send_completion( model.name, @@ -1263,6 +1264,8 @@ class Coder: except KeyboardInterrupt as kbi: self.keyboard_interrupt() raise kbi + except Exception as e: + self.io.tool_error(f"Error during API call: {str(e)}") finally: self.io.log_llm_history( "LLM RESPONSE", From 139f7992cbe89312a548198524870ed68713ff1c Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Tue, 13 Aug 2024 17:43:41 -0700 Subject: [PATCH 012/105] do not pass pretty to coder --- benchmark/benchmark.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/benchmark/benchmark.py b/benchmark/benchmark.py index 6261e00f9..d3c61dedd 100755 --- a/benchmark/benchmark.py +++ b/benchmark/benchmark.py @@ -378,7 +378,7 @@ def summarize_results(dirname): pass_rate = 100 * passed_tests[i] / res.completed_tests percents[i] = pass_rate # console.print(f"{pass_rate:.1f}% correct after try {i+1}") - setattr(res, f"pass_rate_{i+1}", f"{pass_rate:.1f}") + setattr(res, f"pass_rate_{i + 1}", f"{pass_rate:.1f}") print(f"- dirname: {dirname.name}") style = None if res.completed_tests in NUM_TESTS else "red" @@ -393,10 +393,10 @@ def summarize_results(dirname): console.print(f" {key}: {val}", style=style) for i in range(tries): - print(f" pass_rate_{i+1}: {percents[i]:.1f}") + print(f" pass_rate_{i + 1}: {percents[i]:.1f}") pct_well_formed = 1.0 - res.num_with_malformed_responses / res.completed_tests - print(f" percent_cases_well_formed: {pct_well_formed*100:.1f}") + print(f" percent_cases_well_formed: {pct_well_formed * 100:.1f}") show("error_outputs") show("num_malformed_responses") @@ -564,7 +564,6 @@ def run_test_real( fnames=fnames, use_git=False, stream=False, - pretty=False, verbose=verbose, ) coder.max_apply_update_errors = max_apply_update_errors From 277c8b32a71fec16c312ea3522769b5f0a05efd3 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Tue, 13 Aug 2024 17:52:54 -0700 Subject: [PATCH 013/105] copy --- aider/website/docs/usage/images-urls.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/website/docs/usage/images-urls.md b/aider/website/docs/usage/images-urls.md index 2cecfdef6..b3fb6797a 100644 --- a/aider/website/docs/usage/images-urls.md +++ b/aider/website/docs/usage/images-urls.md @@ -23,7 +23,7 @@ You can add images to the chat just like you would add any other file: - Use `/add ` from within the chat -- Use `/add-clipboard-image` to paste an image from your clipboard into the chat. +- Use `/clipboard` to paste an image from your clipboard into the chat. - Launch aider with image filenames on the command line: `aider ` along with any other command line arguments you need. ## Web pages From 060c8ff89ad6677bf69b6eb5b53f9a3e3ab94c94 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Tue, 13 Aug 2024 18:06:00 -0700 Subject: [PATCH 014/105] override dotenv --- benchmark/benchmark.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmark/benchmark.py b/benchmark/benchmark.py index d3c61dedd..61f9bf1c4 100755 --- a/benchmark/benchmark.py +++ b/benchmark/benchmark.py @@ -28,8 +28,6 @@ from aider.coders import Coder from aider.dump import dump # noqa: F401 from aider.io import InputOutput -load_dotenv() - BENCHMARK_DNAME = Path(os.environ.get("AIDER_BENCHMARK_DIR", "tmp.benchmarks")) EXERCISES_DIR_DEFAULT = "exercism-python" @@ -39,6 +37,8 @@ app = typer.Typer(add_completion=False, pretty_exceptions_enable=False) NUM_TESTS = (89, 133) +load_dotenv(override=True) + def show_stats(dirnames, graphs): raw_rows = [] @@ -590,7 +590,7 @@ def run_test_real( coder.apply_updates() else: - response = coder.run(with_message=instructions) + response = coder.run(with_message=instructions, preproc=False) dur += time.time() - start if not no_aider: From 37512a532a9d96d2cb9d3293616149b342d8673b Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Tue, 13 Aug 2024 18:44:00 -0700 Subject: [PATCH 015/105] copy --- HISTORY.md | 4 ++++ aider/website/HISTORY.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 2807e037d..6a520a8c2 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,10 @@ # Release history +### Aider v0.50.1 + +- Bugfix for provider API exceptions. + ### Aider v0.50.0 - Infinite output for DeepSeek Coder, Mistral models in addition to Anthropic's models. diff --git a/aider/website/HISTORY.md b/aider/website/HISTORY.md index d70bde900..96420b06a 100644 --- a/aider/website/HISTORY.md +++ b/aider/website/HISTORY.md @@ -16,6 +16,10 @@ cog.out(text) # Release history +### Aider v0.50.1 + +- Bugfix for provider API exceptions. + ### Aider v0.50.0 - Infinite output for DeepSeek Coder, Mistral models in addition to Anthropic's models. From 044687cd99baaa77d7fab035264f8991f24dba64 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Tue, 13 Aug 2024 18:47:55 -0700 Subject: [PATCH 016/105] version bump to 0.50.1 --- aider/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/__init__.py b/aider/__init__.py index 41d36926a..834178665 100644 --- a/aider/__init__.py +++ b/aider/__init__.py @@ -1 +1 @@ -__version__ = "0.50.1-dev" +__version__ = "0.50.1" From c84759d875e319dcfe9c84b89fe1e4a55c79319e Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Tue, 13 Aug 2024 18:49:54 -0700 Subject: [PATCH 017/105] set version to 0.50.2-dev --- aider/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/__init__.py b/aider/__init__.py index 834178665..a7d6d6205 100644 --- a/aider/__init__.py +++ b/aider/__init__.py @@ -1 +1 @@ -__version__ = "0.50.1" +__version__ = "0.50.2-dev" From b1c376981380f38faa9f308c5e6c072492c27476 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Tue, 13 Aug 2024 18:51:33 -0700 Subject: [PATCH 018/105] editblock prompt improvement to better edit code in json wrapped formats like ipynb Confirmed improvements on basic edits to a .ipynb file. Confirmed no regressions against latest deepseek coder, sonnet, gpt-4o. --- aider/coders/editblock_prompts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aider/coders/editblock_prompts.py b/aider/coders/editblock_prompts.py index af3e4f3b7..7a2acdae9 100644 --- a/aider/coders/editblock_prompts.py +++ b/aider/coders/editblock_prompts.py @@ -125,8 +125,8 @@ Every *SEARCH/REPLACE block* must use this format: 7. The end of the replace block: >>>>>>> REPLACE 8. The closing fence: {fence[1]} -Every *SEARCH* section must *EXACTLY MATCH* the existing source code, character for character, including all comments, docstrings, etc. - +Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc. +If the file contains code or other data wrapped/escaped in json/xml/quotes or other containers, you need to propose edits to the literal contents of the file, including the container markup. *SEARCH/REPLACE* blocks will replace *all* matching occurrences. Include enough lines to make the SEARCH blocks uniquely match the lines to change. From bcedaebe57cefd192317cf620c577a22e9e66c06 Mon Sep 17 00:00:00 2001 From: pcamp Date: Wed, 14 Aug 2024 04:22:04 -0500 Subject: [PATCH 019/105] Fix typo in config.md --- aider/website/docs/config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/website/docs/config.md b/aider/website/docs/config.md index 40087c936..3b192c432 100644 --- a/aider/website/docs/config.md +++ b/aider/website/docs/config.md @@ -28,7 +28,7 @@ Using a `.aider.conf.yml` file: dark-mode: true ``` -By setting an environgment variable: +By setting an environment variable: ``` export AIDER_DARK_MODE=true From 454408f9d58b7f4260fea9c94062792081c6ca3c Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 06:11:45 -0700 Subject: [PATCH 020/105] Added chatgpt-4o-latest --- aider/website/_data/edit_leaderboard.yml | 23 +++++++++++++++++++++++ aider/website/docs/leaderboards/index.md | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/aider/website/_data/edit_leaderboard.yml b/aider/website/_data/edit_leaderboard.yml index 52f667849..72dd9c96b 100644 --- a/aider/website/_data/edit_leaderboard.yml +++ b/aider/website/_data/edit_leaderboard.yml @@ -843,4 +843,27 @@ versions: 0.48.1-dev seconds_per_case: 6.5 total_cost: 0.0000 + +- dirname: 2024-08-14-13-07-12--chatgpt-4o-latest-diff + test_cases: 133 + model: chatgpt-4o-latest + edit_format: diff + commit_hash: b1c3769 + pass_rate_1: 53.4 + pass_rate_2: 69.2 + percent_cases_well_formed: 97.7 + error_outputs: 27 + num_malformed_responses: 5 + num_with_malformed_responses: 3 + user_asks: 7 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openai/chatgpt-4o-latest + date: 2024-08-14 + versions: 0.50.2-dev + seconds_per_case: 26.3 + total_cost: 3.6113 \ No newline at end of file diff --git a/aider/website/docs/leaderboards/index.md b/aider/website/docs/leaderboards/index.md index 3efa40e8b..5e4255bdc 100644 --- a/aider/website/docs/leaderboards/index.md +++ b/aider/website/docs/leaderboards/index.md @@ -321,6 +321,6 @@ mod_dates = [get_last_modified_date(file) for file in files] latest_mod_date = max(mod_dates) cog.out(f"{latest_mod_date.strftime('%B %d, %Y.')}") ]]]--> -August 10, 2024. +August 14, 2024.

From 56975d02a16202502b17fc2257295bef5719279a Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 06:20:31 -0700 Subject: [PATCH 021/105] fix: Update path to edit_leaderboard.yml file --- benchmark/over_time.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index 0ea641d64..1c20dc336 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -2,7 +2,7 @@ import matplotlib.pyplot as plt import yaml from imgcat import imgcat from matplotlib import rc - +from aider.dump import dump # noqa: 401 def plot_over_time(yaml_file): with open(yaml_file, "r") as file: @@ -57,4 +57,4 @@ def plot_over_time(yaml_file): # Example usage -plot_over_time("_data/edit_leaderboard.yml") +plot_over_time("aider/website/_data/edit_leaderboard.yml") From d2479f30f76f178bed794db9cc96b064206878a2 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 06:20:32 -0700 Subject: [PATCH 022/105] fix: Add debug prints and check for empty data in over_time.py --- benchmark/over_time.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index 1c20dc336..6143c0ece 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -12,11 +12,23 @@ def plot_over_time(yaml_file): pass_rates = [] models = [] + print("Debug: Raw data from YAML file:") + print(data) + for entry in data: if "released" in entry and "pass_rate_2" in entry: dates.append(entry["released"]) pass_rates.append(entry["pass_rate_2"]) models.append(entry["model"].split("(")[0].strip()) + + print("Debug: Processed data:") + print("Dates:", dates) + print("Pass rates:", pass_rates) + print("Models:", models) + + if not dates or not pass_rates: + print("Error: No data to plot. Check if the YAML file is empty or if the data is in the expected format.") + return plt.rcParams["hatch.linewidth"] = 0.5 plt.rcParams["hatch.color"] = "#444444" From d94d5aa3fa88dcf56a350d5c0a8cb041fda9508b Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 06:20:36 -0700 Subject: [PATCH 023/105] style: format code according to linter rules --- benchmark/over_time.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index 6143c0ece..f073ad9eb 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -2,7 +2,9 @@ import matplotlib.pyplot as plt import yaml from imgcat import imgcat from matplotlib import rc -from aider.dump import dump # noqa: 401 + +from aider.dump import dump # noqa: 401 + def plot_over_time(yaml_file): with open(yaml_file, "r") as file: @@ -20,14 +22,17 @@ def plot_over_time(yaml_file): dates.append(entry["released"]) pass_rates.append(entry["pass_rate_2"]) models.append(entry["model"].split("(")[0].strip()) - + print("Debug: Processed data:") print("Dates:", dates) print("Pass rates:", pass_rates) print("Models:", models) if not dates or not pass_rates: - print("Error: No data to plot. Check if the YAML file is empty or if the data is in the expected format.") + print( + "Error: No data to plot. Check if the YAML file is empty or if the data is in the" + " expected format." + ) return plt.rcParams["hatch.linewidth"] = 0.5 @@ -58,7 +63,9 @@ def plot_over_time(yaml_file): ) ax.set_xlabel("Model release date", fontsize=18, color="#555") - ax.set_ylabel("Aider code editing benchmark,\npercent completed correctly", fontsize=18, color="#555") + ax.set_ylabel( + "Aider code editing benchmark,\npercent completed correctly", fontsize=18, color="#555" + ) ax.set_title("LLM code editing skill by model release date", fontsize=20) ax.set_ylim(0, 30) plt.xticks(fontsize=14) From d8c8c51156d89bff3cc4d4be69ef09f40655960b Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 06:21:45 -0700 Subject: [PATCH 024/105] The commit message for these changes would be: feat: Improve graph visualization and add debugging The changes made in this commit include: 1. Adjusting the y-axis limit to 100 to accommodate the higher pass rate values. 2. Rotating the x-axis labels for better readability. 3. Adding debug print statements to track the progress of figure generation and display. 4. Increasing the figure size for better visibility. 5. Adding additional debugging to ensure the data is being plotted correctly. These improvements should help with the visualization and debugging of the graph generation process. --- benchmark/over_time.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index f073ad9eb..2e04c7881 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -41,7 +41,9 @@ def plot_over_time(yaml_file): rc("font", **{"family": "sans-serif", "sans-serif": ["Helvetica"], "size": 10}) plt.rcParams["text.color"] = "#444444" - fig, ax = plt.subplots(figsize=(10, 5)) + fig, ax = plt.subplots(figsize=(12, 6)) # Increase figure size for better visibility + + print("Debug: Figure created. Plotting data...") ax.grid(axis="y", zorder=0, lw=0.2) for spine in ax.spines.values(): spine.set_edgecolor("#DDDDDD") @@ -67,12 +69,18 @@ def plot_over_time(yaml_file): "Aider code editing benchmark,\npercent completed correctly", fontsize=18, color="#555" ) ax.set_title("LLM code editing skill by model release date", fontsize=20) - ax.set_ylim(0, 30) - plt.xticks(fontsize=14) + ax.set_ylim(0, 100) # Adjust y-axis limit to accommodate higher values + plt.xticks(fontsize=14, rotation=45, ha='right') # Rotate x-axis labels for better readability plt.tight_layout(pad=3.0) + + print("Debug: Saving figures...") plt.savefig("tmp_over_time.png") plt.savefig("tmp_over_time.svg") + + print("Debug: Displaying figure with imgcat...") imgcat(fig) + + print("Debug: Figure generation complete.") # Example usage From 1f59687e9ddf102d755a2149812121c1d9c59864 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 06:21:48 -0700 Subject: [PATCH 025/105] style: Format code with linter --- benchmark/over_time.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index 2e04c7881..884dfefc3 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -42,7 +42,7 @@ def plot_over_time(yaml_file): plt.rcParams["text.color"] = "#444444" fig, ax = plt.subplots(figsize=(12, 6)) # Increase figure size for better visibility - + print("Debug: Figure created. Plotting data...") ax.grid(axis="y", zorder=0, lw=0.2) for spine in ax.spines.values(): @@ -70,16 +70,16 @@ def plot_over_time(yaml_file): ) ax.set_title("LLM code editing skill by model release date", fontsize=20) ax.set_ylim(0, 100) # Adjust y-axis limit to accommodate higher values - plt.xticks(fontsize=14, rotation=45, ha='right') # Rotate x-axis labels for better readability + plt.xticks(fontsize=14, rotation=45, ha="right") # Rotate x-axis labels for better readability plt.tight_layout(pad=3.0) - + print("Debug: Saving figures...") plt.savefig("tmp_over_time.png") plt.savefig("tmp_over_time.svg") - + print("Debug: Displaying figure with imgcat...") imgcat(fig) - + print("Debug: Figure generation complete.") From c4f70d81b72853c7597086dc2611f15cbd8fe2cd Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 06:22:48 -0700 Subject: [PATCH 026/105] feat: add new color for all "-4o-" models except "gpt-4o-mini" --- benchmark/over_time.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index 884dfefc3..f04da3730 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -50,7 +50,10 @@ def plot_over_time(yaml_file): spine.set_linewidth(0.5) colors = [ - "red" if "gpt-4" in model else "green" if "gpt-3.5" in model else "blue" for model in models + "orange" if "-4o-" in model and "gpt-4o-mini" not in model + else "red" if "gpt-4" in model + else "green" if "gpt-3.5" in model + else "blue" for model in models ] ax.scatter(dates, pass_rates, c=colors, alpha=0.5, s=120) From 1f6cadcc66172d21e844eca2930192dfb7ba2eef Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 06:22:51 -0700 Subject: [PATCH 027/105] style: Refactor conditional logic in color assignment --- benchmark/over_time.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index f04da3730..fc0e13f9c 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -50,10 +50,12 @@ def plot_over_time(yaml_file): spine.set_linewidth(0.5) colors = [ - "orange" if "-4o-" in model and "gpt-4o-mini" not in model - else "red" if "gpt-4" in model - else "green" if "gpt-3.5" in model - else "blue" for model in models + ( + "orange" + if "-4o-" in model and "gpt-4o-mini" not in model + else "red" if "gpt-4" in model else "green" if "gpt-3.5" in model else "blue" + ) + for model in models ] ax.scatter(dates, pass_rates, c=colors, alpha=0.5, s=120) From 714fd45f4d3efe1206ea9aa6002f5a08aa97b05b Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 06:27:47 -0700 Subject: [PATCH 028/105] fix: Update color logic and font size in over_time.py --- benchmark/over_time.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index fc0e13f9c..2c2116628 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -52,7 +52,7 @@ def plot_over_time(yaml_file): colors = [ ( "orange" - if "-4o-" in model and "gpt-4o-mini" not in model + if "-4o" in model and "gpt-4o-mini" not in model else "red" if "gpt-4" in model else "green" if "gpt-3.5" in model else "blue" ) for model in models @@ -63,7 +63,7 @@ def plot_over_time(yaml_file): ax.annotate( model, (dates[i], pass_rates[i]), - fontsize=12, + fontsize=8, alpha=0.75, xytext=(5, 5), textcoords="offset points", From 1cdbc769746a838d12f9a9b344dffc5e1868d671 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 06:27:48 -0700 Subject: [PATCH 029/105] feat: Connect model family lines in over_time plot --- benchmark/over_time.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index 2c2116628..6215c5411 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -57,6 +57,25 @@ def plot_over_time(yaml_file): ) for model in models ] + + # Separate data points by color + orange_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "orange"] + red_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "red"] + green_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "green"] + blue_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "blue"] + + # Plot lines for orange, red, and green points + if orange_points: + orange_dates, orange_rates = zip(*sorted(orange_points)) + ax.plot(orange_dates, orange_rates, c="orange", alpha=0.5, linewidth=1) + if red_points: + red_dates, red_rates = zip(*sorted(red_points)) + ax.plot(red_dates, red_rates, c="red", alpha=0.5, linewidth=1) + if green_points: + green_dates, green_rates = zip(*sorted(green_points)) + ax.plot(green_dates, green_rates, c="green", alpha=0.5, linewidth=1) + + # Plot all points ax.scatter(dates, pass_rates, c=colors, alpha=0.5, s=120) for i, model in enumerate(models): From a7290be843c6a6af2649556b1a81b02bf5a90b3c Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 06:27:51 -0700 Subject: [PATCH 030/105] style: Apply linter formatting changes --- benchmark/over_time.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index 6215c5411..8eec5d603 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -57,7 +57,7 @@ def plot_over_time(yaml_file): ) for model in models ] - + # Separate data points by color orange_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "orange"] red_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "red"] From fb0b348bec51dc093c4ea1472cca3f8020a5ca34 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 06:28:28 -0700 Subject: [PATCH 031/105] fix: Remove unused `blue_points` variable --- benchmark/over_time.py | 1 - 1 file changed, 1 deletion(-) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index 8eec5d603..2204eae45 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -62,7 +62,6 @@ def plot_over_time(yaml_file): orange_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "orange"] red_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "red"] green_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "green"] - blue_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "blue"] # Plot lines for orange, red, and green points if orange_points: From d2b4846b956b8f12d351964c861418b20848d389 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 06:29:13 -0700 Subject: [PATCH 032/105] feat: Replace orange color with purple for "-4o" models --- benchmark/over_time.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index 2204eae45..12e5dde5a 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -51,7 +51,7 @@ def plot_over_time(yaml_file): colors = [ ( - "orange" + "purple" if "-4o" in model and "gpt-4o-mini" not in model else "red" if "gpt-4" in model else "green" if "gpt-3.5" in model else "blue" ) @@ -59,14 +59,14 @@ def plot_over_time(yaml_file): ] # Separate data points by color - orange_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "orange"] + purple_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "purple"] red_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "red"] green_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "green"] - # Plot lines for orange, red, and green points - if orange_points: - orange_dates, orange_rates = zip(*sorted(orange_points)) - ax.plot(orange_dates, orange_rates, c="orange", alpha=0.5, linewidth=1) + # Plot lines for purple, red, and green points + if purple_points: + purple_dates, purple_rates = zip(*sorted(purple_points)) + ax.plot(purple_dates, purple_rates, c="purple", alpha=0.5, linewidth=1) if red_points: red_dates, red_rates = zip(*sorted(red_points)) ax.plot(red_dates, red_rates, c="red", alpha=0.5, linewidth=1) From 0a3c6bfbe721eb4765e293f69da6ed759d2aaa5b Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 06:29:48 -0700 Subject: [PATCH 033/105] feat: Change blue color to light blue in plot_over_time function --- benchmark/over_time.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index 12e5dde5a..565038a8e 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -53,7 +53,7 @@ def plot_over_time(yaml_file): ( "purple" if "-4o" in model and "gpt-4o-mini" not in model - else "red" if "gpt-4" in model else "green" if "gpt-3.5" in model else "blue" + else "red" if "gpt-4" in model else "green" if "gpt-3.5" in model else "lightblue" ) for model in models ] From 1ced72b7286de71f6d8aac97c3f038842ef0b52e Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 06:31:20 -0700 Subject: [PATCH 034/105] update models-over-time --- aider/website/_data/edit_leaderboard.yml | 12 + aider/website/assets/models-over-time.svg | 945 ++++++++++++++++------ 2 files changed, 722 insertions(+), 235 deletions(-) diff --git a/aider/website/_data/edit_leaderboard.yml b/aider/website/_data/edit_leaderboard.yml index 72dd9c96b..426c86336 100644 --- a/aider/website/_data/edit_leaderboard.yml +++ b/aider/website/_data/edit_leaderboard.yml @@ -577,6 +577,7 @@ pass_rate_2: 77.4 percent_cases_well_formed: 99.2 error_outputs: 23 + released: 2024-06-20 num_malformed_responses: 4 num_with_malformed_responses: 1 user_asks: 2 @@ -603,6 +604,7 @@ num_malformed_responses: 0 num_with_malformed_responses: 0 user_asks: 0 + released: 2024-03-13 lazy_comments: 0 syntax_errors: 0 indentation_errors: 0 @@ -644,6 +646,7 @@ commit_hash: d31eef3-dirty pass_rate_1: 40.6 pass_rate_2: 55.6 + released: 2024-07-18 percent_cases_well_formed: 100.0 error_outputs: 1 num_malformed_responses: 0 @@ -668,6 +671,7 @@ pass_rate_1: 60.9 pass_rate_2: 69.9 percent_cases_well_formed: 97.7 + released: 2024-06-28 error_outputs: 58 num_malformed_responses: 13 num_with_malformed_responses: 3 @@ -690,6 +694,7 @@ commit_hash: f7ce78b-dirty pass_rate_1: 46.6 pass_rate_2: 63.9 + released: 2024-07-23 percent_cases_well_formed: 92.5 error_outputs: 84 num_malformed_responses: 19 @@ -716,6 +721,7 @@ percent_cases_well_formed: 100.0 error_outputs: 0 num_malformed_responses: 0 + released: 2024-07-23 num_with_malformed_responses: 0 user_asks: 0 lazy_comments: 0 @@ -738,6 +744,7 @@ pass_rate_2: 72.9 percent_cases_well_formed: 97.7 error_outputs: 13 + released: 2024-07-24 num_malformed_responses: 3 num_with_malformed_responses: 3 user_asks: 1 @@ -763,6 +770,7 @@ error_outputs: 3 num_malformed_responses: 0 num_with_malformed_responses: 0 + released: 2024-07-24 user_asks: 3 lazy_comments: 0 syntax_errors: 1 @@ -785,6 +793,7 @@ percent_cases_well_formed: 100.0 error_outputs: 27 num_malformed_responses: 0 + released: 2024-07-23 num_with_malformed_responses: 0 user_asks: 23 lazy_comments: 8 @@ -810,6 +819,7 @@ num_malformed_responses: 0 num_with_malformed_responses: 0 user_asks: 0 + released: 2024-07-23 lazy_comments: 0 syntax_errors: 0 indentation_errors: 0 @@ -838,6 +848,7 @@ indentation_errors: 2 exhausted_context_windows: 0 test_timeouts: 5 + released: 2024-08-06 command: aider --model openai/gpt-4o-2024-08-06 date: 2024-08-06 versions: 0.48.1-dev @@ -863,6 +874,7 @@ test_timeouts: 0 command: aider --model openai/chatgpt-4o-latest date: 2024-08-14 + released: 2024-08-08 versions: 0.50.2-dev seconds_per_case: 26.3 total_cost: 3.6113 diff --git a/aider/website/assets/models-over-time.svg b/aider/website/assets/models-over-time.svg index 994dab6ae..a4fe87061 100644 --- a/aider/website/assets/models-over-time.svg +++ b/aider/website/assets/models-over-time.svg @@ -1,16 +1,16 @@ - + - 2024-05-15T11:52:34.512395 + 2024-08-14T06:29:51.758534 image/svg+xml - Matplotlib v3.8.4, https://matplotlib.org/ + Matplotlib v3.9.2, https://matplotlib.org/ @@ -21,25 +21,25 @@ - - - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -441,12 +474,12 @@ z - + - + @@ -457,9 +490,47 @@ z - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + - - + - - - - - + + + + - - + + - + - + - - - - + + + + - - + + - + - + - - - - + + + + - - + + - + - + - + - + - - + + - + - + - - - - + + + + + + + - + + + + + + + + + + + + + + + + + + + - + - + + + + + + + + + - - - - - + - + - + - + @@ -1282,28 +1434,9 @@ z - - - - - - - - - - - - - - - - - - - - + - + - + - + @@ -1356,9 +1489,9 @@ z - + - + @@ -1379,9 +1512,9 @@ z - + - + - + - + @@ -1445,9 +1578,9 @@ z - + - + @@ -1460,9 +1593,9 @@ z - + - + @@ -1483,9 +1616,9 @@ z - + - + @@ -1510,50 +1643,9 @@ z - + - - - - + @@ -1571,9 +1663,9 @@ z - + - + @@ -1590,30 +1682,121 @@ z - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + @@ -1672,9 +1855,184 @@ z - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1735,8 +2210,8 @@ z - - + + From db22d298e34fdd79d594be73a730ce3f2e13c5be Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 09:53:44 -0700 Subject: [PATCH 035/105] feat: Add comprehensive test for YAML config file loading The commit message is: feat: Add comprehensive test for YAML config file loading --- tests/basic/test_main.py | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tests/basic/test_main.py b/tests/basic/test_main.py index 1560894a0..e24ccc9de 100644 --- a/tests/basic/test_main.py +++ b/tests/basic/test_main.py @@ -373,6 +373,60 @@ class TestMain(TestCase): self.assertRegex(relevant_output, r"AIDER_DARK_MODE:\s+on") self.assertRegex(relevant_output, r"dark_mode:\s+True") + def test_yaml_config_file_loading(self): + with GitTemporaryDirectory() as git_dir: + git_dir = Path(git_dir) + + # Create fake home directory + fake_home = git_dir / "fake_home" + fake_home.mkdir() + os.environ["HOME"] = str(fake_home) + + # Create subdirectory as current working directory + cwd = git_dir / "subdir" + cwd.mkdir() + os.chdir(cwd) + + # Create .aider.conf.yml files in different locations + home_config = fake_home / ".aider.conf.yml" + git_config = git_dir / ".aider.conf.yml" + cwd_config = cwd / ".aider.conf.yml" + named_config = git_dir / "named.aider.conf.yml" + + home_config.write_text("model: gpt-3.5-turbo\nmap-tokens: 1024\n") + git_config.write_text("model: gpt-4\nmap-tokens: 2048\n") + cwd_config.write_text("model: gpt-4-32k\nmap-tokens: 4096\n") + named_config.write_text("model: gpt-4-1106-preview\nmap-tokens: 8192\n") + + with patch("pathlib.Path.home", return_value=fake_home), \ + patch("aider.coders.Coder.create") as MockCoder: + + # Test loading from current working directory + main(["--yes", "--exit"], input=DummyInput(), output=DummyOutput()) + _, kwargs = MockCoder.call_args + self.assertEqual(kwargs["model"], "gpt-4-32k") + self.assertEqual(kwargs["map_tokens"], 4096) + + # Test loading from git root + cwd_config.unlink() + main(["--yes", "--exit"], input=DummyInput(), output=DummyOutput()) + _, kwargs = MockCoder.call_args + self.assertEqual(kwargs["model"], "gpt-4") + self.assertEqual(kwargs["map_tokens"], 2048) + + # Test loading from home directory + git_config.unlink() + main(["--yes", "--exit"], input=DummyInput(), output=DummyOutput()) + _, kwargs = MockCoder.call_args + self.assertEqual(kwargs["model"], "gpt-3.5-turbo") + self.assertEqual(kwargs["map_tokens"], 1024) + + # Test loading from specified config file + main(["--yes", "--exit", "--config", str(named_config)], input=DummyInput(), output=DummyOutput()) + _, kwargs = MockCoder.call_args + self.assertEqual(kwargs["model"], "gpt-4-1106-preview") + self.assertEqual(kwargs["map_tokens"], 8192) + def test_map_tokens_option(self): with GitTemporaryDirectory(): with patch("aider.coders.base_coder.RepoMap") as MockRepoMap: From 81ed9c3002a546ca5bd0c85fad7bacc5e6a57941 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 09:53:48 -0700 Subject: [PATCH 036/105] style: Apply linter formatting changes --- tests/basic/test_main.py | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/tests/basic/test_main.py b/tests/basic/test_main.py index e24ccc9de..fcb407ab0 100644 --- a/tests/basic/test_main.py +++ b/tests/basic/test_main.py @@ -226,9 +226,10 @@ class TestMain(TestCase): def test_main_exit_calls_version_check(self): with GitTemporaryDirectory(): - with patch("aider.main.check_version") as mock_check_version, patch( - "aider.main.InputOutput" - ) as mock_input_output: + with ( + patch("aider.main.check_version") as mock_check_version, + patch("aider.main.InputOutput") as mock_input_output, + ): main(["--exit"], input=DummyInput(), output=DummyOutput()) mock_check_version.assert_called_once() mock_input_output.assert_called_once() @@ -376,53 +377,58 @@ class TestMain(TestCase): def test_yaml_config_file_loading(self): with GitTemporaryDirectory() as git_dir: git_dir = Path(git_dir) - + # Create fake home directory fake_home = git_dir / "fake_home" fake_home.mkdir() os.environ["HOME"] = str(fake_home) - + # Create subdirectory as current working directory cwd = git_dir / "subdir" cwd.mkdir() os.chdir(cwd) - + # Create .aider.conf.yml files in different locations home_config = fake_home / ".aider.conf.yml" git_config = git_dir / ".aider.conf.yml" cwd_config = cwd / ".aider.conf.yml" named_config = git_dir / "named.aider.conf.yml" - + home_config.write_text("model: gpt-3.5-turbo\nmap-tokens: 1024\n") git_config.write_text("model: gpt-4\nmap-tokens: 2048\n") cwd_config.write_text("model: gpt-4-32k\nmap-tokens: 4096\n") named_config.write_text("model: gpt-4-1106-preview\nmap-tokens: 8192\n") - - with patch("pathlib.Path.home", return_value=fake_home), \ - patch("aider.coders.Coder.create") as MockCoder: - + + with ( + patch("pathlib.Path.home", return_value=fake_home), + patch("aider.coders.Coder.create") as MockCoder, + ): # Test loading from current working directory main(["--yes", "--exit"], input=DummyInput(), output=DummyOutput()) _, kwargs = MockCoder.call_args self.assertEqual(kwargs["model"], "gpt-4-32k") self.assertEqual(kwargs["map_tokens"], 4096) - + # Test loading from git root cwd_config.unlink() main(["--yes", "--exit"], input=DummyInput(), output=DummyOutput()) _, kwargs = MockCoder.call_args self.assertEqual(kwargs["model"], "gpt-4") self.assertEqual(kwargs["map_tokens"], 2048) - + # Test loading from home directory git_config.unlink() main(["--yes", "--exit"], input=DummyInput(), output=DummyOutput()) _, kwargs = MockCoder.call_args self.assertEqual(kwargs["model"], "gpt-3.5-turbo") self.assertEqual(kwargs["map_tokens"], 1024) - + # Test loading from specified config file - main(["--yes", "--exit", "--config", str(named_config)], input=DummyInput(), output=DummyOutput()) + main( + ["--yes", "--exit", "--config", str(named_config)], + input=DummyInput(), + output=DummyOutput(), + ) _, kwargs = MockCoder.call_args self.assertEqual(kwargs["model"], "gpt-4-1106-preview") self.assertEqual(kwargs["map_tokens"], 8192) From 258132bfd47f2f34070cc7dea146fdd403b3722d Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 09:54:26 -0700 Subject: [PATCH 037/105] fix: Fix YAML configuration file loading --- tests/basic/test_main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/basic/test_main.py b/tests/basic/test_main.py index fcb407ab0..48fde53a7 100644 --- a/tests/basic/test_main.py +++ b/tests/basic/test_main.py @@ -406,6 +406,8 @@ class TestMain(TestCase): # Test loading from current working directory main(["--yes", "--exit"], input=DummyInput(), output=DummyOutput()) _, kwargs = MockCoder.call_args + print("kwargs:", kwargs) # Add this line for debugging + self.assertIn("model", kwargs, "model key not found in kwargs") self.assertEqual(kwargs["model"], "gpt-4-32k") self.assertEqual(kwargs["map_tokens"], 4096) From 95535b92949ebdbc13846a60f9347a87128893dd Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 09:56:07 -0700 Subject: [PATCH 038/105] fix: Update test_yaml_config_file_loading to correctly access model name --- tests/basic/test_main.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/basic/test_main.py b/tests/basic/test_main.py index 48fde53a7..c0e62c56c 100644 --- a/tests/basic/test_main.py +++ b/tests/basic/test_main.py @@ -407,22 +407,22 @@ class TestMain(TestCase): main(["--yes", "--exit"], input=DummyInput(), output=DummyOutput()) _, kwargs = MockCoder.call_args print("kwargs:", kwargs) # Add this line for debugging - self.assertIn("model", kwargs, "model key not found in kwargs") - self.assertEqual(kwargs["model"], "gpt-4-32k") + self.assertIn("main_model", kwargs, "main_model key not found in kwargs") + self.assertEqual(kwargs["main_model"].name, "gpt-4-32k") self.assertEqual(kwargs["map_tokens"], 4096) # Test loading from git root cwd_config.unlink() main(["--yes", "--exit"], input=DummyInput(), output=DummyOutput()) _, kwargs = MockCoder.call_args - self.assertEqual(kwargs["model"], "gpt-4") + self.assertEqual(kwargs["main_model"].name, "gpt-4") self.assertEqual(kwargs["map_tokens"], 2048) # Test loading from home directory git_config.unlink() main(["--yes", "--exit"], input=DummyInput(), output=DummyOutput()) _, kwargs = MockCoder.call_args - self.assertEqual(kwargs["model"], "gpt-3.5-turbo") + self.assertEqual(kwargs["main_model"].name, "gpt-3.5-turbo") self.assertEqual(kwargs["map_tokens"], 1024) # Test loading from specified config file @@ -432,7 +432,7 @@ class TestMain(TestCase): output=DummyOutput(), ) _, kwargs = MockCoder.call_args - self.assertEqual(kwargs["model"], "gpt-4-1106-preview") + self.assertEqual(kwargs["main_model"].name, "gpt-4-1106-preview") self.assertEqual(kwargs["map_tokens"], 8192) def test_map_tokens_option(self): From 1cc1ce0bd409d00659ff1d31601991700f2fa288 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 10:02:55 -0700 Subject: [PATCH 039/105] fix: load yml config files most specific to least --- aider/main.py | 2 ++ tests/basic/test_main.py | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/aider/main.py b/aider/main.py index bb647d55d..a25816f45 100644 --- a/aider/main.py +++ b/aider/main.py @@ -324,6 +324,8 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F default_config_files.append(Path.home() / conf_fname) # homedir default_config_files = list(map(str, default_config_files)) + default_config_files.reverse() + parser = get_parser(default_config_files, git_root) args, unknown = parser.parse_known_args(argv) diff --git a/tests/basic/test_main.py b/tests/basic/test_main.py index c0e62c56c..1f0d467b5 100644 --- a/tests/basic/test_main.py +++ b/tests/basic/test_main.py @@ -394,15 +394,25 @@ class TestMain(TestCase): cwd_config = cwd / ".aider.conf.yml" named_config = git_dir / "named.aider.conf.yml" - home_config.write_text("model: gpt-3.5-turbo\nmap-tokens: 1024\n") - git_config.write_text("model: gpt-4\nmap-tokens: 2048\n") cwd_config.write_text("model: gpt-4-32k\nmap-tokens: 4096\n") + git_config.write_text("model: gpt-4\nmap-tokens: 2048\n") + home_config.write_text("model: gpt-3.5-turbo\nmap-tokens: 1024\n") named_config.write_text("model: gpt-4-1106-preview\nmap-tokens: 8192\n") with ( patch("pathlib.Path.home", return_value=fake_home), patch("aider.coders.Coder.create") as MockCoder, ): + # Test loading from specified config file + main( + ["--yes", "--exit", "--config", str(named_config)], + input=DummyInput(), + output=DummyOutput(), + ) + _, kwargs = MockCoder.call_args + self.assertEqual(kwargs["main_model"].name, "gpt-4-1106-preview") + self.assertEqual(kwargs["map_tokens"], 8192) + # Test loading from current working directory main(["--yes", "--exit"], input=DummyInput(), output=DummyOutput()) _, kwargs = MockCoder.call_args @@ -425,16 +435,6 @@ class TestMain(TestCase): self.assertEqual(kwargs["main_model"].name, "gpt-3.5-turbo") self.assertEqual(kwargs["map_tokens"], 1024) - # Test loading from specified config file - main( - ["--yes", "--exit", "--config", str(named_config)], - input=DummyInput(), - output=DummyOutput(), - ) - _, kwargs = MockCoder.call_args - self.assertEqual(kwargs["main_model"].name, "gpt-4-1106-preview") - self.assertEqual(kwargs["map_tokens"], 8192) - def test_map_tokens_option(self): with GitTemporaryDirectory(): with patch("aider.coders.base_coder.RepoMap") as MockRepoMap: From aaade794a6a2465f8cef5a1a4efdb76c937edfa5 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 10:04:12 -0700 Subject: [PATCH 040/105] feat: Add verbose printing of default config files before reversing --- aider/main.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/aider/main.py b/aider/main.py index a25816f45..27261549a 100644 --- a/aider/main.py +++ b/aider/main.py @@ -324,6 +324,14 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F default_config_files.append(Path.home() / conf_fname) # homedir default_config_files = list(map(str, default_config_files)) + parser = get_parser(default_config_files, git_root) + args, unknown = parser.parse_known_args(argv) + + if args.verbose: + print("Default config files before reversing:") + for file in default_config_files: + print(f" - {file}") + default_config_files.reverse() parser = get_parser(default_config_files, git_root) From e55513bd797cba94868e3b690af23227cf22bbb3 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 10:05:18 -0700 Subject: [PATCH 041/105] fix: Update config files search order message --- aider/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/main.py b/aider/main.py index 27261549a..9e62ccb34 100644 --- a/aider/main.py +++ b/aider/main.py @@ -328,7 +328,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F args, unknown = parser.parse_known_args(argv) if args.verbose: - print("Default config files before reversing:") + print("Config files search order, if no --config:") for file in default_config_files: print(f" - {file}") From cdab3fd17ffdbde742470ed007e4f610fd938b4d Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 10:05:55 -0700 Subject: [PATCH 042/105] feat: mark which of the default_config_files exist in the verbose output --- aider/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aider/main.py b/aider/main.py index 9e62ccb34..335dfcb6c 100644 --- a/aider/main.py +++ b/aider/main.py @@ -330,7 +330,8 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F if args.verbose: print("Config files search order, if no --config:") for file in default_config_files: - print(f" - {file}") + exists = "[EXISTS]" if Path(file).exists() else "" + print(f" - {file} {exists}") default_config_files.reverse() From 7534fabcc0db3fac10cf648442d90cf349072ca0 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 10:06:49 -0700 Subject: [PATCH 043/105] fix: Update config file existence indicator in main.py --- aider/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/main.py b/aider/main.py index 335dfcb6c..be0268f88 100644 --- a/aider/main.py +++ b/aider/main.py @@ -330,7 +330,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F if args.verbose: print("Config files search order, if no --config:") for file in default_config_files: - exists = "[EXISTS]" if Path(file).exists() else "" + exists = "(exists)" if Path(file).exists() else "" print(f" - {file} {exists}") default_config_files.reverse() From fb7bbb982e083ad354478633a188345390c06509 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 10:10:28 -0700 Subject: [PATCH 044/105] fix: Change default prompt option to uppercase 'Y' --- aider/commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/commands.py b/aider/commands.py index 599d5013d..5bfaac932 100644 --- a/aider/commands.py +++ b/aider/commands.py @@ -724,7 +724,7 @@ class Commands: add = result.returncode != 0 else: response = self.io.prompt_ask( - "Add the output to the chat?\n(y/n/instructions)", default="" + "Add the output to the chat?\n(Y/n/instructions)", default="" ).strip() if response.lower() in ["yes", "y"]: From a37220b974b7c34e6a75af9ccbe3052fa80dfecf Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 11:24:16 -0700 Subject: [PATCH 045/105] remove spurious except clause --- aider/coders/base_coder.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index 3fdc12260..c7f9816e8 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -1264,8 +1264,6 @@ class Coder: except KeyboardInterrupt as kbi: self.keyboard_interrupt() raise kbi - except Exception as e: - self.io.tool_error(f"Error during API call: {str(e)}") finally: self.io.log_llm_history( "LLM RESPONSE", From b2211c4a58274a75e3c5921d8bb55510b5f9cca4 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 16:41:08 -0700 Subject: [PATCH 046/105] initial --- .../website/_posts/2024-08-14-code-in-json.md | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 aider/website/_posts/2024-08-14-code-in-json.md diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md new file mode 100644 index 000000000..7fc8919db --- /dev/null +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -0,0 +1,127 @@ +--- +title: LLMs are bad at returning code in json +excerpt: LLMs write worse code if you ask them to return the code wrapped in json via a tool/function call. +highlight_image: /assets/code-in-json.jpg +draft: true +nav_exclude: true +--- +{% if page.date %} + +{% endif %} + +# LLMs are bad at returning code in json + + +A lot of people wonder why aider doesn't have LLMs use tools or function calls to +specify code edits. +Instead, aider asks LLMs to return code edits in plain text, like this: + +```` +greeting.py +```python +<<<<<<< SEARCH +def greeting(): + print("Hello") +======= +def greeting(): + print("Goodbye") +>>>>>>> REPLACE +``` +```` + +People expect that it would be easier and more reliable +for aider to parse a nicely formatted json +response more like this: + +``` +{ + "filename": "greeting.py", + "start_line": 6, + "end_line": 7, + "new_content": "def greeting():\n print(\"Goodbye\")\n" +} +``` + +This seems even more tempting as LLMs get better tooling for reliably generating +valid json, or even enforcing that it meets a specific schema. +For example, OpenAI recently announced +[strict enforcement of json responses](). + +The problem is that LLMs are bad a writing code when you ask them to wrap it +into a json container. +The json tooling around the LLM helps make sure it's valid json, +which does solve an important problem. +LLMs used to frequently produce invalid json, so that's a big step forward. + +The problem remains, LLMs write worse code when they're asked to +emit it wrapped in json. +In some sense this shouldn't be surprising. +Just look at the very simple +json example above, with the escaped +quotes `\"` quotes +newlines `\n` +mixed into the code. +Coding is complicated enough without having to escape all the special characters too. + +If I asked you to write me a program, would you do a better job +typing it into a text file or hand typing it as a properly escaped json string? + +## Quantifying the benefits of plain text + + +Previous [benchmark results](/2023/07/02/benchmarks.html) +showed +the superiority of plain text coding compared to json-wrapped function calls, +but they were done over a year ago. +OpenAI's newly announced support for "strict" json seemed like a good reason to +investigate whether the newest models are still handicapped by json-wrapping code. + +To find out, I benchmarked 3 of the strongest code editing models: + +- gpt-4o-2024-08-06 +- claude-3-5-sonnet-20240620 +- deepseek-coder (V2 0724) + +Each model was given one try to solve +[133 practice exercises from the Exercism python repository](/2023/07/02/benchmarks.html#the-benchmark). +This is the standard aider "code editing" benchmark, except restricted to a single attempt. + +Each model ran through the benchmark with two strategies for returning code: + +- **Markdown** -- where the model simply returns the whole source code file in standard markdown triple-backtick fences. +- **Tool call** -- where the model is told to use a function to return the whole source code file. This requires the LLM to wrap the code in json. + +The markdown strategy would return a program like this: + +```` +Here is the program you asked for which prints "Hello, world!": + +greeting.py +``` +def greeting(): + print("Hello") +``` +```` + +The tool strategy requires the LLM to call the `write_file` function with +two parameters, like this: + +``` +{ + "explanation": "Here is the program you asked for which prints \"Hello, world!\"", + "content": "def greeting():\n print(\"Hello\")\n" +} +``` + +Both of these formats avoid actually *editing* source files, to keep things as +simple as possible. +This makes the task much easier, since the LLM can emit the whole source file intact. +LLMs find it much more challenging to correctly formulate instructions to edit +portions of a file. + +We are simply testing the effects of json-wrapping on the LLMs ability to solve coding tasks. + +## Results + +All 3 models did significantly worse on the benchmark when asked to +return json-wrapped code in a tool function call. From 205a503d64ee655f8d284406beb655567fc97d2e Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 16:41:22 -0700 Subject: [PATCH 047/105] init --- aider/website/_data/code-in-json.yml | 154 +++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 aider/website/_data/code-in-json.yml diff --git a/aider/website/_data/code-in-json.yml b/aider/website/_data/code-in-json.yml new file mode 100644 index 000000000..c4ed8d073 --- /dev/null +++ b/aider/website/_data/code-in-json.yml @@ -0,0 +1,154 @@ +- dirname: 2024-08-14-18-38-25--json-gpt-4o-2024-08-06-non-strict-func + test_cases: 133 + model: gpt-4o-2024-08-06 + edit_format: Tool call + commit_hash: 2eb1946-dirty + pass_rate_1: 54.1 + percent_cases_well_formed: 100.0 + error_outputs: 7 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 2 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 4 + command: aider --model gpt-4o-2024-08-06 + date: 2024-08-14 + versions: 0.50.2-dev + seconds_per_case: 11.5 + total_cost: 1.3819 + +- dirname: 2024-08-14-18-32-02--json-gpt-4o-2024-08-06-strict-func + test_cases: 133 + model: gpt-4o-2024-08-06 + edit_format: Tool call (strict) + commit_hash: 2eb1946 + pass_rate_1: 56.4 + percent_cases_well_formed: 100.0 + error_outputs: 1 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 7 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 4 + command: aider --model gpt-4o-2024-08-06 + date: 2024-08-14 + versions: 0.50.2-dev + seconds_per_case: 12.7 + total_cost: 1.3652 + +- dirname: 2024-08-14-18-26-18--json-gpt-4o-2024-08-06-whole + test_cases: 133 + model: gpt-4o-2024-08-06 + edit_format: Markdown + commit_hash: 94a2601-dirty + pass_rate_1: 62.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model gpt-4o-2024-08-06 + date: 2024-08-14 + versions: 0.50.2-dev + seconds_per_case: 6.8 + total_cost: 1.2717 + +- dirname: 2024-08-14-20-19-23--json-sonnet-non-strict-func + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: Tool call + commit_hash: e2f14a2 + pass_rate_1: 52.6 + percent_cases_well_formed: 100.0 + error_outputs: 1 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-14 + versions: 0.50.2-dev + seconds_per_case: 18.9 + total_cost: 2.6341 + +- dirname: 2024-08-14-20-15-19--json-sonnet-whole + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: Markdown + commit_hash: e2f14a2 + pass_rate_1: 58.6 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-14 + versions: 0.50.2-dev + seconds_per_case: 19.7 + total_cost: 2.5335 + +- dirname: 2024-08-14-21-20-46--json-deepseek-non-strict-func + test_cases: 133 + model: openrouter/deepseek/deepseek-coder + edit_format: Tool call + commit_hash: e2f14a2 + pass_rate_1: 54.1 + percent_cases_well_formed: 100.0 + error_outputs: 9 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 5 + lazy_comments: 0 + syntax_errors: 2 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/deepseek/deepseek-coder + date: 2024-08-14 + versions: 0.50.2-dev + seconds_per_case: 17.4 + total_cost: 0.0332 + +- dirname: 2024-08-14-21-23-27--json-deepseek-whole + test_cases: 133 + model: openrouter/deepseek/deepseek-coder + edit_format: Markdown + commit_hash: e2f14a2 + pass_rate_1: 61.7 + percent_cases_well_formed: 100.0 + error_outputs: 1 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/deepseek/deepseek-coder + date: 2024-08-14 + versions: 0.50.2-dev + seconds_per_case: 23.0 + total_cost: 0.0439 + From 957524680a2e6c7044009067a6561aaa87e78704 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 16:44:43 -0700 Subject: [PATCH 048/105] feat: Add bar graph to plot pass_rate_1 by model and edit_format --- .../website/_posts/2024-08-14-code-in-json.md | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 7fc8919db..2cb18662b 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -9,6 +9,74 @@ nav_exclude: true {% endif %} + + + + + # LLMs are bad at returning code in json From 7310f0928f919c493d4327b86f53dd4e2af960e8 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 16:46:00 -0700 Subject: [PATCH 049/105] feat: Fetch data from YAML file for chart --- .../website/_posts/2024-08-14-code-in-json.md | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 2cb18662b..1e7e729c6 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -16,25 +16,25 @@ nav_exclude: true document.addEventListener('DOMContentLoaded', function () { var ctx = document.getElementById('passRateChart').getContext('2d'); + var yamlData = {{ site.data.code-in-json | jsonify }}; + + var models = [...new Set(yamlData.map(item => item.model))]; + var editFormats = [...new Set(yamlData.map(item => item.edit_format))]; + + var datasets = editFormats.map(format => ({ + label: format, + data: models.map(model => { + var item = yamlData.find(d => d.model === model && d.edit_format === format); + return item ? item.pass_rate_1 : null; + }), + backgroundColor: format === 'Markdown' ? 'rgba(54, 162, 235, 0.8)' : + format === 'Tool call' ? 'rgba(255, 99, 132, 0.8)' : + 'rgba(75, 192, 192, 0.8)', + })); + var data = { - labels: ['gpt-4o-2024-08-06', 'claude-3.5-sonnet', 'deepseek-coder'], - datasets: [ - { - label: 'Markdown', - data: [62.4, 58.6, 61.7], - backgroundColor: 'rgba(54, 162, 235, 0.8)', - }, - { - label: 'Tool call', - data: [54.1, 52.6, 54.1], - backgroundColor: 'rgba(255, 99, 132, 0.8)', - }, - { - label: 'Tool call (strict)', - data: [56.4, null, null], - backgroundColor: 'rgba(75, 192, 192, 0.8)', - } - ] + labels: models, + datasets: datasets }; var config = { From b3ed2c8a48a97e17ddbba6578ab519e983a81d24 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 16:50:14 -0700 Subject: [PATCH 050/105] copy --- aider/website/_data/code-in-json.yml | 114 +++++++++--------- .../website/_posts/2024-08-14-code-in-json.md | 9 +- 2 files changed, 62 insertions(+), 61 deletions(-) diff --git a/aider/website/_data/code-in-json.yml b/aider/website/_data/code-in-json.yml index c4ed8d073..64c42a2d5 100644 --- a/aider/website/_data/code-in-json.yml +++ b/aider/website/_data/code-in-json.yml @@ -1,3 +1,25 @@ +- dirname: 2024-08-14-18-26-18--json-gpt-4o-2024-08-06-whole + test_cases: 133 + model: gpt-4o-2024-08-06 + edit_format: Markdown + commit_hash: 94a2601-dirty + pass_rate_1: 62.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model gpt-4o-2024-08-06 + date: 2024-08-14 + versions: 0.50.2-dev + seconds_per_case: 6.8 + total_cost: 1.2717 + - dirname: 2024-08-14-18-38-25--json-gpt-4o-2024-08-06-non-strict-func test_cases: 133 model: gpt-4o-2024-08-06 @@ -42,53 +64,9 @@ seconds_per_case: 12.7 total_cost: 1.3652 -- dirname: 2024-08-14-18-26-18--json-gpt-4o-2024-08-06-whole - test_cases: 133 - model: gpt-4o-2024-08-06 - edit_format: Markdown - commit_hash: 94a2601-dirty - pass_rate_1: 62.4 - percent_cases_well_formed: 100.0 - error_outputs: 0 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 0 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 3 - command: aider --model gpt-4o-2024-08-06 - date: 2024-08-14 - versions: 0.50.2-dev - seconds_per_case: 6.8 - total_cost: 1.2717 - -- dirname: 2024-08-14-20-19-23--json-sonnet-non-strict-func - test_cases: 133 - model: openrouter/anthropic/claude-3.5-sonnet - edit_format: Tool call - commit_hash: e2f14a2 - pass_rate_1: 52.6 - percent_cases_well_formed: 100.0 - error_outputs: 1 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 1 - lazy_comments: 0 - syntax_errors: 1 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 0 - command: aider --model openrouter/anthropic/claude-3.5-sonnet - date: 2024-08-14 - versions: 0.50.2-dev - seconds_per_case: 18.9 - total_cost: 2.6341 - - dirname: 2024-08-14-20-15-19--json-sonnet-whole test_cases: 133 - model: openrouter/anthropic/claude-3.5-sonnet + model: claude-3.5-sonnet edit_format: Markdown commit_hash: e2f14a2 pass_rate_1: 58.6 @@ -102,37 +80,37 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openrouter/anthropic/claude-3.5-sonnet + command: aider --model claude-3.5-sonnet date: 2024-08-14 versions: 0.50.2-dev seconds_per_case: 19.7 total_cost: 2.5335 -- dirname: 2024-08-14-21-20-46--json-deepseek-non-strict-func +- dirname: 2024-08-14-20-19-23--json-sonnet-non-strict-func test_cases: 133 - model: openrouter/deepseek/deepseek-coder + model: claude-3.5-sonnet edit_format: Tool call commit_hash: e2f14a2 - pass_rate_1: 54.1 + pass_rate_1: 52.6 percent_cases_well_formed: 100.0 - error_outputs: 9 + error_outputs: 1 num_malformed_responses: 0 num_with_malformed_responses: 0 - user_asks: 5 + user_asks: 1 lazy_comments: 0 - syntax_errors: 2 + syntax_errors: 1 indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openrouter/deepseek/deepseek-coder + command: aider --model claude-3.5-sonnet date: 2024-08-14 versions: 0.50.2-dev - seconds_per_case: 17.4 - total_cost: 0.0332 + seconds_per_case: 18.9 + total_cost: 2.6341 - dirname: 2024-08-14-21-23-27--json-deepseek-whole test_cases: 133 - model: openrouter/deepseek/deepseek-coder + model: deepseek-coder edit_format: Markdown commit_hash: e2f14a2 pass_rate_1: 61.7 @@ -146,9 +124,31 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openrouter/deepseek/deepseek-coder + command: aider --model deepseek-coder date: 2024-08-14 versions: 0.50.2-dev seconds_per_case: 23.0 total_cost: 0.0439 +- dirname: 2024-08-14-21-20-46--json-deepseek-non-strict-func + test_cases: 133 + model: deepseek-coder + edit_format: Tool call + commit_hash: e2f14a2 + pass_rate_1: 54.1 + percent_cases_well_formed: 100.0 + error_outputs: 9 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 5 + lazy_comments: 0 + syntax_errors: 2 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model deepseek-coder + date: 2024-08-14 + versions: 0.50.2-dev + seconds_per_case: 17.4 + total_cost: 0.0332 + diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 1e7e729c6..747eaa0cd 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -9,6 +9,9 @@ nav_exclude: true {% endif %} +# LLMs are bad at returning code in json + + @@ -55,13 +58,13 @@ document.addEventListener('DOMContentLoaded', function () { display: true, text: 'Pass Rate (%)' }, - max: 100 + max: 70 } }, plugins: { title: { display: true, - text: 'Pass Rate by Model and Edit Format', + text: 'Pass rate by model and code return strategy', font: { size: 16 } @@ -77,8 +80,6 @@ document.addEventListener('DOMContentLoaded', function () { }); -# LLMs are bad at returning code in json - A lot of people wonder why aider doesn't have LLMs use tools or function calls to specify code edits. From a951a2afc9ea535f9c021a26a497156421edb97a Mon Sep 17 00:00:00 2001 From: paul-gauthier <69695708+paul-gauthier@users.noreply.github.com> Date: Wed, 14 Aug 2024 18:56:01 -0700 Subject: [PATCH 051/105] Update 2024-08-14-code-in-json.md --- .../website/_posts/2024-08-14-code-in-json.md | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 747eaa0cd..119059015 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -116,14 +116,13 @@ valid json, or even enforcing that it meets a specific schema. For example, OpenAI recently announced [strict enforcement of json responses](). -The problem is that LLMs are bad a writing code when you ask them to wrap it -into a json container. -The json tooling around the LLM helps make sure it's valid json, -which does solve an important problem. -LLMs used to frequently produce invalid json, so that's a big step forward. - -The problem remains, LLMs write worse code when they're asked to +But it's not sufficient to just produce +valid json, it also +has to contain quality code. +Unfortunately, +LLMs write worse code when they're asked to emit it wrapped in json. + In some sense this shouldn't be surprising. Just look at the very simple json example above, with the escaped @@ -140,12 +139,17 @@ typing it into a text file or hand typing it as a properly escaped json string? Previous [benchmark results](/2023/07/02/benchmarks.html) showed -the superiority of plain text coding compared to json-wrapped function calls, -but they were done over a year ago. +the superiority of returning code +as plain text coding compared to json-wrapped function calls. +But those results were obtained +over a year ago, against far less +capable models. OpenAI's newly announced support for "strict" json seemed like a good reason to investigate whether the newest models are still handicapped by json-wrapping code. -To find out, I benchmarked 3 of the strongest code editing models: +The graph above shows benchmark +results from +3 of the strongest code editing models: - gpt-4o-2024-08-06 - claude-3-5-sonnet-20240620 @@ -155,15 +159,18 @@ Each model was given one try to solve [133 practice exercises from the Exercism python repository](/2023/07/02/benchmarks.html#the-benchmark). This is the standard aider "code editing" benchmark, except restricted to a single attempt. -Each model ran through the benchmark with two strategies for returning code: +Each model was assessed by the benchmark with two +different strategies for returning code: -- **Markdown** -- where the model simply returns the whole source code file in standard markdown triple-backtick fences. +- **Markdown** -- where the model simply returned the whole source code file in standard markdown triple-backtick fences. - **Tool call** -- where the model is told to use a function to return the whole source code file. This requires the LLM to wrap the code in json. -The markdown strategy would return a program like this: +The markdown strategy is the same as +aider's "whole" edit format. +It asks the LLM to return a program like this: ```` -Here is the program you asked for which prints "Hello, world!": +Here is the program you asked for which prints "Hello": greeting.py ``` @@ -177,18 +184,21 @@ two parameters, like this: ``` { - "explanation": "Here is the program you asked for which prints \"Hello, world!\"", + "explanation": "Here is the program you asked for which prints \"Hello\"", "content": "def greeting():\n print(\"Hello\")\n" } ``` -Both of these formats avoid actually *editing* source files, to keep things as +Both of these formats avoid actually *editing* source files, to keep +the task as simple as possible. -This makes the task much easier, since the LLM can emit the whole source file intact. -LLMs find it much more challenging to correctly formulate instructions to edit +The LLM can emit the whole source file intact, +which is much easier +than correctly formulating +instructions to edit portions of a file. -We are simply testing the effects of json-wrapping on the LLMs ability to solve coding tasks. +We are simply testing the effects of json-wrapping on the LLMs ability to write code to solve a task. ## Results From 9ab185a88fa1a5c52a9497e8b3767c99a13fd700 Mon Sep 17 00:00:00 2001 From: paul-gauthier <69695708+paul-gauthier@users.noreply.github.com> Date: Wed, 14 Aug 2024 18:57:18 -0700 Subject: [PATCH 052/105] Update 2024-08-14-code-in-json.md --- aider/website/_posts/2024-08-14-code-in-json.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 119059015..71f789ed1 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -1,6 +1,6 @@ --- title: LLMs are bad at returning code in json -excerpt: LLMs write worse code if you ask them to return the code wrapped in json via a tool/function call. +excerpt: LLMs write worse code if you ask them to return the code wrapped in json (via a tool or function call). highlight_image: /assets/code-in-json.jpg draft: true nav_exclude: true From d0e716ea7da300499e31ae9671e3eaaf425de6b1 Mon Sep 17 00:00:00 2001 From: paul-gauthier <69695708+paul-gauthier@users.noreply.github.com> Date: Wed, 14 Aug 2024 19:02:23 -0700 Subject: [PATCH 053/105] Update 2024-08-14-code-in-json.md --- aider/website/_posts/2024-08-14-code-in-json.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 71f789ed1..9721da004 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -100,7 +100,7 @@ def greeting(): People expect that it would be easier and more reliable for aider to parse a nicely formatted json -response more like this: +response, like this: ``` { @@ -111,7 +111,8 @@ response more like this: } ``` -This seems even more tempting as LLMs get better tooling for reliably generating +This seems even more tempting as LLMs +get better tooling for reliably generating valid json, or even enforcing that it meets a specific schema. For example, OpenAI recently announced [strict enforcement of json responses](). @@ -126,13 +127,16 @@ emit it wrapped in json. In some sense this shouldn't be surprising. Just look at the very simple json example above, with the escaped -quotes `\"` quotes +quotes `\"` and newlines `\n` mixed into the code. Coding is complicated enough without having to escape all the special characters too. -If I asked you to write me a program, would you do a better job -typing it into a text file or hand typing it as a properly escaped json string? +If you tried to write a program, +would you do a better job +typing it normally +or as a properly escaped +json string? ## Quantifying the benefits of plain text From 0a2d75b966a5f81d0309cc40990d4a55537e276f Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 20:05:23 -0700 Subject: [PATCH 054/105] fix: Apply consistent color and striped pattern to "Tool call (strict)" --- aider/website/_posts/2024-08-14-code-in-json.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 9721da004..a2f52b0c2 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -31,8 +31,11 @@ document.addEventListener('DOMContentLoaded', function () { return item ? item.pass_rate_1 : null; }), backgroundColor: format === 'Markdown' ? 'rgba(54, 162, 235, 0.8)' : - format === 'Tool call' ? 'rgba(255, 99, 132, 0.8)' : + format.startsWith('Tool call') ? 'rgba(255, 99, 132, 0.8)' : 'rgba(75, 192, 192, 0.8)', + borderColor: format === 'Tool call (strict)' ? 'rgba(255, 255, 255, 0.8)' : null, + borderWidth: format === 'Tool call (strict)' ? 2 : 0, + borderDash: format === 'Tool call (strict)' ? [5, 5] : null, })); var data = { From a47a5c91794a2ebe1621acf341396d2b647d35aa Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 20:07:09 -0700 Subject: [PATCH 055/105] fix: update code-in-json.md post with improved styling for code blocks --- aider/website/_posts/2024-08-14-code-in-json.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index a2f52b0c2..ed25f1056 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -33,9 +33,6 @@ document.addEventListener('DOMContentLoaded', function () { backgroundColor: format === 'Markdown' ? 'rgba(54, 162, 235, 0.8)' : format.startsWith('Tool call') ? 'rgba(255, 99, 132, 0.8)' : 'rgba(75, 192, 192, 0.8)', - borderColor: format === 'Tool call (strict)' ? 'rgba(255, 255, 255, 0.8)' : null, - borderWidth: format === 'Tool call (strict)' ? 2 : 0, - borderDash: format === 'Tool call (strict)' ? [5, 5] : null, })); var data = { From 9b2f317ba362f8bdb52b47540e169efc1892e874 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Wed, 14 Aug 2024 20:07:20 -0700 Subject: [PATCH 056/105] feat: Add function to create striped canvas pattern --- .../website/_posts/2024-08-14-code-in-json.md | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index ed25f1056..289fdc481 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -76,6 +76,28 @@ document.addEventListener('DOMContentLoaded', function () { } }; + function createStripedCanvas(isStrict) { + const patternCanvas = document.createElement('canvas'); + const patternContext = patternCanvas.getContext('2d'); + const size = 10; + patternCanvas.width = size; + patternCanvas.height = size; + + patternContext.fillStyle = 'rgba(255, 99, 132, 0.8)'; + patternContext.fillRect(0, 0, size, size); + + if (isStrict) { + patternContext.strokeStyle = 'rgba(255, 255, 255, 0.8)'; + patternContext.lineWidth = 2; + patternContext.beginPath(); + patternContext.moveTo(0, 0); + patternContext.lineTo(size, size); + patternContext.stroke(); + } + + return patternCanvas; + } + new Chart(ctx, config); }); From 23f89f1d29d4525c89da37273034863e0364f2a8 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Wed, 14 Aug 2024 20:07:21 -0700 Subject: [PATCH 057/105] feat: Add striped pattern for "Tool call (strict)" format --- aider/website/_posts/2024-08-14-code-in-json.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 289fdc481..6dd2d3e4b 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -30,9 +30,18 @@ document.addEventListener('DOMContentLoaded', function () { var item = yamlData.find(d => d.model === model && d.edit_format === format); return item ? item.pass_rate_1 : null; }), - backgroundColor: format === 'Markdown' ? 'rgba(54, 162, 235, 0.8)' : - format.startsWith('Tool call') ? 'rgba(255, 99, 132, 0.8)' : - 'rgba(75, 192, 192, 0.8)', + backgroundColor: function(context) { + const format = context.dataset.label; + if (format === 'Markdown') { + return 'rgba(54, 162, 235, 0.8)'; + } else if (format.startsWith('Tool call')) { + const ctx = context.chart.ctx; + const gradient = ctx.createPattern(createStripedCanvas(format === 'Tool call (strict)'), 'repeat'); + return gradient; + } else { + return 'rgba(75, 192, 192, 0.8)'; + } + }, })); var data = { From 6ef2b8c0fa1c6ec16f9dbe9a24502a0fadfe8bc0 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 06:05:38 -0700 Subject: [PATCH 058/105] copy --- aider/website/_posts/2024-08-14-code-in-json.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 6dd2d3e4b..f61643aa2 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -97,7 +97,7 @@ document.addEventListener('DOMContentLoaded', function () { if (isStrict) { patternContext.strokeStyle = 'rgba(255, 255, 255, 0.8)'; - patternContext.lineWidth = 2; + patternContext.lineWidth = 0.75; patternContext.beginPath(); patternContext.moveTo(0, 0); patternContext.lineTo(size, size); @@ -112,6 +112,21 @@ document.addEventListener('DOMContentLoaded', function () { +## Abstract + +The newest LLMs have explicit tooling and +support for returning properly formatted json responses. +While it is tempting to have LLMs use json tool or function calls to +return code or code edits, this is unwise. +LLMs write worse code when asked to wrap it in json, harming their ability +to correctly solve coding tasks. +Returning code as plain (markdown) text results in 6% higher scores +on a variant of the aider code editing benchmark. +Even OpenAI's newest gpt-4o-2024-08-06 with "strict" json support +suffers from this code-in-json handicap. + +## Introduction + A lot of people wonder why aider doesn't have LLMs use tools or function calls to specify code edits. Instead, aider asks LLMs to return code edits in plain text, like this: From ed6ebfbdb69269b04db3607a1ddfb685b3c6cf3e Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 08:08:56 -0700 Subject: [PATCH 059/105] fix: Update post on code in JSON --- .../website/_posts/2024-08-14-code-in-json.md | 89 ++++++++++--------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index f61643aa2..572aaf3be 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -114,22 +114,26 @@ document.addEventListener('DOMContentLoaded', function () { ## Abstract -The newest LLMs have explicit tooling and -support for returning properly formatted json responses. -While it is tempting to have LLMs use json tool or function calls to -return code or code edits, this is unwise. +The newest LLMs have support for returning properly formatted json responses, +making it easy for client applications to parse complex responses. +This makes it tempting for AI coding applications to +use tool function calls or other structured reply formats to +receive code from LLMs. +Unfortunately, LLMs write worse code when asked to wrap it in json, harming their ability to correctly solve coding tasks. -Returning code as plain (markdown) text results in 6% higher scores +Returning code as plain (markdown) text results in an average of 6% higher scores on a variant of the aider code editing benchmark. -Even OpenAI's newest gpt-4o-2024-08-06 with "strict" json support +This holds true across many top coding LLMs, +and even OpenAI's newest gpt-4o-2024-08-06 with "strict" json support suffers from this code-in-json handicap. ## Introduction -A lot of people wonder why aider doesn't have LLMs use tools or function calls to +A lot of people wonder why aider doesn't tell LLMs to +use tools or function calls to specify code edits. -Instead, aider asks LLMs to return code edits in plain text, like this: +Instead, aider asks for code edits in plain text, like this: ```` greeting.py @@ -144,31 +148,30 @@ def greeting(): ``` ```` -People expect that it would be easier and more reliable -for aider to parse a nicely formatted json -response, like this: +People expect that it would be easier and more reliable to use tool calls, +and parse a nicely formatted json +response: ``` { "filename": "greeting.py", - "start_line": 6, - "end_line": 7, - "new_content": "def greeting():\n print(\"Goodbye\")\n" + "search": "def greeting():\n print(\"Hello\")\n" + "replace": "def greeting():\n print(\"Goodbye\")\n" } ``` -This seems even more tempting as LLMs -get better tooling for reliably generating -valid json, or even enforcing that it meets a specific schema. -For example, OpenAI recently announced -[strict enforcement of json responses](). +This has become even more tempting as LLM providers +continue to improve their tooling for reliably generating +valid json. +For example, OpenAI recently announced the ability to +[strictly enforce that json responses will be syntactically correct +and conform to a specified schema](https://openai.com/index/introducing-structured-outputs-in-the-api/). -But it's not sufficient to just produce -valid json, it also -has to contain quality code. -Unfortunately, +But producing valid (schema compliant) json is not sufficient for this use case. +The json also has to contain valid, high quality code. +And unfortunately, LLMs write worse code when they're asked to -emit it wrapped in json. +wrap it in json. In some sense this shouldn't be surprising. Just look at the very simple @@ -176,24 +179,26 @@ json example above, with the escaped quotes `\"` and newlines `\n` mixed into the code. -Coding is complicated enough without having to escape all the special characters too. +Imagine if the code itself contained json or other quoted strings, +with their +own escape sequences. If you tried to write a program, would you do a better job -typing it normally +typing it out normally or as a properly escaped json string? + ## Quantifying the benefits of plain text - -Previous [benchmark results](/2023/07/02/benchmarks.html) +Previous [aider benchmark results](/2023/07/02/benchmarks.html) showed the superiority of returning code -as plain text coding compared to json-wrapped function calls. -But those results were obtained +as plain text coding compared to json-wrapped function calls. +Those results were obtained over a year ago, against far less -capable models. +capable models. OpenAI's newly announced support for "strict" json seemed like a good reason to investigate whether the newest models are still handicapped by json-wrapping code. @@ -207,17 +212,18 @@ results from Each model was given one try to solve [133 practice exercises from the Exercism python repository](/2023/07/02/benchmarks.html#the-benchmark). -This is the standard aider "code editing" benchmark, except restricted to a single attempt. +This is the standard aider "code editing" benchmark, but restricted to a single attempt +without a second try to "fix" any errors. -Each model was assessed by the benchmark with two +Each model was assessed by the benchmark using two different strategies for returning code: -- **Markdown** -- where the model simply returned the whole source code file in standard markdown triple-backtick fences. -- **Tool call** -- where the model is told to use a function to return the whole source code file. This requires the LLM to wrap the code in json. +- **Markdown** -- the model returned the whole source code file in standard markdown triple-backtick fences. +- **Tool call** -- the model used a tool function call to return the whole source code file. This requires the LLM to wrap the code in json. The markdown strategy is the same as -aider's "whole" edit format. -It asks the LLM to return a program like this: +aider's "whole" edit format, where the +LLM would return a source file like this: ```` Here is the program you asked for which prints "Hello": @@ -230,7 +236,9 @@ def greeting(): ```` The tool strategy requires the LLM to call the `write_file` function with -two parameters, like this: +two parameters, as shown below. +For maximum simplicity, the LLM didn't even have to specify the filename, +since the benchmark operates only on a single source file. ``` { @@ -242,13 +250,14 @@ two parameters, like this: Both of these formats avoid actually *editing* source files, to keep the task as simple as possible. -The LLM can emit the whole source file intact, +The LLM is able to emit the whole source file intact, which is much easier than correctly formulating instructions to edit portions of a file. -We are simply testing the effects of json-wrapping on the LLMs ability to write code to solve a task. +This experimental setup is designed to highlight +the effects of json-wrapping on the LLMs ability to write code to solve a task. ## Results From 341c08be3ecd58f1371b6e58eee8dbad57b57910 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 08:08:58 -0700 Subject: [PATCH 060/105] feat: average datapoints for each model/edit_format --- aider/website/_posts/2024-08-14-code-in-json.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 572aaf3be..bde150140 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -27,8 +27,10 @@ document.addEventListener('DOMContentLoaded', function () { var datasets = editFormats.map(format => ({ label: format, data: models.map(model => { - var item = yamlData.find(d => d.model === model && d.edit_format === format); - return item ? item.pass_rate_1 : null; + var items = yamlData.filter(d => d.model === model && d.edit_format === format); + if (items.length === 0) return null; + var average = items.reduce((sum, item) => sum + item.pass_rate_1, 0) / items.length; + return parseFloat(average.toFixed(1)); }), backgroundColor: function(context) { const format = context.dataset.label; From 9982cda5085dd450592486fd067943f3b984707a Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 08:11:54 -0700 Subject: [PATCH 061/105] 5 benchmark runs --- aider/website/_data/code-in-json.yml | 848 ++++++++++++++++++++++++--- 1 file changed, 767 insertions(+), 81 deletions(-) diff --git a/aider/website/_data/code-in-json.yml b/aider/website/_data/code-in-json.yml index 64c42a2d5..0f2bbcbed 100644 --- a/aider/website/_data/code-in-json.yml +++ b/aider/website/_data/code-in-json.yml @@ -1,9 +1,9 @@ -- dirname: 2024-08-14-18-26-18--json-gpt-4o-2024-08-06-whole +- dirname: 2024-08-15-13-17-11--json-no-lint-gpt-4o-2024-08-06-whole test_cases: 133 - model: gpt-4o-2024-08-06 - edit_format: Markdown - commit_hash: 94a2601-dirty - pass_rate_1: 62.4 + model: openai/gpt-4o-2024-08-06 + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 60.2 percent_cases_well_formed: 100.0 error_outputs: 0 num_malformed_responses: 0 @@ -13,62 +13,395 @@ syntax_errors: 0 indentation_errors: 0 exhausted_context_windows: 0 - test_timeouts: 3 - command: aider --model gpt-4o-2024-08-06 - date: 2024-08-14 + test_timeouts: 1 + command: aider --model openai/gpt-4o-2024-08-06 + date: 2024-08-15 versions: 0.50.2-dev - seconds_per_case: 6.8 - total_cost: 1.2717 - -- dirname: 2024-08-14-18-38-25--json-gpt-4o-2024-08-06-non-strict-func + seconds_per_case: 4.3 + total_cost: 0.7965 +- dirname: 2024-08-15-13-18-36--json-no-lint-gpt-4o-2024-08-06-func test_cases: 133 - model: gpt-4o-2024-08-06 - edit_format: Tool call - commit_hash: 2eb1946-dirty - pass_rate_1: 54.1 + model: openai/gpt-4o-2024-08-06 + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 57.9 percent_cases_well_formed: 100.0 - error_outputs: 7 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openai/gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 5.7 + total_cost: 0.8417 +- dirname: 2024-08-15-13-20-11--json-no-lint-gpt-4o-2024-05-13-whole + test_cases: 133 + model: openai/gpt-4o-2024-05-13 + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 56.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openai/gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 8.0 + total_cost: 1.5034 +- dirname: 2024-08-15-13-21-55--json-no-lint-gpt-4o-2024-05-13-func + test_cases: 133 + model: openai/gpt-4o-2024-05-13 + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 60.2 + percent_cases_well_formed: 100.0 + error_outputs: 2 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openai/gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 7.1 + total_cost: 1.2285 +- dirname: 2024-08-15-13-23-33--json-no-lint-claude-3.5-sonnet-whole + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 60.2 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 10.5 + total_cost: 1.6714 +- dirname: 2024-08-15-13-24-56--json-no-lint-claude-3.5-sonnet-func + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 53.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 9.7 + total_cost: 1.5980 +- dirname: 2024-08-15-13-26-38--json-no-lint-deepseek-coder-whole + test_cases: 133 + model: openrouter/deepseek/deepseek-coder + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 59.4 + percent_cases_well_formed: 100.0 + error_outputs: 2 num_malformed_responses: 0 num_with_malformed_responses: 0 user_asks: 2 lazy_comments: 0 - syntax_errors: 2 + syntax_errors: 0 indentation_errors: 0 exhausted_context_windows: 0 - test_timeouts: 4 - command: aider --model gpt-4o-2024-08-06 - date: 2024-08-14 + test_timeouts: 0 + command: aider --model openrouter/deepseek/deepseek-coder + date: 2024-08-15 versions: 0.50.2-dev - seconds_per_case: 11.5 - total_cost: 1.3819 - -- dirname: 2024-08-14-18-32-02--json-gpt-4o-2024-08-06-strict-func + seconds_per_case: 27.9 + total_cost: 0.0438 +- dirname: 2024-08-15-13-29-55--json-no-lint-deepseek-coder-func test_cases: 133 - model: gpt-4o-2024-08-06 - edit_format: Tool call (strict) - commit_hash: 2eb1946 + model: openrouter/deepseek/deepseek-coder + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 49.6 + percent_cases_well_formed: 100.0 + error_outputs: 3 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 4 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/deepseek/deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 20.5 + total_cost: 0.0329 +- dirname: 2024-08-15-13-50-03--json-no-lint-gpt-4o-2024-08-06-whole-2 + test_cases: 133 + model: openai/gpt-4o-2024-08-06 + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 61.7 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openai/gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 4.2 + total_cost: 0.7946 +- dirname: 2024-08-15-13-51-36--json-no-lint-gpt-4o-2024-08-06-func-2 + test_cases: 133 + model: openai/gpt-4o-2024-08-06 + edit_format: func + commit_hash: bac04a2 pass_rate_1: 56.4 percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openai/gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 6.4 + total_cost: 0.8390 +- dirname: 2024-08-15-13-53-23--json-no-lint-gpt-4o-2024-05-13-whole-2 + test_cases: 133 + model: openai/gpt-4o-2024-05-13 + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 59.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openai/gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 7.4 + total_cost: 1.4996 +- dirname: 2024-08-15-13-54-53--json-no-lint-gpt-4o-2024-05-13-func-2 + test_cases: 133 + model: openai/gpt-4o-2024-05-13 + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 60.2 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openai/gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 7.7 + total_cost: 1.2210 +- dirname: 2024-08-15-13-56-21--json-no-lint-claude-3.5-sonnet-whole-2 + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 60.9 + percent_cases_well_formed: 100.0 error_outputs: 1 num_malformed_responses: 0 num_with_malformed_responses: 0 user_asks: 0 lazy_comments: 0 - syntax_errors: 7 + syntax_errors: 0 indentation_errors: 0 exhausted_context_windows: 0 - test_timeouts: 4 - command: aider --model gpt-4o-2024-08-06 - date: 2024-08-14 + test_timeouts: 0 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-15 versions: 0.50.2-dev - seconds_per_case: 12.7 - total_cost: 1.3652 - -- dirname: 2024-08-14-20-15-19--json-sonnet-whole + seconds_per_case: 16.5 + total_cost: 1.6556 +- dirname: 2024-08-15-14-02-15--json-no-lint-claude-3.5-sonnet-func-2 test_cases: 133 - model: claude-3.5-sonnet - edit_format: Markdown - commit_hash: e2f14a2 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 51.9 + percent_cases_well_formed: 100.0 + error_outputs: 1 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 14.3 + total_cost: 1.5835 +- dirname: 2024-08-15-14-06-12--json-no-lint-deepseek-coder-whole-2 + test_cases: 133 + model: openrouter/deepseek/deepseek-coder + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 60.9 + percent_cases_well_formed: 100.0 + error_outputs: 2 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 1 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/deepseek/deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 25.8 + total_cost: 0.0439 +- dirname: 2024-08-15-14-09-22--json-no-lint-deepseek-coder-func-2 + test_cases: 133 + model: openrouter/deepseek/deepseek-coder + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 53.4 + percent_cases_well_formed: 100.0 + error_outputs: 5 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 6 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/deepseek/deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 18.8 + total_cost: 0.0333 +- dirname: 2024-08-15-14-11-45--json-no-lint-gpt-4o-2024-08-06-whole-3 + test_cases: 133 + model: openai/gpt-4o-2024-08-06 + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 60.9 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openai/gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 4.3 + total_cost: 0.7945 +- dirname: 2024-08-15-14-13-11--json-no-lint-gpt-4o-2024-08-06-func-3 + test_cases: 133 + model: openai/gpt-4o-2024-08-06 + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 56.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openai/gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 5.6 + total_cost: 0.8220 +- dirname: 2024-08-15-14-14-40--json-no-lint-gpt-4o-2024-05-13-whole-3 + test_cases: 133 + model: openai/gpt-4o-2024-05-13 + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 61.7 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 6 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openai/gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 8.8 + total_cost: 1.4993 +- dirname: 2024-08-15-14-16-34--json-no-lint-gpt-4o-2024-05-13-func-3 + test_cases: 133 + model: openai/gpt-4o-2024-05-13 + edit_format: func + commit_hash: bac04a2 pass_rate_1: 58.6 percent_cases_well_formed: 100.0 error_outputs: 0 @@ -80,75 +413,428 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model claude-3.5-sonnet - date: 2024-08-14 + command: aider --model openai/gpt-4o-2024-05-13 + date: 2024-08-15 versions: 0.50.2-dev - seconds_per_case: 19.7 - total_cost: 2.5335 - -- dirname: 2024-08-14-20-19-23--json-sonnet-non-strict-func + seconds_per_case: 8.7 + total_cost: 1.2064 +- dirname: 2024-08-15-14-17-51--json-no-lint-claude-3.5-sonnet-whole-3 test_cases: 133 - model: claude-3.5-sonnet - edit_format: Tool call - commit_hash: e2f14a2 - pass_rate_1: 52.6 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 60.2 percent_cases_well_formed: 100.0 - error_outputs: 1 + error_outputs: 0 num_malformed_responses: 0 num_with_malformed_responses: 0 - user_asks: 1 + user_asks: 0 lazy_comments: 0 - syntax_errors: 1 + syntax_errors: 0 indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model claude-3.5-sonnet - date: 2024-08-14 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-15 versions: 0.50.2-dev - seconds_per_case: 18.9 - total_cost: 2.6341 - -- dirname: 2024-08-14-21-23-27--json-deepseek-whole + seconds_per_case: 11.0 + total_cost: 1.6555 +- dirname: 2024-08-15-14-19-19--json-no-lint-claude-3.5-sonnet-func-3 test_cases: 133 - model: deepseek-coder - edit_format: Markdown - commit_hash: e2f14a2 - pass_rate_1: 61.7 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 51.1 percent_cases_well_formed: 100.0 - error_outputs: 1 + error_outputs: 3 num_malformed_responses: 0 num_with_malformed_responses: 0 - user_asks: 1 + user_asks: 0 lazy_comments: 0 syntax_errors: 0 indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model deepseek-coder - date: 2024-08-14 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-15 versions: 0.50.2-dev - seconds_per_case: 23.0 - total_cost: 0.0439 - -- dirname: 2024-08-14-21-20-46--json-deepseek-non-strict-func + seconds_per_case: 10.3 + total_cost: 1.5614 +- dirname: 2024-08-15-14-21-06--json-no-lint-deepseek-coder-whole-3 test_cases: 133 - model: deepseek-coder - edit_format: Tool call - commit_hash: e2f14a2 - pass_rate_1: 54.1 + model: openrouter/deepseek/deepseek-coder + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 61.7 percent_cases_well_formed: 100.0 - error_outputs: 9 + error_outputs: 3 num_malformed_responses: 0 num_with_malformed_responses: 0 - user_asks: 5 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model openrouter/deepseek/deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 24.4 + total_cost: 0.0439 +- dirname: 2024-08-15-14-24-46--json-no-lint-deepseek-coder-func-3 + test_cases: 133 + model: openrouter/deepseek/deepseek-coder + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 52.6 + percent_cases_well_formed: 100.0 + error_outputs: 3 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 12 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/deepseek/deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 19.0 + total_cost: 0.0334 +- dirname: 2024-08-15-14-27-17--json-no-lint-gpt-4o-2024-08-06-whole-4 + test_cases: 133 + model: openai/gpt-4o-2024-08-06 + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 60.2 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openai/gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 4.3 + total_cost: 0.8015 +- dirname: 2024-08-15-14-28-58--json-no-lint-gpt-4o-2024-08-06-func-4 + test_cases: 133 + model: openai/gpt-4o-2024-08-06 + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 60.2 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openai/gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 6.0 + total_cost: 0.8394 +- dirname: 2024-08-15-14-30-48--json-no-lint-gpt-4o-2024-05-13-whole-4 + test_cases: 133 + model: openai/gpt-4o-2024-05-13 + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 61.7 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 6 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openai/gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 12.3 + total_cost: 1.4919 +- dirname: 2024-08-15-14-32-58--json-no-lint-gpt-4o-2024-05-13-func-4 + test_cases: 133 + model: openai/gpt-4o-2024-05-13 + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 59.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 lazy_comments: 0 syntax_errors: 2 indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model deepseek-coder - date: 2024-08-14 + command: aider --model openai/gpt-4o-2024-05-13 + date: 2024-08-15 versions: 0.50.2-dev - seconds_per_case: 17.4 - total_cost: 0.0332 - + seconds_per_case: 11.1 + total_cost: 1.2120 +- dirname: 2024-08-15-14-34-39--json-no-lint-claude-3.5-sonnet-whole-4 + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 60.9 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 11.3 + total_cost: 1.6635 +- dirname: 2024-08-15-14-36-18--json-no-lint-claude-3.5-sonnet-func-4 + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 55.6 + percent_cases_well_formed: 100.0 + error_outputs: 1 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 10.5 + total_cost: 1.5768 +- dirname: 2024-08-15-14-38-35--json-no-lint-deepseek-coder-whole-4 + test_cases: 133 + model: openrouter/deepseek/deepseek-coder + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 59.4 + percent_cases_well_formed: 100.0 + error_outputs: 2 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/deepseek/deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 24.5 + total_cost: 0.0438 +- dirname: 2024-08-15-14-41-36--json-no-lint-deepseek-coder-func-4 + test_cases: 133 + model: openrouter/deepseek/deepseek-coder + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 49.6 + percent_cases_well_formed: 100.0 + error_outputs: 7 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 2 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/deepseek/deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 18.7 + total_cost: 0.0333 +- dirname: 2024-08-15-14-44-11--json-no-lint-gpt-4o-2024-08-06-whole-5 + test_cases: 133 + model: openai/gpt-4o-2024-08-06 + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 60.9 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openai/gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 4.6 + total_cost: 0.8023 +- dirname: 2024-08-15-14-45-40--json-no-lint-gpt-4o-2024-08-06-func-5 + test_cases: 133 + model: openai/gpt-4o-2024-08-06 + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 57.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 3 + command: aider --model openai/gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 6.3 + total_cost: 0.8354 +- dirname: 2024-08-15-14-47-39--json-no-lint-gpt-4o-2024-05-13-whole-5 + test_cases: 133 + model: openai/gpt-4o-2024-05-13 + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 60.2 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 9 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openai/gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 10.7 + total_cost: 1.4982 +- dirname: 2024-08-15-14-49-44--json-no-lint-gpt-4o-2024-05-13-func-5 + test_cases: 133 + model: openai/gpt-4o-2024-05-13 + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 59.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 4 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openai/gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 10.5 + total_cost: 1.2099 +- dirname: 2024-08-15-14-51-18--json-no-lint-claude-3.5-sonnet-whole-5 + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 60.2 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 11.4 + total_cost: 1.6685 +- dirname: 2024-08-15-14-52-48--json-no-lint-claude-3.5-sonnet-func-5 + test_cases: 133 + model: openrouter/anthropic/claude-3.5-sonnet + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 53.4 + percent_cases_well_formed: 100.0 + error_outputs: 2 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model openrouter/anthropic/claude-3.5-sonnet + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 10.8 + total_cost: 1.5786 +- dirname: 2024-08-15-14-54-41--json-no-lint-deepseek-coder-whole-5 + test_cases: 133 + model: openrouter/deepseek/deepseek-coder + edit_format: whole + commit_hash: bac04a2 + pass_rate_1: 61.7 + percent_cases_well_formed: 100.0 + error_outputs: 2 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 2 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/deepseek/deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 24.5 + total_cost: 0.0439 +- dirname: 2024-08-15-14-57-51--json-no-lint-deepseek-coder-func-5 + test_cases: 133 + model: openrouter/deepseek/deepseek-coder + edit_format: func + commit_hash: bac04a2 + pass_rate_1: 53.4 + percent_cases_well_formed: 100.0 + error_outputs: 5 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 4 + indentation_errors: 1 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model openrouter/deepseek/deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 18.5 + total_cost: 0.0330 From 957374a6114305d94b5956b26437710718e59ef5 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 08:29:43 -0700 Subject: [PATCH 062/105] fix: Update code-in-json post with improved formatting and performance details --- aider/website/_posts/2024-08-14-code-in-json.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index bde150140..22f2dc852 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -36,9 +36,9 @@ document.addEventListener('DOMContentLoaded', function () { const format = context.dataset.label; if (format === 'Markdown') { return 'rgba(54, 162, 235, 0.8)'; - } else if (format.startsWith('Tool call')) { + } else if (format.startsWith('JSON')) { const ctx = context.chart.ctx; - const gradient = ctx.createPattern(createStripedCanvas(format === 'Tool call (strict)'), 'repeat'); + const gradient = ctx.createPattern(createStripedCanvas(format === 'JSON (strict)'), 'repeat'); return gradient; } else { return 'rgba(75, 192, 192, 0.8)'; @@ -124,8 +124,9 @@ receive code from LLMs. Unfortunately, LLMs write worse code when asked to wrap it in json, harming their ability to correctly solve coding tasks. -Returning code as plain (markdown) text results in an average of 6% higher scores -on a variant of the aider code editing benchmark. +Returning code as plain (markdown) text results in lower scores +on a variant of the aider code editing benchmark, often significantly harming coding +performance. This holds true across many top coding LLMs, and even OpenAI's newest gpt-4o-2024-08-06 with "strict" json support suffers from this code-in-json handicap. From ea38f91c702d5eba27af87b7aedb4d1a29204f65 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 08:29:44 -0700 Subject: [PATCH 063/105] feat: Sort x-axis by model name --- aider/website/_posts/2024-08-14-code-in-json.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 22f2dc852..23b58aa33 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -21,7 +21,7 @@ document.addEventListener('DOMContentLoaded', function () { var yamlData = {{ site.data.code-in-json | jsonify }}; - var models = [...new Set(yamlData.map(item => item.model))]; + var models = [...new Set(yamlData.map(item => item.model))].sort(); var editFormats = [...new Set(yamlData.map(item => item.edit_format))]; var datasets = editFormats.map(format => ({ From 04e816ff2e2de14359e69a7e903357e8697523e8 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 09:49:51 -0700 Subject: [PATCH 064/105] copy --- aider/website/_data/code-in-json.yml | 324 +++++++++++------- .../website/_posts/2024-08-14-code-in-json.md | 118 ++++--- 2 files changed, 282 insertions(+), 160 deletions(-) diff --git a/aider/website/_data/code-in-json.yml b/aider/website/_data/code-in-json.yml index 0f2bbcbed..78efd129f 100644 --- a/aider/website/_data/code-in-json.yml +++ b/aider/website/_data/code-in-json.yml @@ -1,7 +1,7 @@ - dirname: 2024-08-15-13-17-11--json-no-lint-gpt-4o-2024-08-06-whole test_cases: 133 - model: openai/gpt-4o-2024-08-06 - edit_format: whole + model: gpt-4o-2024-08-06 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 60.2 percent_cases_well_formed: 100.0 @@ -14,15 +14,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openai/gpt-4o-2024-08-06 + command: aider --model gpt-4o-2024-08-06 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 4.3 total_cost: 0.7965 - dirname: 2024-08-15-13-18-36--json-no-lint-gpt-4o-2024-08-06-func test_cases: 133 - model: openai/gpt-4o-2024-08-06 - edit_format: func + model: gpt-4o-2024-08-06 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 57.9 percent_cases_well_formed: 100.0 @@ -35,15 +35,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openai/gpt-4o-2024-08-06 + command: aider --model gpt-4o-2024-08-06 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 5.7 total_cost: 0.8417 - dirname: 2024-08-15-13-20-11--json-no-lint-gpt-4o-2024-05-13-whole test_cases: 133 - model: openai/gpt-4o-2024-05-13 - edit_format: whole + model: gpt-4o-2024-05-13 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 56.4 percent_cases_well_formed: 100.0 @@ -56,15 +56,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openai/gpt-4o-2024-05-13 + command: aider --model gpt-4o-2024-05-13 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 8.0 total_cost: 1.5034 - dirname: 2024-08-15-13-21-55--json-no-lint-gpt-4o-2024-05-13-func test_cases: 133 - model: openai/gpt-4o-2024-05-13 - edit_format: func + model: gpt-4o-2024-05-13 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 60.2 percent_cases_well_formed: 100.0 @@ -77,15 +77,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openai/gpt-4o-2024-05-13 + command: aider --model gpt-4o-2024-05-13 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 7.1 total_cost: 1.2285 - dirname: 2024-08-15-13-23-33--json-no-lint-claude-3.5-sonnet-whole test_cases: 133 - model: openrouter/anthropic/claude-3.5-sonnet - edit_format: whole + model: claude-3.5-sonnet + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 60.2 percent_cases_well_formed: 100.0 @@ -98,15 +98,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openrouter/anthropic/claude-3.5-sonnet + command: aider --model claude-3.5-sonnet date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 10.5 total_cost: 1.6714 - dirname: 2024-08-15-13-24-56--json-no-lint-claude-3.5-sonnet-func test_cases: 133 - model: openrouter/anthropic/claude-3.5-sonnet - edit_format: func + model: claude-3.5-sonnet + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 53.4 percent_cases_well_formed: 100.0 @@ -119,15 +119,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openrouter/anthropic/claude-3.5-sonnet + command: aider --model claude-3.5-sonnet date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 9.7 total_cost: 1.5980 - dirname: 2024-08-15-13-26-38--json-no-lint-deepseek-coder-whole test_cases: 133 - model: openrouter/deepseek/deepseek-coder - edit_format: whole + model: deepseek-coder V2 0724 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 59.4 percent_cases_well_formed: 100.0 @@ -140,15 +140,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openrouter/deepseek/deepseek-coder + command: aider --model deepseek-coder date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 27.9 total_cost: 0.0438 - dirname: 2024-08-15-13-29-55--json-no-lint-deepseek-coder-func test_cases: 133 - model: openrouter/deepseek/deepseek-coder - edit_format: func + model: deepseek-coder V2 0724 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 49.6 percent_cases_well_formed: 100.0 @@ -161,15 +161,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openrouter/deepseek/deepseek-coder + command: aider --model deepseek-coder date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 20.5 total_cost: 0.0329 - dirname: 2024-08-15-13-50-03--json-no-lint-gpt-4o-2024-08-06-whole-2 test_cases: 133 - model: openai/gpt-4o-2024-08-06 - edit_format: whole + model: gpt-4o-2024-08-06 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 61.7 percent_cases_well_formed: 100.0 @@ -182,15 +182,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openai/gpt-4o-2024-08-06 + command: aider --model gpt-4o-2024-08-06 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 4.2 total_cost: 0.7946 - dirname: 2024-08-15-13-51-36--json-no-lint-gpt-4o-2024-08-06-func-2 test_cases: 133 - model: openai/gpt-4o-2024-08-06 - edit_format: func + model: gpt-4o-2024-08-06 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 56.4 percent_cases_well_formed: 100.0 @@ -203,15 +203,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openai/gpt-4o-2024-08-06 + command: aider --model gpt-4o-2024-08-06 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 6.4 total_cost: 0.8390 - dirname: 2024-08-15-13-53-23--json-no-lint-gpt-4o-2024-05-13-whole-2 test_cases: 133 - model: openai/gpt-4o-2024-05-13 - edit_format: whole + model: gpt-4o-2024-05-13 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 59.4 percent_cases_well_formed: 100.0 @@ -224,15 +224,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openai/gpt-4o-2024-05-13 + command: aider --model gpt-4o-2024-05-13 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 7.4 total_cost: 1.4996 - dirname: 2024-08-15-13-54-53--json-no-lint-gpt-4o-2024-05-13-func-2 test_cases: 133 - model: openai/gpt-4o-2024-05-13 - edit_format: func + model: gpt-4o-2024-05-13 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 60.2 percent_cases_well_formed: 100.0 @@ -245,15 +245,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openai/gpt-4o-2024-05-13 + command: aider --model gpt-4o-2024-05-13 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 7.7 total_cost: 1.2210 - dirname: 2024-08-15-13-56-21--json-no-lint-claude-3.5-sonnet-whole-2 test_cases: 133 - model: openrouter/anthropic/claude-3.5-sonnet - edit_format: whole + model: claude-3.5-sonnet + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 60.9 percent_cases_well_formed: 100.0 @@ -266,15 +266,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openrouter/anthropic/claude-3.5-sonnet + command: aider --model claude-3.5-sonnet date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 16.5 total_cost: 1.6556 - dirname: 2024-08-15-14-02-15--json-no-lint-claude-3.5-sonnet-func-2 test_cases: 133 - model: openrouter/anthropic/claude-3.5-sonnet - edit_format: func + model: claude-3.5-sonnet + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 51.9 percent_cases_well_formed: 100.0 @@ -287,15 +287,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openrouter/anthropic/claude-3.5-sonnet + command: aider --model claude-3.5-sonnet date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 14.3 total_cost: 1.5835 - dirname: 2024-08-15-14-06-12--json-no-lint-deepseek-coder-whole-2 test_cases: 133 - model: openrouter/deepseek/deepseek-coder - edit_format: whole + model: deepseek-coder V2 0724 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 60.9 percent_cases_well_formed: 100.0 @@ -308,15 +308,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openrouter/deepseek/deepseek-coder + command: aider --model deepseek-coder date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 25.8 total_cost: 0.0439 - dirname: 2024-08-15-14-09-22--json-no-lint-deepseek-coder-func-2 test_cases: 133 - model: openrouter/deepseek/deepseek-coder - edit_format: func + model: deepseek-coder V2 0724 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 53.4 percent_cases_well_formed: 100.0 @@ -329,15 +329,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openrouter/deepseek/deepseek-coder + command: aider --model deepseek-coder date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 18.8 total_cost: 0.0333 - dirname: 2024-08-15-14-11-45--json-no-lint-gpt-4o-2024-08-06-whole-3 test_cases: 133 - model: openai/gpt-4o-2024-08-06 - edit_format: whole + model: gpt-4o-2024-08-06 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 60.9 percent_cases_well_formed: 100.0 @@ -350,15 +350,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openai/gpt-4o-2024-08-06 + command: aider --model gpt-4o-2024-08-06 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 4.3 total_cost: 0.7945 - dirname: 2024-08-15-14-13-11--json-no-lint-gpt-4o-2024-08-06-func-3 test_cases: 133 - model: openai/gpt-4o-2024-08-06 - edit_format: func + model: gpt-4o-2024-08-06 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 56.4 percent_cases_well_formed: 100.0 @@ -371,15 +371,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openai/gpt-4o-2024-08-06 + command: aider --model gpt-4o-2024-08-06 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 5.6 total_cost: 0.8220 - dirname: 2024-08-15-14-14-40--json-no-lint-gpt-4o-2024-05-13-whole-3 test_cases: 133 - model: openai/gpt-4o-2024-05-13 - edit_format: whole + model: gpt-4o-2024-05-13 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 61.7 percent_cases_well_formed: 100.0 @@ -392,15 +392,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openai/gpt-4o-2024-05-13 + command: aider --model gpt-4o-2024-05-13 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 8.8 total_cost: 1.4993 - dirname: 2024-08-15-14-16-34--json-no-lint-gpt-4o-2024-05-13-func-3 test_cases: 133 - model: openai/gpt-4o-2024-05-13 - edit_format: func + model: gpt-4o-2024-05-13 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 58.6 percent_cases_well_formed: 100.0 @@ -413,15 +413,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openai/gpt-4o-2024-05-13 + command: aider --model gpt-4o-2024-05-13 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 8.7 total_cost: 1.2064 - dirname: 2024-08-15-14-17-51--json-no-lint-claude-3.5-sonnet-whole-3 test_cases: 133 - model: openrouter/anthropic/claude-3.5-sonnet - edit_format: whole + model: claude-3.5-sonnet + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 60.2 percent_cases_well_formed: 100.0 @@ -434,15 +434,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openrouter/anthropic/claude-3.5-sonnet + command: aider --model claude-3.5-sonnet date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 11.0 total_cost: 1.6555 - dirname: 2024-08-15-14-19-19--json-no-lint-claude-3.5-sonnet-func-3 test_cases: 133 - model: openrouter/anthropic/claude-3.5-sonnet - edit_format: func + model: claude-3.5-sonnet + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 51.1 percent_cases_well_formed: 100.0 @@ -455,15 +455,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openrouter/anthropic/claude-3.5-sonnet + command: aider --model claude-3.5-sonnet date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 10.3 total_cost: 1.5614 - dirname: 2024-08-15-14-21-06--json-no-lint-deepseek-coder-whole-3 test_cases: 133 - model: openrouter/deepseek/deepseek-coder - edit_format: whole + model: deepseek-coder V2 0724 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 61.7 percent_cases_well_formed: 100.0 @@ -476,15 +476,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 3 - command: aider --model openrouter/deepseek/deepseek-coder + command: aider --model deepseek-coder date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 24.4 total_cost: 0.0439 - dirname: 2024-08-15-14-24-46--json-no-lint-deepseek-coder-func-3 test_cases: 133 - model: openrouter/deepseek/deepseek-coder - edit_format: func + model: deepseek-coder V2 0724 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 52.6 percent_cases_well_formed: 100.0 @@ -497,15 +497,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openrouter/deepseek/deepseek-coder + command: aider --model deepseek-coder date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 19.0 total_cost: 0.0334 - dirname: 2024-08-15-14-27-17--json-no-lint-gpt-4o-2024-08-06-whole-4 test_cases: 133 - model: openai/gpt-4o-2024-08-06 - edit_format: whole + model: gpt-4o-2024-08-06 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 60.2 percent_cases_well_formed: 100.0 @@ -518,15 +518,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openai/gpt-4o-2024-08-06 + command: aider --model gpt-4o-2024-08-06 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 4.3 total_cost: 0.8015 - dirname: 2024-08-15-14-28-58--json-no-lint-gpt-4o-2024-08-06-func-4 test_cases: 133 - model: openai/gpt-4o-2024-08-06 - edit_format: func + model: gpt-4o-2024-08-06 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 60.2 percent_cases_well_formed: 100.0 @@ -539,15 +539,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openai/gpt-4o-2024-08-06 + command: aider --model gpt-4o-2024-08-06 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 6.0 total_cost: 0.8394 - dirname: 2024-08-15-14-30-48--json-no-lint-gpt-4o-2024-05-13-whole-4 test_cases: 133 - model: openai/gpt-4o-2024-05-13 - edit_format: whole + model: gpt-4o-2024-05-13 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 61.7 percent_cases_well_formed: 100.0 @@ -560,15 +560,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openai/gpt-4o-2024-05-13 + command: aider --model gpt-4o-2024-05-13 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 12.3 total_cost: 1.4919 - dirname: 2024-08-15-14-32-58--json-no-lint-gpt-4o-2024-05-13-func-4 test_cases: 133 - model: openai/gpt-4o-2024-05-13 - edit_format: func + model: gpt-4o-2024-05-13 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 59.4 percent_cases_well_formed: 100.0 @@ -581,15 +581,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openai/gpt-4o-2024-05-13 + command: aider --model gpt-4o-2024-05-13 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 11.1 total_cost: 1.2120 - dirname: 2024-08-15-14-34-39--json-no-lint-claude-3.5-sonnet-whole-4 test_cases: 133 - model: openrouter/anthropic/claude-3.5-sonnet - edit_format: whole + model: claude-3.5-sonnet + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 60.9 percent_cases_well_formed: 100.0 @@ -602,15 +602,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openrouter/anthropic/claude-3.5-sonnet + command: aider --model claude-3.5-sonnet date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 11.3 total_cost: 1.6635 - dirname: 2024-08-15-14-36-18--json-no-lint-claude-3.5-sonnet-func-4 test_cases: 133 - model: openrouter/anthropic/claude-3.5-sonnet - edit_format: func + model: claude-3.5-sonnet + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 55.6 percent_cases_well_formed: 100.0 @@ -623,15 +623,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openrouter/anthropic/claude-3.5-sonnet + command: aider --model claude-3.5-sonnet date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 10.5 total_cost: 1.5768 - dirname: 2024-08-15-14-38-35--json-no-lint-deepseek-coder-whole-4 test_cases: 133 - model: openrouter/deepseek/deepseek-coder - edit_format: whole + model: deepseek-coder V2 0724 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 59.4 percent_cases_well_formed: 100.0 @@ -644,15 +644,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openrouter/deepseek/deepseek-coder + command: aider --model deepseek-coder date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 24.5 total_cost: 0.0438 - dirname: 2024-08-15-14-41-36--json-no-lint-deepseek-coder-func-4 test_cases: 133 - model: openrouter/deepseek/deepseek-coder - edit_format: func + model: deepseek-coder V2 0724 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 49.6 percent_cases_well_formed: 100.0 @@ -665,15 +665,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openrouter/deepseek/deepseek-coder + command: aider --model deepseek-coder date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 18.7 total_cost: 0.0333 - dirname: 2024-08-15-14-44-11--json-no-lint-gpt-4o-2024-08-06-whole-5 test_cases: 133 - model: openai/gpt-4o-2024-08-06 - edit_format: whole + model: gpt-4o-2024-08-06 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 60.9 percent_cases_well_formed: 100.0 @@ -686,15 +686,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openai/gpt-4o-2024-08-06 + command: aider --model gpt-4o-2024-08-06 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 4.6 total_cost: 0.8023 - dirname: 2024-08-15-14-45-40--json-no-lint-gpt-4o-2024-08-06-func-5 test_cases: 133 - model: openai/gpt-4o-2024-08-06 - edit_format: func + model: gpt-4o-2024-08-06 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 57.1 percent_cases_well_formed: 100.0 @@ -707,15 +707,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 3 - command: aider --model openai/gpt-4o-2024-08-06 + command: aider --model gpt-4o-2024-08-06 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 6.3 total_cost: 0.8354 - dirname: 2024-08-15-14-47-39--json-no-lint-gpt-4o-2024-05-13-whole-5 test_cases: 133 - model: openai/gpt-4o-2024-05-13 - edit_format: whole + model: gpt-4o-2024-05-13 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 60.2 percent_cases_well_formed: 100.0 @@ -728,15 +728,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openai/gpt-4o-2024-05-13 + command: aider --model gpt-4o-2024-05-13 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 10.7 total_cost: 1.4982 - dirname: 2024-08-15-14-49-44--json-no-lint-gpt-4o-2024-05-13-func-5 test_cases: 133 - model: openai/gpt-4o-2024-05-13 - edit_format: func + model: gpt-4o-2024-05-13 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 59.4 percent_cases_well_formed: 100.0 @@ -749,15 +749,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openai/gpt-4o-2024-05-13 + command: aider --model gpt-4o-2024-05-13 date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 10.5 total_cost: 1.2099 - dirname: 2024-08-15-14-51-18--json-no-lint-claude-3.5-sonnet-whole-5 test_cases: 133 - model: openrouter/anthropic/claude-3.5-sonnet - edit_format: whole + model: claude-3.5-sonnet + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 60.2 percent_cases_well_formed: 100.0 @@ -770,15 +770,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openrouter/anthropic/claude-3.5-sonnet + command: aider --model claude-3.5-sonnet date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 11.4 total_cost: 1.6685 - dirname: 2024-08-15-14-52-48--json-no-lint-claude-3.5-sonnet-func-5 test_cases: 133 - model: openrouter/anthropic/claude-3.5-sonnet - edit_format: func + model: claude-3.5-sonnet + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 53.4 percent_cases_well_formed: 100.0 @@ -791,15 +791,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 - command: aider --model openrouter/anthropic/claude-3.5-sonnet + command: aider --model claude-3.5-sonnet date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 10.8 total_cost: 1.5786 - dirname: 2024-08-15-14-54-41--json-no-lint-deepseek-coder-whole-5 test_cases: 133 - model: openrouter/deepseek/deepseek-coder - edit_format: whole + model: deepseek-coder V2 0724 + edit_format: Markdown commit_hash: bac04a2 pass_rate_1: 61.7 percent_cases_well_formed: 100.0 @@ -812,15 +812,15 @@ indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openrouter/deepseek/deepseek-coder + command: aider --model deepseek-coder date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 24.5 total_cost: 0.0439 - dirname: 2024-08-15-14-57-51--json-no-lint-deepseek-coder-func-5 test_cases: 133 - model: openrouter/deepseek/deepseek-coder - edit_format: func + model: deepseek-coder V2 0724 + edit_format: JSON commit_hash: bac04a2 pass_rate_1: 53.4 percent_cases_well_formed: 100.0 @@ -833,8 +833,92 @@ indentation_errors: 1 exhausted_context_windows: 0 test_timeouts: 0 - command: aider --model openrouter/deepseek/deepseek-coder + command: aider --model deepseek-coder date: 2024-08-15 versions: 0.50.2-dev seconds_per_case: 18.5 total_cost: 0.0330 +- dirname: 2024-08-15-15-12-55--json-no-lint-strict-gpt-4o-2024-08-06-func-2 + test_cases: 133 + model: gpt-4o-2024-08-06 + edit_format: JSON (strict) + commit_hash: bf2d5fe + pass_rate_1: 57.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 5.9 + total_cost: 0.8216 +- dirname: 2024-08-15-15-14-31--json-no-lint-strict-gpt-4o-2024-08-06-func-3 + test_cases: 133 + model: gpt-4o-2024-08-06 + edit_format: JSON (strict) + commit_hash: bf2d5fe + pass_rate_1: 54.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 2 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 6.3 + total_cost: 0.8410 +- dirname: 2024-08-15-15-16-14--json-no-lint-strict-gpt-4o-2024-08-06-func-4 + test_cases: 133 + model: gpt-4o-2024-08-06 + edit_format: JSON (strict) + commit_hash: bf2d5fe + pass_rate_1: 59.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 5.9 + total_cost: 0.8203 +- dirname: 2024-08-15-15-17-50--json-no-lint-strict-gpt-4o-2024-08-06-func-5 + test_cases: 133 + model: gpt-4o-2024-08-06 + edit_format: JSON (strict) + commit_hash: bf2d5fe + pass_rate_1: 57.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 1 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model gpt-4o-2024-08-06 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 6.1 + total_cost: 0.8415 diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 23b58aa33..9f3345971 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -1,6 +1,6 @@ --- -title: LLMs are bad at returning code in json -excerpt: LLMs write worse code if you ask them to return the code wrapped in json (via a tool or function call). +title: LLMs are bad at returning code in JSON +excerpt: LLMs write worse code if you ask them to return the code wrapped in JSON (via a tool or function call). highlight_image: /assets/code-in-json.jpg draft: true nav_exclude: true @@ -9,7 +9,7 @@ nav_exclude: true {% endif %} -# LLMs are bad at returning code in json +# LLMs are bad at returning code in JSON @@ -67,7 +67,7 @@ document.addEventListener('DOMContentLoaded', function () { beginAtZero: true, title: { display: true, - text: 'Pass Rate (%)' + text: 'Pass Rate (%, average of 5 runs)' }, max: 70 } @@ -75,7 +75,7 @@ document.addEventListener('DOMContentLoaded', function () { plugins: { title: { display: true, - text: 'Pass rate by model and code return strategy', + text: 'Pass rate by model and code wrapping strategy', font: { size: 16 } @@ -116,20 +116,22 @@ document.addEventListener('DOMContentLoaded', function () { ## Abstract -The newest LLMs have support for returning properly formatted json responses, +The newest LLMs have support for returning properly formatted JSON responses, making it easy for client applications to parse complex responses. This makes it tempting for AI coding applications to use tool function calls or other structured reply formats to receive code from LLMs. Unfortunately, -LLMs write worse code when asked to wrap it in json, harming their ability +LLMs write worse code when asked to wrap it in JSON, harming their ability to correctly solve coding tasks. -Returning code as plain (markdown) text results in lower scores -on a variant of the aider code editing benchmark, often significantly harming coding -performance. +On a variant of the aider code editing benchmark, +JSON-wrapping code +often significantly harms coding +performance +compared to returning code as plain (markdown) text. This holds true across many top coding LLMs, -and even OpenAI's newest gpt-4o-2024-08-06 with "strict" json support -suffers from this code-in-json handicap. +and even OpenAI's newest gpt-4o-2024-08-06 with "strict" JSON support +suffers from this code-in-JSON handicap. ## Introduction @@ -152,8 +154,7 @@ def greeting(): ```` People expect that it would be easier and more reliable to use tool calls, -and parse a nicely formatted json -response: +which would return a structured JSON response: ``` { @@ -165,32 +166,33 @@ response: This has become even more tempting as LLM providers continue to improve their tooling for reliably generating -valid json. +valid JSON. For example, OpenAI recently announced the ability to -[strictly enforce that json responses will be syntactically correct +[strictly enforce that JSON responses will be syntactically correct and conform to a specified schema](https://openai.com/index/introducing-structured-outputs-in-the-api/). -But producing valid (schema compliant) json is not sufficient for this use case. -The json also has to contain valid, high quality code. -And unfortunately, +But producing valid (schema compliant) JSON is not sufficient for this use case. +The JSON also has to contain valid, high quality code. +Unfortunately, LLMs write worse code when they're asked to -wrap it in json. +wrap it in JSON. In some sense this shouldn't be surprising. Just look at the very simple -json example above, with the escaped +JSON example above, with the escaped quotes `\"` and newlines `\n` mixed into the code. -Imagine if the code itself contained json or other quoted strings, +Imagine the additional +complexity +if the code itself contained JSON or other quoted strings, with their own escape sequences. -If you tried to write a program, -would you do a better job +Would *you* write better code by typing it out normally or as a properly escaped -json string? +JSON string? ## Quantifying the benefits of plain text @@ -198,31 +200,33 @@ json string? Previous [aider benchmark results](/2023/07/02/benchmarks.html) showed the superiority of returning code -as plain text coding compared to json-wrapped function calls. +as plain text compared to JSON-wrapped function calls. Those results were obtained over a year ago, against far less capable models. -OpenAI's newly announced support for "strict" json seemed like a good reason to -investigate whether the newest models are still handicapped by json-wrapping code. +OpenAI's newly announced support for "strict" JSON seemed like a good reason to +investigate whether the newest models are still handicapped by JSON-wrapping code. The graph above shows benchmark results from -3 of the strongest code editing models: +4 of the strongest code editing models: -- gpt-4o-2024-08-06 - claude-3-5-sonnet-20240620 - deepseek-coder (V2 0724) +- gpt-4o-2024-05-13 +- gpt-4o-2024-08-06 Each model was given one try to solve [133 practice exercises from the Exercism python repository](/2023/07/02/benchmarks.html#the-benchmark). This is the standard aider "code editing" benchmark, but restricted to a single attempt without a second try to "fix" any errors. -Each model was assessed by the benchmark using two -different strategies for returning code: +The benchmark assessed the models coding ability +using different strategies for returning code: - **Markdown** -- the model returned the whole source code file in standard markdown triple-backtick fences. -- **Tool call** -- the model used a tool function call to return the whole source code file. This requires the LLM to wrap the code in json. +- **JSON** -- the model used a tool function call to return the whole source code file. This requires the LLM to wrap the code in JSON. +- **JSON (strict)** -- the same as the "JSON" strategy, but with `strict=True`. Only gpt-4o-2024-08-06 supports this setting. The markdown strategy is the same as aider's "whole" edit format, where the @@ -238,10 +242,10 @@ def greeting(): ``` ```` -The tool strategy requires the LLM to call the `write_file` function with +The JSON and JSON (strict) strategies required the LLM to call the `write_file` function with two parameters, as shown below. -For maximum simplicity, the LLM didn't even have to specify the filename, -since the benchmark operates only on a single source file. +For maximum simplicity, the LLM didn't have to specify the filename, +since the benchmark operates on one source file at a time. ``` { @@ -250,7 +254,7 @@ since the benchmark operates only on a single source file. } ``` -Both of these formats avoid actually *editing* source files, to keep +These strategies avoid actually *editing* source files, to keep the task as simple as possible. The LLM is able to emit the whole source file intact, @@ -260,9 +264,43 @@ instructions to edit portions of a file. This experimental setup is designed to highlight -the effects of json-wrapping on the LLMs ability to write code to solve a task. +the effects of JSON-wrapping on the LLMs ability to write code to solve a task. +The results in the graph are the average of 5 runs for each +model & strategy combination. ## Results -All 3 models did significantly worse on the benchmark when asked to -return json-wrapped code in a tool function call. +All of the models did worse on the benchmark when asked to +return JSON-wrapped code in a tool function call. +Most did significantly worse, performing far below +the result obtained with the markdown strategy. + +Some noteworthy observations: + +- OpenAI's gpt-4o-2024-05-13 was the only model where the markdown and JSON results were +close. Using JSON only dropped the score by 0.3 percent, a difference which is +probably within the margin of error for 5 trials. +- The use of OpenAI's new strict mode seemed to harm the results for gpt-4o-2024-08-06 +as compared to non-strict JSON. +Of course, both JSON results were well below the markdown result. +- The results from Sonnet and DeepSeek Coder suffered the worst harm from JSON wrapping. + +## Conclusions + +While the quantitative results differ from the similar +[July 2023 experiments](/2023/07/02/benchmarks.html), +the conclusion seems unchanged: LLMs are bad at returning code in JSON. + +OpenAI appears to be making progress in allowing LLMs to return code in +structured JSON responses without harming the code quality. +But it seems premature to consider switching from plain text +to JSON-wrapped code. + + +## Notes on the aider leaderboard + +The results presented here are not directly comparable to results +from the main +[aider LLM leaderboard](https://aider.chat/docs/leaderboards/). +A number of settings were changed to simplify the benchmark +in order to focus on comparing plain text and JSON wrapped code. From 5ccdebf2c0a5e094949f0ca1da4be07ae006c6ff Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 09:50:50 -0700 Subject: [PATCH 065/105] refactor: Extract color assignment logic into a separate function --- benchmark/over_time.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/benchmark/over_time.py b/benchmark/over_time.py index 565038a8e..f72bac31e 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -6,6 +6,17 @@ from matplotlib import rc from aider.dump import dump # noqa: 401 +def get_model_color(model): + if "-4o" in model and "gpt-4o-mini" not in model: + return "purple" + elif "gpt-4" in model: + return "red" + elif "gpt-3.5" in model: + return "green" + else: + return "lightblue" + + def plot_over_time(yaml_file): with open(yaml_file, "r") as file: data = yaml.safe_load(file) @@ -49,14 +60,7 @@ def plot_over_time(yaml_file): spine.set_edgecolor("#DDDDDD") spine.set_linewidth(0.5) - colors = [ - ( - "purple" - if "-4o" in model and "gpt-4o-mini" not in model - else "red" if "gpt-4" in model else "green" if "gpt-3.5" in model else "lightblue" - ) - for model in models - ] + colors = [get_model_color(model) for model in models] # Separate data points by color purple_points = [(d, r) for d, r, c in zip(dates, pass_rates, colors) if c == "purple"] From 822a8ab671f49a25a25259802b178bc02534d4a7 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 09:52:21 -0700 Subject: [PATCH 066/105] remove gpt-4o-mini from the gpt-4 trendline --- aider/website/assets/models-over-time.svg | 169 +++++++++++----------- benchmark/over_time.py | 17 ++- 2 files changed, 96 insertions(+), 90 deletions(-) diff --git a/aider/website/assets/models-over-time.svg b/aider/website/assets/models-over-time.svg index a4fe87061..8fd066630 100644 --- a/aider/website/assets/models-over-time.svg +++ b/aider/website/assets/models-over-time.svg @@ -6,7 +6,7 @@ - 2024-08-14T06:29:51.758534 + 2024-08-15T09:51:56.911643 image/svg+xml @@ -39,7 +39,7 @@ z - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + @@ -250,7 +250,7 @@ z - + @@ -297,7 +297,7 @@ z - + @@ -332,7 +332,7 @@ z - + @@ -383,7 +383,7 @@ z - + @@ -415,7 +415,7 @@ z - + @@ -455,7 +455,7 @@ z - + @@ -474,7 +474,7 @@ z - + @@ -493,7 +493,7 @@ z - + @@ -512,7 +512,7 @@ z - + @@ -789,16 +789,16 @@ z +" clip-path="url(#p463a66dc35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.2; stroke-linecap: square"/> - - + @@ -812,11 +812,11 @@ L -3.5 0 +" clip-path="url(#p463a66dc35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.2; stroke-linecap: square"/> - + @@ -831,11 +831,11 @@ L 783.420506 273.255599 +" clip-path="url(#p463a66dc35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.2; stroke-linecap: square"/> - + @@ -850,11 +850,11 @@ L 783.420506 217.541699 +" clip-path="url(#p463a66dc35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.2; stroke-linecap: square"/> - + @@ -901,11 +901,11 @@ z +" clip-path="url(#p463a66dc35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.2; stroke-linecap: square"/> - + @@ -961,11 +961,11 @@ z +" clip-path="url(#p463a66dc35)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.2; stroke-linecap: square"/> - + @@ -1317,7 +1317,7 @@ z +" clip-path="url(#p463a66dc35)" style="fill: none; stroke: #800080; stroke-opacity: 0.5; stroke-linecap: square"/> +" clip-path="url(#p463a66dc35)" style="fill: none; stroke: #ff0000; stroke-opacity: 0.5; stroke-linecap: square"/> +" clip-path="url(#p463a66dc35)" style="fill: none; stroke: #008000; stroke-opacity: 0.5; stroke-linecap: square"/> + diff --git a/benchmark/over_time.py b/benchmark/over_time.py index f72bac31e..931b7e1d2 100644 --- a/benchmark/over_time.py +++ b/benchmark/over_time.py @@ -7,14 +7,21 @@ from aider.dump import dump # noqa: 401 def get_model_color(model): - if "-4o" in model and "gpt-4o-mini" not in model: + default = "lightblue" + + if model == "gpt-4o-mini": + return default + + if "-4o" in model: return "purple" - elif "gpt-4" in model: + + if "gpt-4" in model: return "red" - elif "gpt-3.5" in model: + + if "gpt-3.5" in model: return "green" - else: - return "lightblue" + + return default def plot_over_time(yaml_file): From 19073dd93904ee51b4a10d124d53b2a4432ddcc4 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 10:08:13 -0700 Subject: [PATCH 067/105] feat: Add section on overall coding skill and syntax errors to blog post on code in JSON --- aider/website/_posts/2024-08-14-code-in-json.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 9f3345971..601fab485 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -270,6 +270,9 @@ model & strategy combination. ## Results + +## Overall coding skill + All of the models did worse on the benchmark when asked to return JSON-wrapped code in a tool function call. Most did significantly worse, performing far below @@ -285,6 +288,9 @@ as compared to non-strict JSON. Of course, both JSON results were well below the markdown result. - The results from Sonnet and DeepSeek Coder suffered the worst harm from JSON wrapping. +## Syntax errors + + ## Conclusions While the quantitative results differ from the similar From 8f0cc731fdb5daddb5eb0498f9059ad92d9a2984 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 10:10:01 -0700 Subject: [PATCH 068/105] feat: Increase chart height on small screens --- .../website/_posts/2024-08-14-code-in-json.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 601fab485..b4db42cda 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -12,7 +12,9 @@ nav_exclude: true # LLMs are bad at returning code in JSON - +
+ +
+ ## Conclusions From a2882f4104711de5bc383e7d5fc5c79365572ed2 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 10:23:49 -0700 Subject: [PATCH 071/105] feat: Add createStripedCanvas function to second chart's script --- .../website/_posts/2024-08-14-code-in-json.md | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 5db5b05ea..f0e9a2243 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -128,6 +128,28 @@ document.addEventListener('DOMContentLoaded', function () { new Chart(ctx, config); }); + +function createStripedCanvas(isStrict) { + const patternCanvas = document.createElement('canvas'); + const patternContext = patternCanvas.getContext('2d'); + const size = 10; + patternCanvas.width = size; + patternCanvas.height = size; + + patternContext.fillStyle = 'rgba(255, 99, 132, 0.8)'; + patternContext.fillRect(0, 0, size, size); + + if (isStrict) { + patternContext.strokeStyle = 'rgba(255, 255, 255, 0.8)'; + patternContext.lineWidth = 0.75; + patternContext.beginPath(); + patternContext.moveTo(0, 0); + patternContext.lineTo(size, size); + patternContext.stroke(); + } + + return patternCanvas; +} From 2bb75dc11ffada9b7e0f468132e8c6f2051346b0 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 10:33:22 -0700 Subject: [PATCH 072/105] feat: Add figures and captions to blog post on code in JSON --- aider/website/_posts/2024-08-14-code-in-json.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index f0e9a2243..69553ad52 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -152,6 +152,8 @@ function createStripedCanvas(isStrict) { } +> Figure 1: Benchmark scores of models using either plain markdown text or JSON to return code. +> Models produce better code when they return it as plain markdown text, as compared to wrapping it in JSON for a tool function call. ## Abstract @@ -421,6 +423,9 @@ document.addEventListener('DOMContentLoaded', function () { }); +> Figure 2: Number of `SyntaxError` and `IndentationError` errors found in model generated code. +> Models tend to make more syntactic errors when asked to wrap code in JSON. + ## Conclusions From 8d4d549a9834bdc6833b49a76140edef7d71a75d Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 10:34:49 -0700 Subject: [PATCH 073/105] catch litellm bug for image size --- aider/models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/aider/models.py b/aider/models.py index cad99d1df..4e5bf74ca 100644 --- a/aider/models.py +++ b/aider/models.py @@ -516,7 +516,11 @@ class Model: def token_count(self, messages): if type(messages) is list: - return litellm.token_counter(model=self.name, messages=messages) + try: + return litellm.token_counter(model=self.name, messages=messages) + except Exception as err: + print(f"Unable to count tokens: {err}") + return 0 if not self.tokenizer: return From e90642295dc5f7d52043c1ffdc8bb54fb504c3c2 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 10:50:51 -0700 Subject: [PATCH 074/105] feat: Add code-in-json-benchmark.js file and update code-in-json.md post --- .../website/_includes/code-in-json-benchmark.js | 0 aider/website/_posts/2024-08-14-code-in-json.md | 16 +++++++--------- 2 files changed, 7 insertions(+), 9 deletions(-) create mode 100644 aider/website/_includes/code-in-json-benchmark.js diff --git a/aider/website/_includes/code-in-json-benchmark.js b/aider/website/_includes/code-in-json-benchmark.js new file mode 100644 index 000000000..e69de29bb diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 69553ad52..fe6a63466 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -157,21 +157,19 @@ function createStripedCanvas(isStrict) { ## Abstract -The newest LLMs have support for returning properly formatted JSON responses, -making it easier for clients to parse complex responses. -This makes it tempting for AI coding applications to -use JSON replies to -receive code from LLMs. +Current LLMs have support for returning properly formatted JSON, +making it easier for clients to reliably parse complex responses. +It therefore seems attractive for +AI coding applications ask LLMs to return code in structure JSON replies. Unfortunately, LLMs write worse code when asked to wrap it in JSON, harming their ability to correctly solve coding tasks. On a variant of the aider code editing benchmark, -JSON-wrapping code +asking for JSON-wrapped code often significantly harms coding -performance -compared to returning code as plain text. +performance. This holds true across many top coding LLMs, -including OpenAI's new gpt-4o-2024-08-06 +including OpenAI's latest model gpt-4o-2024-08-06 which has strong JSON support. ## Introduction From f91faf52dc412c95acd485fe84b6027504b92a46 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 10:57:47 -0700 Subject: [PATCH 075/105] feat: Add code-in-json-syntax.js and update code-in-json-benchmark.js --- .../_includes/code-in-json-benchmark.js | 139 ++++++++++++++++++ .../website/_includes/code-in-json-syntax.js | 93 ++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 aider/website/_includes/code-in-json-syntax.js diff --git a/aider/website/_includes/code-in-json-benchmark.js b/aider/website/_includes/code-in-json-benchmark.js index e69de29bb..93b1ff857 100644 --- a/aider/website/_includes/code-in-json-benchmark.js +++ b/aider/website/_includes/code-in-json-benchmark.js @@ -0,0 +1,139 @@ +
+ +
+ + + diff --git a/aider/website/_includes/code-in-json-syntax.js b/aider/website/_includes/code-in-json-syntax.js new file mode 100644 index 000000000..4008484d1 --- /dev/null +++ b/aider/website/_includes/code-in-json-syntax.js @@ -0,0 +1,93 @@ +
+ +
+ + From 353b63109128c883dfcc1ffdc3267780963df382 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 10:57:48 -0700 Subject: [PATCH 076/105] feat: Add bar value labels to charts --- .../_includes/code-in-json-benchmark.js | 33 ++++++++++++++++++- .../website/_includes/code-in-json-syntax.js | 33 ++++++++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/aider/website/_includes/code-in-json-benchmark.js b/aider/website/_includes/code-in-json-benchmark.js index 93b1ff857..0a8f75e74 100644 --- a/aider/website/_includes/code-in-json-benchmark.js +++ b/aider/website/_includes/code-in-json-benchmark.js @@ -71,9 +71,40 @@ document.addEventListener('DOMContentLoaded', function () { }, legend: { position: 'top', + }, + tooltip: { + callbacks: { + label: function(context) { + let label = context.dataset.label || ''; + if (label) { + label += ': '; + } + if (context.parsed.y !== null) { + label += context.parsed.y.toFixed(1) + '%'; + } + return label; + } + } } } - } + }, + plugins: [{ + afterDraw: function(chart) { + var ctx = chart.ctx; + chart.data.datasets.forEach(function(dataset, i) { + var meta = chart.getDatasetMeta(i); + meta.data.forEach(function(bar, index) { + var data = dataset.data[index]; + if (data !== null) { + ctx.fillStyle = '#000000'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'bottom'; + ctx.fillText(data.toFixed(1) + '%', bar.x, bar.y - 5); + } + }); + }); + } + }] }; // Adjust chart height based on screen width diff --git a/aider/website/_includes/code-in-json-syntax.js b/aider/website/_includes/code-in-json-syntax.js index 4008484d1..77d347cda 100644 --- a/aider/website/_includes/code-in-json-syntax.js +++ b/aider/website/_includes/code-in-json-syntax.js @@ -69,9 +69,40 @@ document.addEventListener('DOMContentLoaded', function () { }, legend: { position: 'top', + }, + tooltip: { + callbacks: { + label: function(context) { + let label = context.dataset.label || ''; + if (label) { + label += ': '; + } + if (context.parsed.y !== null) { + label += context.parsed.y; + } + return label; + } + } } } - } + }, + plugins: [{ + afterDraw: function(chart) { + var ctx = chart.ctx; + chart.data.datasets.forEach(function(dataset, i) { + var meta = chart.getDatasetMeta(i); + meta.data.forEach(function(bar, index) { + var data = dataset.data[index]; + if (data !== null) { + ctx.fillStyle = '#000000'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'bottom'; + ctx.fillText(data, bar.x, bar.y - 5); + } + }); + }); + } + }] }; // Adjust chart height based on screen width From 679e1b8990a4059c51e5fc0827bc9f3f7e81da7c Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 11:13:20 -0700 Subject: [PATCH 077/105] copy --- aider/website/_data/code-in-json.yml | 210 +++++++------- .../website/_includes/code-in-json-syntax.js | 3 +- .../website/_posts/2024-08-14-code-in-json.md | 274 ++---------------- 3 files changed, 136 insertions(+), 351 deletions(-) diff --git a/aider/website/_data/code-in-json.yml b/aider/website/_data/code-in-json.yml index 78efd129f..d983aefa8 100644 --- a/aider/website/_data/code-in-json.yml +++ b/aider/website/_data/code-in-json.yml @@ -40,27 +40,6 @@ versions: 0.50.2-dev seconds_per_case: 5.7 total_cost: 0.8417 -- dirname: 2024-08-15-13-20-11--json-no-lint-gpt-4o-2024-05-13-whole - test_cases: 133 - model: gpt-4o-2024-05-13 - edit_format: Markdown - commit_hash: bac04a2 - pass_rate_1: 56.4 - percent_cases_well_formed: 100.0 - error_outputs: 0 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 0 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 1 - command: aider --model gpt-4o-2024-05-13 - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 8.0 - total_cost: 1.5034 - dirname: 2024-08-15-13-21-55--json-no-lint-gpt-4o-2024-05-13-func test_cases: 133 model: gpt-4o-2024-05-13 @@ -208,27 +187,6 @@ versions: 0.50.2-dev seconds_per_case: 6.4 total_cost: 0.8390 -- dirname: 2024-08-15-13-53-23--json-no-lint-gpt-4o-2024-05-13-whole-2 - test_cases: 133 - model: gpt-4o-2024-05-13 - edit_format: Markdown - commit_hash: bac04a2 - pass_rate_1: 59.4 - percent_cases_well_formed: 100.0 - error_outputs: 0 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 0 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 0 - command: aider --model gpt-4o-2024-05-13 - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 7.4 - total_cost: 1.4996 - dirname: 2024-08-15-13-54-53--json-no-lint-gpt-4o-2024-05-13-func-2 test_cases: 133 model: gpt-4o-2024-05-13 @@ -376,27 +334,6 @@ versions: 0.50.2-dev seconds_per_case: 5.6 total_cost: 0.8220 -- dirname: 2024-08-15-14-14-40--json-no-lint-gpt-4o-2024-05-13-whole-3 - test_cases: 133 - model: gpt-4o-2024-05-13 - edit_format: Markdown - commit_hash: bac04a2 - pass_rate_1: 61.7 - percent_cases_well_formed: 100.0 - error_outputs: 0 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 6 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 1 - command: aider --model gpt-4o-2024-05-13 - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 8.8 - total_cost: 1.4993 - dirname: 2024-08-15-14-16-34--json-no-lint-gpt-4o-2024-05-13-func-3 test_cases: 133 model: gpt-4o-2024-05-13 @@ -544,27 +481,6 @@ versions: 0.50.2-dev seconds_per_case: 6.0 total_cost: 0.8394 -- dirname: 2024-08-15-14-30-48--json-no-lint-gpt-4o-2024-05-13-whole-4 - test_cases: 133 - model: gpt-4o-2024-05-13 - edit_format: Markdown - commit_hash: bac04a2 - pass_rate_1: 61.7 - percent_cases_well_formed: 100.0 - error_outputs: 0 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 6 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 0 - command: aider --model gpt-4o-2024-05-13 - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 12.3 - total_cost: 1.4919 - dirname: 2024-08-15-14-32-58--json-no-lint-gpt-4o-2024-05-13-func-4 test_cases: 133 model: gpt-4o-2024-05-13 @@ -712,27 +628,6 @@ versions: 0.50.2-dev seconds_per_case: 6.3 total_cost: 0.8354 -- dirname: 2024-08-15-14-47-39--json-no-lint-gpt-4o-2024-05-13-whole-5 - test_cases: 133 - model: gpt-4o-2024-05-13 - edit_format: Markdown - commit_hash: bac04a2 - pass_rate_1: 60.2 - percent_cases_well_formed: 100.0 - error_outputs: 0 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 9 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 1 - command: aider --model gpt-4o-2024-05-13 - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 10.7 - total_cost: 1.4982 - dirname: 2024-08-15-14-49-44--json-no-lint-gpt-4o-2024-05-13-func-5 test_cases: 133 model: gpt-4o-2024-05-13 @@ -922,3 +817,108 @@ versions: 0.50.2-dev seconds_per_case: 6.1 total_cost: 0.8415 +- dirname: 2024-08-15-17-36-22--json-no-lint-again-gpt-4o-2024-05-13-whole-1 + test_cases: 133 + model: gpt-4o-2024-05-13 + edit_format: Markdown + commit_hash: ed94379 + pass_rate_1: 60.2 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 7 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 6.8 + total_cost: 1.5110 +- dirname: 2024-08-15-17-38-13--json-no-lint-again-gpt-4o-2024-05-13-whole-2 + test_cases: 133 + model: gpt-4o-2024-05-13 + edit_format: Markdown + commit_hash: ed94379 + pass_rate_1: 60.9 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 7.0 + total_cost: 1.4954 +- dirname: 2024-08-15-17-40-10--json-no-lint-again-gpt-4o-2024-05-13-whole-3 + test_cases: 133 + model: gpt-4o-2024-05-13 + edit_format: Markdown + commit_hash: ed94379 + pass_rate_1: 60.9 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 0 + command: aider --model gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 6.8 + total_cost: 1.4999 +- dirname: 2024-08-15-17-41-30--json-no-lint-again-gpt-4o-2024-05-13-whole-4 + test_cases: 133 + model: gpt-4o-2024-05-13 + edit_format: Markdown + commit_hash: ed94379 + pass_rate_1: 58.6 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 7.4 + total_cost: 1.4848 +- dirname: 2024-08-15-17-43-12--json-no-lint-again-gpt-4o-2024-05-13-whole-5 + test_cases: 133 + model: gpt-4o-2024-05-13 + edit_format: Markdown + commit_hash: ed94379 + pass_rate_1: 59.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model gpt-4o-2024-05-13 + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 7.6 + total_cost: 1.4948 diff --git a/aider/website/_includes/code-in-json-syntax.js b/aider/website/_includes/code-in-json-syntax.js index 77d347cda..b315edea9 100644 --- a/aider/website/_includes/code-in-json-syntax.js +++ b/aider/website/_includes/code-in-json-syntax.js @@ -56,7 +56,8 @@ document.addEventListener('DOMContentLoaded', function () { title: { display: true, text: 'Total syntactic errors from 5 runs' - } + }, + max: 35 } }, plugins: { diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index fe6a63466..6546e1dfa 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -12,155 +12,12 @@ nav_exclude: true # LLMs are bad at returning code in JSON -
- -
- - - - -> Figure 1: Benchmark scores of models using either plain markdown text or JSON to return code. -> Models produce better code when they return it as plain markdown text, as compared to wrapping it in JSON for a tool function call. - ## Abstract Current LLMs have support for returning properly formatted JSON, making it easier for clients to reliably parse complex responses. It therefore seems attractive for -AI coding applications ask LLMs to return code in structure JSON replies. +AI coding applications ask LLMs to return code in structured JSON replies. Unfortunately, LLMs write worse code when asked to wrap it in JSON, harming their ability to correctly solve coding tasks. @@ -172,6 +29,13 @@ This holds true across many top coding LLMs, including OpenAI's latest model gpt-4o-2024-08-06 which has strong JSON support. +{% include code-in-json-benchmark.js %} + +> Figure 1: Benchmark scores of models using either plain markdown text or JSON to return code, +> averaged over 5 runs. +> Models produce better code when they return it as plain markdown text, as compared to wrapping it in JSON for a tool function call. + + ## Introduction A lot of people wonder why aider doesn't use LLM tools for code editing. @@ -244,9 +108,8 @@ capable models. OpenAI's newly announced support for "strict" JSON seemed like a good reason to investigate whether the newest models are still handicapped by JSON-wrapping code. -The graph above shows benchmark -results from -4 of the strongest code editing models: +Four of the strongest code editing models were benchmarked +to assess the impact of JSON-wrapping code: - claude-3-5-sonnet-20240620 - deepseek-coder (V2 0724) @@ -302,15 +165,16 @@ portions of a file. This experimental setup is designed to highlight the effects of JSON-wrapping on the LLMs ability to write code to solve a task. -The results in the graph are the average of 5 runs for each -model & strategy combination. ## Results +Each of the 4 models was benchmarked 5 times using the different +strategies for returning code. ## Overall coding skill -All of the models did worse on the benchmark when asked to +As shown in Figure 1, +all of the models did worse on the benchmark when asked to return JSON-wrapped code in a tool function call. Most did significantly worse, performing far below the result obtained with the markdown strategy. @@ -319,109 +183,29 @@ Some noteworthy observations: - OpenAI's gpt-4o-2024-05-13 was the only model where the markdown and JSON results were close. Using JSON only dropped the score by 0.3 percent, a difference which is -probably within the margin of error for 5 trials. -- The use of OpenAI's new strict mode seemed to harm the results for gpt-4o-2024-08-06 -as compared to non-strict JSON. +within the margin of error for 5 trials. +- The use of OpenAI's new strict mode offered no improvement +as compared to non-strict JSON. Of course, both JSON results were well below the markdown result. - The results from Sonnet and DeepSeek Coder suffered the worst harm from JSON wrapping. ## Syntax errors -
- -
+Figure 2 shows the number of syntactic errors found in the code produced by each +model and code wrapping strategy. +Models tend to make more syntactic errors when asked to wrap code in JSON. - - -> Figure 2: Number of `SyntaxError` and `IndentationError` errors found in model generated code. +> Figure 2: Number of `SyntaxError` and `IndentationError` errors found in model generated code, +> totaled from 5 runs. > Models tend to make more syntactic errors when asked to wrap code in JSON. From 479f73871b7529b1f354bc756a8a76ee8023f2aa Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 12:14:39 -0700 Subject: [PATCH 078/105] more debug on unexepcted error --- aider/coders/base_coder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index c7f9816e8..8c3484c69 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -1009,7 +1009,8 @@ class Coder: ) except Exception as err: self.io.tool_error(f"Unexpected error: {err}") - traceback.print_exc() + lines = traceback.format_exception(type(err), err, err.__traceback__) + self.io.tool_error("".join(lines)) return finally: if self.mdstream: From 3e5dba8d5ca6ebe2f14783136a3d890ee6b0ae5d Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 12:14:49 -0700 Subject: [PATCH 079/105] copy --- .../website/_includes/code-in-json-syntax.js | 4 +- .../website/_posts/2024-08-14-code-in-json.md | 87 ++++++++++--------- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/aider/website/_includes/code-in-json-syntax.js b/aider/website/_includes/code-in-json-syntax.js index b315edea9..5c0e652b1 100644 --- a/aider/website/_includes/code-in-json-syntax.js +++ b/aider/website/_includes/code-in-json-syntax.js @@ -55,7 +55,7 @@ document.addEventListener('DOMContentLoaded', function () { beginAtZero: true, title: { display: true, - text: 'Total syntactic errors from 5 runs' + text: 'Total syntax errors from 5 runs' }, max: 35 } @@ -63,7 +63,7 @@ document.addEventListener('DOMContentLoaded', function () { plugins: { title: { display: true, - text: 'Syntactic errors by model and code wrapping strategy', + text: 'Syntax errors by model and code wrapping strategy', font: { size: 16 } diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 6546e1dfa..59cc444f4 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -12,8 +12,6 @@ nav_exclude: true # LLMs are bad at returning code in JSON -## Abstract - Current LLMs have support for returning properly formatted JSON, making it easier for clients to reliably parse complex responses. It therefore seems attractive for @@ -23,8 +21,7 @@ LLMs write worse code when asked to wrap it in JSON, harming their ability to correctly solve coding tasks. On a variant of the aider code editing benchmark, asking for JSON-wrapped code -often significantly harms coding -performance. +often harms coding performance. This holds true across many top coding LLMs, including OpenAI's latest model gpt-4o-2024-08-06 which has strong JSON support. @@ -36,7 +33,7 @@ which has strong JSON support. > Models produce better code when they return it as plain markdown text, as compared to wrapping it in JSON for a tool function call. -## Introduction +## Background A lot of people wonder why aider doesn't use LLM tools for code editing. Instead, aider asks for code edits in plain text, like this: @@ -66,14 +63,17 @@ which would return a structured JSON response: ``` This has become even more tempting as LLM providers -continue to improve their tooling for reliably generating -valid JSON. -For example, OpenAI recently announced the ability to -[strictly enforce that JSON responses will be syntactically correct -and conform to a specified schema](https://openai.com/index/introducing-structured-outputs-in-the-api/). +continue to improve their tooling for reliably generating JSON. +For example, +[OpenAI recently announced](https://openai.com/index/introducing-structured-outputs-in-the-api/) +the ability to +strictly enforce that JSON responses will be syntactically correct +and conform to a specified schema. + But producing valid (schema compliant) JSON is not sufficient for working with AI generated code. -The code inside the JSON has to be valid and high quality too. +The code inside the JSON has to correctly solve the requested task +and be free from syntax errors. Unfortunately, LLMs write worse code when they're asked to wrap it in JSON. @@ -108,29 +108,23 @@ capable models. OpenAI's newly announced support for "strict" JSON seemed like a good reason to investigate whether the newest models are still handicapped by JSON-wrapping code. -Four of the strongest code editing models were benchmarked -to assess the impact of JSON-wrapping code: +The results presented here were based on +the +[aider "code editing" benchmark](/2023/07/02/benchmarks.html#the-benchmark) +of 133 practice exercises from the Exercism python repository. +Models were +restricted to a single attempt, +without a second try to fix errors as is normal in the aider benchmark. -- claude-3-5-sonnet-20240620 -- deepseek-coder (V2 0724) -- gpt-4o-2024-05-13 -- gpt-4o-2024-08-06 - -Each model was given one try to solve -[133 practice exercises from the Exercism python repository](/2023/07/02/benchmarks.html#the-benchmark). -This is the standard aider "code editing" benchmark, but restricted to a single attempt -without a second try to "fix" any errors. - -The benchmark assessed the models coding ability -using different strategies for returning code: +The performance of each model was compared across different strategies for returning code: - **Markdown** -- the model returned the whole source code file in standard markdown triple-backtick fences. -- **JSON** -- the model used a tool function call to return the whole source code file. This requires the LLM to wrap the code in JSON. +- **JSON** -- the model used a tool function call to return the whole source code file. This required the LLM to wrap the code in JSON. - **JSON (strict)** -- the same as the "JSON" strategy, but with `strict=True`. Only gpt-4o-2024-08-06 supports this setting. The markdown strategy is the same as aider's "whole" edit format, where the -LLM would return a source file like this: +LLM returns a source file like this: ```` Here is the program you asked for which prints "Hello": @@ -163,13 +157,20 @@ than correctly formulating instructions to edit portions of a file. -This experimental setup is designed to highlight +This experimental setup is designed to quantify the effects of JSON-wrapping on the LLMs ability to write code to solve a task. ## Results -Each of the 4 models was benchmarked 5 times using the different -strategies for returning code. +Four of the strongest code editing models were benchmarked +to assess the impact of JSON-wrapping code: + +- claude-3-5-sonnet-20240620 +- deepseek-coder (V2 0724) +- gpt-4o-2024-05-13 +- gpt-4o-2024-08-06 + +Each combination of model and code wrapping strategy was benchmarked 5 times. ## Overall coding skill @@ -191,22 +192,24 @@ Of course, both JSON results were well below the markdown result. ## Syntax errors -Figure 2 shows the number of syntactic errors found in the code produced by each -model and code wrapping strategy. -Models tend to make more syntactic errors when asked to wrap code in JSON. +Models tend to make more syntax errors when asked to wrap code in JSON. +Figure 2 shows the number of syntax errors found in the code produced by each +model and code wrapping strategy, +totaling up `SyntaxError` and `IndentationError` errors from all 5 runs. -Sonnet avoided syntactic errors regardless of the code wrapping strategy, -but its benchmark scores in Figure 1 were lower with JSON. -This seems to indicate that JSON-wrapping -does more than simply raise the syntactic difficulty in coding. -It may distract or challenge the model in a way that -reduces its ability to reason about coding problems. + +Sonnet's results seems to indicate that the negative effects of JSON-wrapping +go beyond syntactic difficulties. +Sonnet avoided syntax errors regardless of the code wrapping strategy, +but its benchmark scores in Figure 1 were nonetheless lower with JSON. +This implies that JSON-wrapping may distract or challenge models in a way that +reduces their ability to reason about solving coding problems. {% include code-in-json-syntax.js %} > Figure 2: Number of `SyntaxError` and `IndentationError` errors found in model generated code, > totaled from 5 runs. -> Models tend to make more syntactic errors when asked to wrap code in JSON. +> Models tend to make more syntax and formatting errors when asked to wrap code in JSON. ## Conclusions @@ -217,7 +220,7 @@ the conclusion seems unchanged: LLMs are bad at returning code in JSON. OpenAI appears to be making progress in allowing LLMs to return code in structured JSON responses without harming the code quality. -But it seems premature to consider switching from plain text +But it still seems premature to consider switching from plain text to JSON-wrapped code. @@ -227,4 +230,4 @@ The results presented here are not directly comparable to results from the main [aider LLM leaderboard](https://aider.chat/docs/leaderboards/). A number of settings were changed to simplify the benchmark -in order to focus on comparing plain text and JSON wrapped code. +in order to focus on comparing plain text and JSON-wrapped code. From 8a1f696bce32dfe5a76eb9513b6c5bc8174145fa Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 13:07:25 -0700 Subject: [PATCH 080/105] add clean deepseek func data, with args None issue resolved --- aider/website/_data/code-in-json.yml | 212 ++++++++++++++------------- 1 file changed, 107 insertions(+), 105 deletions(-) diff --git a/aider/website/_data/code-in-json.yml b/aider/website/_data/code-in-json.yml index d983aefa8..bc4b9b469 100644 --- a/aider/website/_data/code-in-json.yml +++ b/aider/website/_data/code-in-json.yml @@ -124,27 +124,6 @@ versions: 0.50.2-dev seconds_per_case: 27.9 total_cost: 0.0438 -- dirname: 2024-08-15-13-29-55--json-no-lint-deepseek-coder-func - test_cases: 133 - model: deepseek-coder V2 0724 - edit_format: JSON - commit_hash: bac04a2 - pass_rate_1: 49.6 - percent_cases_well_formed: 100.0 - error_outputs: 3 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 4 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 1 - command: aider --model deepseek-coder - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 20.5 - total_cost: 0.0329 - dirname: 2024-08-15-13-50-03--json-no-lint-gpt-4o-2024-08-06-whole-2 test_cases: 133 model: gpt-4o-2024-08-06 @@ -271,27 +250,6 @@ versions: 0.50.2-dev seconds_per_case: 25.8 total_cost: 0.0439 -- dirname: 2024-08-15-14-09-22--json-no-lint-deepseek-coder-func-2 - test_cases: 133 - model: deepseek-coder V2 0724 - edit_format: JSON - commit_hash: bac04a2 - pass_rate_1: 53.4 - percent_cases_well_formed: 100.0 - error_outputs: 5 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 6 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 1 - command: aider --model deepseek-coder - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 18.8 - total_cost: 0.0333 - dirname: 2024-08-15-14-11-45--json-no-lint-gpt-4o-2024-08-06-whole-3 test_cases: 133 model: gpt-4o-2024-08-06 @@ -418,27 +376,6 @@ versions: 0.50.2-dev seconds_per_case: 24.4 total_cost: 0.0439 -- dirname: 2024-08-15-14-24-46--json-no-lint-deepseek-coder-func-3 - test_cases: 133 - model: deepseek-coder V2 0724 - edit_format: JSON - commit_hash: bac04a2 - pass_rate_1: 52.6 - percent_cases_well_formed: 100.0 - error_outputs: 3 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 12 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 1 - command: aider --model deepseek-coder - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 19.0 - total_cost: 0.0334 - dirname: 2024-08-15-14-27-17--json-no-lint-gpt-4o-2024-08-06-whole-4 test_cases: 133 model: gpt-4o-2024-08-06 @@ -565,27 +502,6 @@ versions: 0.50.2-dev seconds_per_case: 24.5 total_cost: 0.0438 -- dirname: 2024-08-15-14-41-36--json-no-lint-deepseek-coder-func-4 - test_cases: 133 - model: deepseek-coder V2 0724 - edit_format: JSON - commit_hash: bac04a2 - pass_rate_1: 49.6 - percent_cases_well_formed: 100.0 - error_outputs: 7 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 2 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 1 - command: aider --model deepseek-coder - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 18.7 - total_cost: 0.0333 - dirname: 2024-08-15-14-44-11--json-no-lint-gpt-4o-2024-08-06-whole-5 test_cases: 133 model: gpt-4o-2024-08-06 @@ -712,27 +628,6 @@ versions: 0.50.2-dev seconds_per_case: 24.5 total_cost: 0.0439 -- dirname: 2024-08-15-14-57-51--json-no-lint-deepseek-coder-func-5 - test_cases: 133 - model: deepseek-coder V2 0724 - edit_format: JSON - commit_hash: bac04a2 - pass_rate_1: 53.4 - percent_cases_well_formed: 100.0 - error_outputs: 5 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 4 - indentation_errors: 1 - exhausted_context_windows: 0 - test_timeouts: 0 - command: aider --model deepseek-coder - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 18.5 - total_cost: 0.0330 - dirname: 2024-08-15-15-12-55--json-no-lint-strict-gpt-4o-2024-08-06-func-2 test_cases: 133 model: gpt-4o-2024-08-06 @@ -922,3 +817,110 @@ versions: 0.50.2-dev seconds_per_case: 7.6 total_cost: 1.4948 + +- dirname: 2024-08-15-19-35-32--json-no-lint-again-deepseek-coder-func-1 + test_cases: 133 + model: deepseek-coder V2 0724 + edit_format: JSON + commit_hash: 3a2ac02-dirty + pass_rate_1: 50.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 2 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 17.8 + total_cost: 0.0330 +- dirname: 2024-08-15-19-37-50--json-no-lint-again-deepseek-coder-func-2 + test_cases: 133 + model: deepseek-coder V2 0724 + edit_format: JSON + commit_hash: 1a98c28 + pass_rate_1: 49.6 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 5 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 18.3 + total_cost: 0.0336 +- dirname: 2024-08-15-19-40-20--json-no-lint-again-deepseek-coder-func-3 + test_cases: 133 + model: deepseek-coder V2 0724 + edit_format: JSON + commit_hash: 1a98c28 + pass_rate_1: 48.9 + percent_cases_well_formed: 100.0 + error_outputs: 1 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 5 + indentation_errors: 1 + exhausted_context_windows: 1 + test_timeouts: 2 + command: aider --model deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 18.4 + total_cost: 0.0337 +- dirname: 2024-08-15-19-44-07--json-no-lint-again-deepseek-coder-func-4 + test_cases: 133 + model: deepseek-coder V2 0724 + edit_format: JSON + commit_hash: 1a98c28 + pass_rate_1: 53.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 2 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 17.6 + total_cost: 0.0330 +- dirname: 2024-08-15-19-46-48--json-no-lint-again-deepseek-coder-func-5 + test_cases: 133 + model: deepseek-coder V2 0724 + edit_format: JSON + commit_hash: 1a98c28-dirty + pass_rate_1: 53.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 11 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 2 + command: aider --model deepseek-coder + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 18.0 + total_cost: 0.0332 + \ No newline at end of file From db5dbb5d13ba276bf9cd0d5f079c91c477f2226e Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 13:27:26 -0700 Subject: [PATCH 081/105] update with clean sonnet func data with args None fix --- aider/website/_data/code-in-json.yml | 211 ++++++++++++++------------- 1 file changed, 106 insertions(+), 105 deletions(-) diff --git a/aider/website/_data/code-in-json.yml b/aider/website/_data/code-in-json.yml index bc4b9b469..a0e6e571e 100644 --- a/aider/website/_data/code-in-json.yml +++ b/aider/website/_data/code-in-json.yml @@ -82,27 +82,6 @@ versions: 0.50.2-dev seconds_per_case: 10.5 total_cost: 1.6714 -- dirname: 2024-08-15-13-24-56--json-no-lint-claude-3.5-sonnet-func - test_cases: 133 - model: claude-3.5-sonnet - edit_format: JSON - commit_hash: bac04a2 - pass_rate_1: 53.4 - percent_cases_well_formed: 100.0 - error_outputs: 0 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 0 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 1 - command: aider --model claude-3.5-sonnet - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 9.7 - total_cost: 1.5980 - dirname: 2024-08-15-13-26-38--json-no-lint-deepseek-coder-whole test_cases: 133 model: deepseek-coder V2 0724 @@ -208,27 +187,6 @@ versions: 0.50.2-dev seconds_per_case: 16.5 total_cost: 1.6556 -- dirname: 2024-08-15-14-02-15--json-no-lint-claude-3.5-sonnet-func-2 - test_cases: 133 - model: claude-3.5-sonnet - edit_format: JSON - commit_hash: bac04a2 - pass_rate_1: 51.9 - percent_cases_well_formed: 100.0 - error_outputs: 1 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 0 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 1 - command: aider --model claude-3.5-sonnet - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 14.3 - total_cost: 1.5835 - dirname: 2024-08-15-14-06-12--json-no-lint-deepseek-coder-whole-2 test_cases: 133 model: deepseek-coder V2 0724 @@ -334,27 +292,6 @@ versions: 0.50.2-dev seconds_per_case: 11.0 total_cost: 1.6555 -- dirname: 2024-08-15-14-19-19--json-no-lint-claude-3.5-sonnet-func-3 - test_cases: 133 - model: claude-3.5-sonnet - edit_format: JSON - commit_hash: bac04a2 - pass_rate_1: 51.1 - percent_cases_well_formed: 100.0 - error_outputs: 3 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 0 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 1 - command: aider --model claude-3.5-sonnet - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 10.3 - total_cost: 1.5614 - dirname: 2024-08-15-14-21-06--json-no-lint-deepseek-coder-whole-3 test_cases: 133 model: deepseek-coder V2 0724 @@ -460,27 +397,6 @@ versions: 0.50.2-dev seconds_per_case: 11.3 total_cost: 1.6635 -- dirname: 2024-08-15-14-36-18--json-no-lint-claude-3.5-sonnet-func-4 - test_cases: 133 - model: claude-3.5-sonnet - edit_format: JSON - commit_hash: bac04a2 - pass_rate_1: 55.6 - percent_cases_well_formed: 100.0 - error_outputs: 1 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 0 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 1 - command: aider --model claude-3.5-sonnet - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 10.5 - total_cost: 1.5768 - dirname: 2024-08-15-14-38-35--json-no-lint-deepseek-coder-whole-4 test_cases: 133 model: deepseek-coder V2 0724 @@ -586,27 +502,6 @@ versions: 0.50.2-dev seconds_per_case: 11.4 total_cost: 1.6685 -- dirname: 2024-08-15-14-52-48--json-no-lint-claude-3.5-sonnet-func-5 - test_cases: 133 - model: claude-3.5-sonnet - edit_format: JSON - commit_hash: bac04a2 - pass_rate_1: 53.4 - percent_cases_well_formed: 100.0 - error_outputs: 2 - num_malformed_responses: 0 - num_with_malformed_responses: 0 - user_asks: 0 - lazy_comments: 0 - syntax_errors: 0 - indentation_errors: 0 - exhausted_context_windows: 0 - test_timeouts: 1 - command: aider --model claude-3.5-sonnet - date: 2024-08-15 - versions: 0.50.2-dev - seconds_per_case: 10.8 - total_cost: 1.5786 - dirname: 2024-08-15-14-54-41--json-no-lint-deepseek-coder-whole-5 test_cases: 133 model: deepseek-coder V2 0724 @@ -923,4 +818,110 @@ versions: 0.50.2-dev seconds_per_case: 18.0 total_cost: 0.0332 + +- dirname: 2024-08-15-20-07-59--json-no-lint-again-claude-3.5-sonnet-func-1 + test_cases: 133 + model: claude-3.5-sonnet + edit_format: JSON + commit_hash: 1a98c28 + pass_rate_1: 54.1 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model claude-3.5-sonnet + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 9.5 + total_cost: 1.5789 +- dirname: 2024-08-15-20-09-39--json-no-lint-again-claude-3.5-sonnet-func-2 + test_cases: 133 + model: claude-3.5-sonnet + edit_format: JSON + commit_hash: 1a98c28 + pass_rate_1: 55.6 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model claude-3.5-sonnet + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 9.2 + total_cost: 1.5916 +- dirname: 2024-08-15-20-11-39--json-no-lint-again-claude-3.5-sonnet-func-3 + test_cases: 133 + model: claude-3.5-sonnet + edit_format: JSON + commit_hash: 1a98c28 + pass_rate_1: 53.4 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model claude-3.5-sonnet + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 10.3 + total_cost: 1.5896 +- dirname: 2024-08-15-20-13-44--json-no-lint-again-claude-3.5-sonnet-func-4 + test_cases: 133 + model: claude-3.5-sonnet + edit_format: JSON + commit_hash: 1a98c28 + pass_rate_1: 55.6 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model claude-3.5-sonnet + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 9.2 + total_cost: 1.6000 +- dirname: 2024-08-15-20-15-51--json-no-lint-again-claude-3.5-sonnet-func-5 + test_cases: 133 + model: claude-3.5-sonnet + edit_format: JSON + commit_hash: 1a98c28 + pass_rate_1: 51.9 + percent_cases_well_formed: 100.0 + error_outputs: 0 + num_malformed_responses: 0 + num_with_malformed_responses: 0 + user_asks: 0 + lazy_comments: 0 + syntax_errors: 0 + indentation_errors: 0 + exhausted_context_windows: 0 + test_timeouts: 1 + command: aider --model claude-3.5-sonnet + date: 2024-08-15 + versions: 0.50.2-dev + seconds_per_case: 8.9 + total_cost: 1.5936 \ No newline at end of file From c3fcaeac5e159f09eac9c0ade2616ca225c540f6 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 13:27:35 -0700 Subject: [PATCH 082/105] adjust canvas height --- aider/website/_includes/code-in-json-benchmark.js | 12 +++--------- aider/website/_includes/code-in-json-syntax.js | 14 ++++---------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/aider/website/_includes/code-in-json-benchmark.js b/aider/website/_includes/code-in-json-benchmark.js index 0a8f75e74..8ac4b7dd3 100644 --- a/aider/website/_includes/code-in-json-benchmark.js +++ b/aider/website/_includes/code-in-json-benchmark.js @@ -1,6 +1,4 @@ -
- -
+ diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 59cc444f4..fea3507f0 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -12,12 +12,11 @@ nav_exclude: true # LLMs are bad at returning code in JSON -Current LLMs have support for returning properly formatted JSON, -making it easier for clients to reliably parse complex responses. -It therefore seems attractive for -AI coding applications ask LLMs to return code in structured JSON replies. -Unfortunately, -LLMs write worse code when asked to wrap it in JSON, harming their ability +AI coding applications should avoid asking LLMs to return code as part of a structured +JSON response. +Even though many current LLMs have special support for returning JSON, +it causes LLMs to write worse code and +harms their ability to correctly solve coding tasks. On a variant of the aider code editing benchmark, asking for JSON-wrapped code From b7a8ddeceb240b33de4257833924b4622a5cd29c Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 13:43:46 -0700 Subject: [PATCH 084/105] copy --- .../website/_posts/2024-08-14-code-in-json.md | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index fea3507f0..4784610b1 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -13,12 +13,9 @@ nav_exclude: true AI coding applications should avoid asking LLMs to return code as part of a structured -JSON response. -Even though many current LLMs have special support for returning JSON, -it causes LLMs to write worse code and -harms their ability -to correctly solve coding tasks. -On a variant of the aider code editing benchmark, +JSON response, +even though many LLMs have special support for returning JSON. +A variant of the aider code editing benchmark clearly demonstrates that asking for JSON-wrapped code often harms coding performance. This holds true across many top coding LLMs, @@ -34,7 +31,7 @@ which has strong JSON support. ## Background -A lot of people wonder why aider doesn't use LLM tools for code editing. +A lot of people wonder why aider does not use LLM tools for code editing. Instead, aider asks for code edits in plain text, like this: ```` @@ -70,7 +67,7 @@ strictly enforce that JSON responses will be syntactically correct and conform to a specified schema. -But producing valid (schema compliant) JSON is not sufficient for working with AI generated code. +But producing valid JSON is not sufficient for working with AI generated code. The code inside the JSON has to correctly solve the requested task and be free from syntax errors. Unfortunately, @@ -102,17 +99,16 @@ showed the superiority of returning code as plain text compared to JSON-wrapped function calls. Those results were obtained -over a year ago, against far less -capable models. +over a year ago, against models far less capable than those available today. OpenAI's newly announced support for "strict" JSON seemed like a good reason to -investigate whether the newest models are still handicapped by JSON-wrapping code. +investigate whether the newest models are still handicapped when JSON-wrapping code. The results presented here were based on the [aider "code editing" benchmark](/2023/07/02/benchmarks.html#the-benchmark) of 133 practice exercises from the Exercism python repository. Models were -restricted to a single attempt, +restricted to a single attempt to solve each task, without a second try to fix errors as is normal in the aider benchmark. The performance of each model was compared across different strategies for returning code: @@ -156,7 +152,7 @@ than correctly formulating instructions to edit portions of a file. -This experimental setup is designed to quantify +This experimental setup was designed to quantify the effects of JSON-wrapping on the LLMs ability to write code to solve a task. ## Results @@ -176,7 +172,7 @@ Each combination of model and code wrapping strategy was benchmarked 5 times. As shown in Figure 1, all of the models did worse on the benchmark when asked to return JSON-wrapped code in a tool function call. -Most did significantly worse, performing far below +Most did significantly worse, performing well below the result obtained with the markdown strategy. Some noteworthy observations: From de7c1484f2b394eebbb9d5c824180ea583434eeb Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 13:54:45 -0700 Subject: [PATCH 085/105] feat: Implement fluid aspect ratio for chart on narrow devices --- .../_includes/code-in-json-benchmark.js | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/aider/website/_includes/code-in-json-benchmark.js b/aider/website/_includes/code-in-json-benchmark.js index 96085fbe1..d312950d4 100644 --- a/aider/website/_includes/code-in-json-benchmark.js +++ b/aider/website/_includes/code-in-json-benchmark.js @@ -1,9 +1,21 @@ - + + +
+ +
From 9f5d5ffe89d0393a503f4468834d34d6642f6657 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 13:59:55 -0700 Subject: [PATCH 087/105] feat: Adjust aspect ratio calculation for code-in-json-benchmark.js --- aider/website/_includes/code-in-json-benchmark.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/website/_includes/code-in-json-benchmark.js b/aider/website/_includes/code-in-json-benchmark.js index d312950d4..6c01e17af 100644 --- a/aider/website/_includes/code-in-json-benchmark.js +++ b/aider/website/_includes/code-in-json-benchmark.js @@ -52,7 +52,7 @@ document.addEventListener('DOMContentLoaded', function () { function getAspectRatio() { var width = chartContainer.offsetWidth; // Gradually change aspect ratio from 2 (landscape) to 1 (square) - return Math.max(1, Math.min(2, width / 400)); + return Math.max(1, Math.min(2, width / 300)); } var config = { From 200427e3f1edd0516f25e799ecde2c7719b86aca Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 13:59:56 -0700 Subject: [PATCH 088/105] feat: Show percentage numbers on top of bars without decimals --- aider/website/_includes/code-in-json-benchmark.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/website/_includes/code-in-json-benchmark.js b/aider/website/_includes/code-in-json-benchmark.js index 6c01e17af..befcdc285 100644 --- a/aider/website/_includes/code-in-json-benchmark.js +++ b/aider/website/_includes/code-in-json-benchmark.js @@ -116,7 +116,7 @@ document.addEventListener('DOMContentLoaded', function () { ctx.fillStyle = '#000000'; ctx.textAlign = 'center'; ctx.textBaseline = 'bottom'; - ctx.fillText(data.toFixed(1) + '%', bar.x, bar.y - 5); + ctx.fillText(Math.round(data) + '%', bar.x, bar.y - 5); } }); }); From 36a8ed6eedf44fb6edb4b42a881c3bff98957b76 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 14:02:59 -0700 Subject: [PATCH 089/105] copy --- aider/website/_posts/2024-08-14-code-in-json.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 4784610b1..b82900eb5 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -26,7 +26,9 @@ which has strong JSON support. > Figure 1: Benchmark scores of models using either plain markdown text or JSON to return code, > averaged over 5 runs. -> Models produce better code when they return it as plain markdown text, as compared to wrapping it in JSON for a tool function call. +> Models produce better code when they return it as plain markdown text, +> as compared to wrapping it in JSON for a tool function call. +> Except for gpt-4o-2024-05-13. ## Background From e6bf5d8f48aa961fd17547c13cf0608c968f7c29 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 14:09:31 -0700 Subject: [PATCH 090/105] fix: Use base64 to encode images in get_images_message --- aider/coders/base_coder.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index 8c3484c69..55ca97f38 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import base64 import hashlib import json import locale @@ -652,9 +653,11 @@ class Coder: image_messages = [] for fname, content in self.get_abs_fnames_content(): if is_image_file(fname): + with open(fname, "rb") as image_file: + encoded_string = base64.b64encode(image_file.read()).decode('utf-8') mime_type, _ = mimetypes.guess_type(fname) if mime_type and mime_type.startswith("image/"): - image_url = f"data:{mime_type};base64,{content}" + image_url = f"data:{mime_type};base64,{encoded_string}" rel_fname = self.get_rel_fname(fname) image_messages += [ {"type": "text", "text": f"Image file: {rel_fname}"}, From 3baf2db6c95f94f154fd994dee51ce7a90e2b4d1 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 14:26:21 -0700 Subject: [PATCH 091/105] lint --- aider/coders/base_coder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index 55ca97f38..b64aa647d 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -654,7 +654,7 @@ class Coder: for fname, content in self.get_abs_fnames_content(): if is_image_file(fname): with open(fname, "rb") as image_file: - encoded_string = base64.b64encode(image_file.read()).decode('utf-8') + encoded_string = base64.b64encode(image_file.read()).decode("utf-8") mime_type, _ = mimetypes.guess_type(fname) if mime_type and mime_type.startswith("image/"): image_url = f"data:{mime_type};base64,{encoded_string}" From 9a893c9a6ee77a9f32a1759f13422f9d9923a888 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 14:27:52 -0700 Subject: [PATCH 092/105] copy --- HISTORY.md | 5 +++++ aider/website/HISTORY.md | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 6a520a8c2..fdaa14896 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,11 @@ # Release history +### main branch + +- Improved editing performance on Jupyter Notebook `.ipynb` files. +- Work around litellm tokenizer bug for images. + ### Aider v0.50.1 - Bugfix for provider API exceptions. diff --git a/aider/website/HISTORY.md b/aider/website/HISTORY.md index 96420b06a..ca63982ef 100644 --- a/aider/website/HISTORY.md +++ b/aider/website/HISTORY.md @@ -16,6 +16,11 @@ cog.out(text) # Release history +### main branch + +- Improved editing performance on Jupyter Notebook `.ipynb` files. +- Work around litellm tokenizer bug for images. + ### Aider v0.50.1 - Bugfix for provider API exceptions. From 84e24bd5a2961ead6eb3b19c7b4eed8e8c06e36d Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 14:36:11 -0700 Subject: [PATCH 093/105] feat: Show one decimal point for numbers atop bars on wide screens --- aider/website/_includes/code-in-json-benchmark.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aider/website/_includes/code-in-json-benchmark.js b/aider/website/_includes/code-in-json-benchmark.js index befcdc285..a2bf7b050 100644 --- a/aider/website/_includes/code-in-json-benchmark.js +++ b/aider/website/_includes/code-in-json-benchmark.js @@ -108,6 +108,7 @@ document.addEventListener('DOMContentLoaded', function () { plugins: [{ afterDraw: function(chart) { var ctx = chart.ctx; + var isWideScreen = window.innerWidth > 768; // Assuming 768px as the breakpoint for wide screens chart.data.datasets.forEach(function(dataset, i) { var meta = chart.getDatasetMeta(i); meta.data.forEach(function(bar, index) { @@ -116,7 +117,8 @@ document.addEventListener('DOMContentLoaded', function () { ctx.fillStyle = '#000000'; ctx.textAlign = 'center'; ctx.textBaseline = 'bottom'; - ctx.fillText(Math.round(data) + '%', bar.x, bar.y - 5); + var displayText = isWideScreen ? data.toFixed(1) + '%' : Math.round(data) + '%'; + ctx.fillText(displayText, bar.x, bar.y - 5); } }); }); From 2054bef7f9c6d4fab5d1b9ab30409869a44ace28 Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 14:38:37 -0700 Subject: [PATCH 094/105] feat: Omit numbers on narrow screens --- .../_includes/code-in-json-benchmark.js | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/aider/website/_includes/code-in-json-benchmark.js b/aider/website/_includes/code-in-json-benchmark.js index a2bf7b050..3f416c1ca 100644 --- a/aider/website/_includes/code-in-json-benchmark.js +++ b/aider/website/_includes/code-in-json-benchmark.js @@ -109,19 +109,21 @@ document.addEventListener('DOMContentLoaded', function () { afterDraw: function(chart) { var ctx = chart.ctx; var isWideScreen = window.innerWidth > 768; // Assuming 768px as the breakpoint for wide screens - chart.data.datasets.forEach(function(dataset, i) { - var meta = chart.getDatasetMeta(i); - meta.data.forEach(function(bar, index) { - var data = dataset.data[index]; - if (data !== null) { - ctx.fillStyle = '#000000'; - ctx.textAlign = 'center'; - ctx.textBaseline = 'bottom'; - var displayText = isWideScreen ? data.toFixed(1) + '%' : Math.round(data) + '%'; - ctx.fillText(displayText, bar.x, bar.y - 5); - } + if (isWideScreen) { + chart.data.datasets.forEach(function(dataset, i) { + var meta = chart.getDatasetMeta(i); + meta.data.forEach(function(bar, index) { + var data = dataset.data[index]; + if (data !== null) { + ctx.fillStyle = '#000000'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'bottom'; + var displayText = data.toFixed(1) + '%'; + ctx.fillText(displayText, bar.x, bar.y - 5); + } + }); }); - }); + } } }] }; From e0bd9881eafd7c683be84b55cfa4196a616cd5c5 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 14:38:47 -0700 Subject: [PATCH 095/105] copy --- aider/website/_posts/2024-08-14-code-in-json.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index b82900eb5..2c6b6383a 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -1,5 +1,5 @@ --- -title: LLMs are bad at returning code in JSON +title: LLMs are bad at wrapping code in JSON excerpt: LLMs write worse code if you ask them to return the code wrapped in JSON (via a tool or function call). highlight_image: /assets/code-in-json.jpg draft: true @@ -9,7 +9,7 @@ nav_exclude: true {% endif %} -# LLMs are bad at returning code in JSON +# LLMs are bad at wrapping code in JSON AI coding applications should avoid asking LLMs to return code as part of a structured @@ -28,7 +28,6 @@ which has strong JSON support. > averaged over 5 runs. > Models produce better code when they return it as plain markdown text, > as compared to wrapping it in JSON for a tool function call. -> Except for gpt-4o-2024-05-13. ## Background @@ -180,11 +179,11 @@ the result obtained with the markdown strategy. Some noteworthy observations: - OpenAI's gpt-4o-2024-05-13 was the only model where the markdown and JSON results were -close. Using JSON only dropped the score by 0.3 percent, a difference which is +close. Using JSON only dropped the score by 0.4 percent, a difference which is within the margin of error for 5 trials. - The use of OpenAI's new strict mode offered no improvement as compared to non-strict JSON. -Of course, both JSON results were well below the markdown result. +Both JSON results were well below the markdown result. - The results from Sonnet and DeepSeek Coder suffered the worst harm from JSON wrapping. ## Syntax errors @@ -213,7 +212,7 @@ reduces their ability to reason about solving coding problems. While the quantitative results differ from the similar [July 2023 experiments](/2023/07/02/benchmarks.html), -the conclusion seems unchanged: LLMs are bad at returning code in JSON. +the conclusion seems unchanged: LLMs are bad at wrapping code in JSON. OpenAI appears to be making progress in allowing LLMs to return code in structured JSON responses without harming the code quality. From ec836b99cc6b08177d7542e23f45bf866461d60b Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 14:45:13 -0700 Subject: [PATCH 096/105] feat: add test for --model-metadata-file option --- tests/basic/test_main.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/basic/test_main.py b/tests/basic/test_main.py index 1f0d467b5..9a2034be2 100644 --- a/tests/basic/test_main.py +++ b/tests/basic/test_main.py @@ -1,6 +1,7 @@ import os import subprocess import tempfile +import json from io import StringIO from pathlib import Path from unittest import TestCase @@ -489,3 +490,22 @@ class TestMain(TestCase): self.assertIn(real_external_file_path, coder.abs_read_only_fnames) finally: os.unlink(external_file_path) + + def test_model_metadata_file(self): + with GitTemporaryDirectory(): + metadata_file = Path(".aider.model.metadata.json") + metadata_content = { + "deepseek-chat": { + "max_input_tokens": 1234 + } + } + metadata_file.write_text(json.dumps(metadata_content)) + + coder = main( + ["--model", "deepseek-chat", "--model-metadata-file", str(metadata_file), "--exit", "--yes"], + input=DummyInput(), + output=DummyOutput(), + return_coder=True, + ) + + self.assertEqual(coder.main_model.info["max_input_tokens"], 1234) From cb9da29bc3dbd1111bc12f286540b74135615e9e Mon Sep 17 00:00:00 2001 From: "Paul Gauthier (aider)" Date: Thu, 15 Aug 2024 14:45:16 -0700 Subject: [PATCH 097/105] style: Apply linter edits to test_main.py --- tests/basic/test_main.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/basic/test_main.py b/tests/basic/test_main.py index 9a2034be2..2748f0ee9 100644 --- a/tests/basic/test_main.py +++ b/tests/basic/test_main.py @@ -1,7 +1,7 @@ +import json import os import subprocess import tempfile -import json from io import StringIO from pathlib import Path from unittest import TestCase @@ -494,15 +494,18 @@ class TestMain(TestCase): def test_model_metadata_file(self): with GitTemporaryDirectory(): metadata_file = Path(".aider.model.metadata.json") - metadata_content = { - "deepseek-chat": { - "max_input_tokens": 1234 - } - } + metadata_content = {"deepseek-chat": {"max_input_tokens": 1234}} metadata_file.write_text(json.dumps(metadata_content)) coder = main( - ["--model", "deepseek-chat", "--model-metadata-file", str(metadata_file), "--exit", "--yes"], + [ + "--model", + "deepseek-chat", + "--model-metadata-file", + str(metadata_file), + "--exit", + "--yes", + ], input=DummyInput(), output=DummyOutput(), return_coder=True, From 0dacb3f54011bf14bb6541b3124ba3a1b02445d6 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 14:59:28 -0700 Subject: [PATCH 098/105] copy --- aider/website/docs/config/adv-model-settings.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/aider/website/docs/config/adv-model-settings.md b/aider/website/docs/config/adv-model-settings.md index 6cf7b9909..4ec8949e5 100644 --- a/aider/website/docs/config/adv-model-settings.md +++ b/aider/website/docs/config/adv-model-settings.md @@ -27,7 +27,7 @@ The json file should be a dictionary with an entry for each model, as follows: ``` { - "deepseek-chat": { + "deepseek/deepseek-chat": { "max_tokens": 4096, "max_input_tokens": 32000, "max_output_tokens": 4096, @@ -42,6 +42,11 @@ The json file should be a dictionary with an entry for each model, as follows: See [litellm's model_prices_and_context_window.json file](https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json) for more examples. +{: .tip } +Use a fully qualified model name with a `provider/` at the front +in the `.aider.model.metadata.json` file. +For example, use `deepseek/deepseek-chat`, not just `deepseek-chat`. + ## Model settings Aider has a number of settings that control how it works with From c66a771119175b9b407efdaf6752bbc28df451a6 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 15:40:11 -0700 Subject: [PATCH 099/105] copy --- aider/website/_posts/2024-08-14-code-in-json.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 2c6b6383a..5e28d3420 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -13,8 +13,9 @@ nav_exclude: true AI coding applications should avoid asking LLMs to return code as part of a structured -JSON response, -even though many LLMs have special support for returning JSON. +JSON response. +Even though many LLMs have special support for returning JSON, +using it with code often causes lower quality code generation. A variant of the aider code editing benchmark clearly demonstrates that asking for JSON-wrapped code often harms coding performance. From 4081f2c5b19dd9c8e27a455b1b17fdaff98cc82f Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Thu, 15 Aug 2024 15:42:15 -0700 Subject: [PATCH 100/105] fix metadata file test --- tests/basic/test_main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/basic/test_main.py b/tests/basic/test_main.py index 2748f0ee9..c7418b809 100644 --- a/tests/basic/test_main.py +++ b/tests/basic/test_main.py @@ -494,13 +494,15 @@ class TestMain(TestCase): def test_model_metadata_file(self): with GitTemporaryDirectory(): metadata_file = Path(".aider.model.metadata.json") - metadata_content = {"deepseek-chat": {"max_input_tokens": 1234}} + + # must be a fully qualified model name: provider/... + metadata_content = {"deepseek/deepseek-chat": {"max_input_tokens": 1234}} metadata_file.write_text(json.dumps(metadata_content)) coder = main( [ "--model", - "deepseek-chat", + "deepseek/deepseek-chat", "--model-metadata-file", str(metadata_file), "--exit", From f9ad633ee05911c0c6921bbe1d327ebcad515c87 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Fri, 16 Aug 2024 06:13:13 -0700 Subject: [PATCH 101/105] copy --- .../_includes/code-in-json-benchmark.js | 2 +- .../website/_posts/2024-08-14-code-in-json.md | 149 +++++++++--------- 2 files changed, 79 insertions(+), 72 deletions(-) diff --git a/aider/website/_includes/code-in-json-benchmark.js b/aider/website/_includes/code-in-json-benchmark.js index 3f416c1ca..b7e89568b 100644 --- a/aider/website/_includes/code-in-json-benchmark.js +++ b/aider/website/_includes/code-in-json-benchmark.js @@ -81,7 +81,7 @@ document.addEventListener('DOMContentLoaded', function () { plugins: { title: { display: true, - text: 'Pass rate by model and code wrapping strategy', + text: 'Coding skill by model and code wrapping strategy', font: { size: 16 } diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 5e28d3420..fa774eb2e 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -1,6 +1,6 @@ --- -title: LLMs are bad at wrapping code in JSON -excerpt: LLMs write worse code if you ask them to return the code wrapped in JSON (via a tool or function call). +title: LLMs are bad at returning code in JSON +excerpt: LLMs write worse code if you ask them to return the code wrapped in JSON via a tool function call. highlight_image: /assets/code-in-json.jpg draft: true nav_exclude: true @@ -9,36 +9,27 @@ nav_exclude: true {% endif %} -# LLMs are bad at wrapping code in JSON +# LLMs are bad at returning code in JSON -AI coding applications should avoid asking LLMs to return code as part of a structured -JSON response. -Even though many LLMs have special support for returning JSON, -using it with code often causes lower quality code generation. -A variant of the aider code editing benchmark clearly demonstrates that -asking for JSON-wrapped code -often harms coding performance. -This holds true across many top coding LLMs, -including OpenAI's latest model gpt-4o-2024-08-06 -which has strong JSON support. +LLMs produce lower quality code if they’re asked to return it as part of a structured JSON response. This seems to be true for many top models, including those with specialized support for JSON. Benchmarks show that models struggle with syntactic issues related to quoting and escaping. +The benchmark results also imply a decreased capacity for solving coding problems due to the burden of JSON formatting. {% include code-in-json-benchmark.js %} -> Figure 1: Benchmark scores of models using either plain markdown text or JSON to return code, -> averaged over 5 runs. -> Models produce better code when they return it as plain markdown text, -> as compared to wrapping it in JSON for a tool function call. +> Figure 1: Aider coding benchmark scores of models using either plain markdown text or JSON to return code. +> Pass rate (%) averaged over 5 runs. +> Models produce better code when they return it as markdown text, +> as compared to returning code in a structured JSON response. ## Background -A lot of people wonder why aider does not use LLM tools for code editing. -Instead, aider asks for code edits in plain text, like this: +People often ask why aider uses a plain text format for LLMs to specify code edits (below), +rather than relying on LLM tools and structured JSON responses. -```` +```python greeting.py -``` <<<<<<< SEARCH def greeting(): print("Hello") @@ -47,10 +38,9 @@ def greeting(): print("Goodbye") >>>>>>> REPLACE ``` -```` People expect that it would be easier and more reliable to use tool calls, -which would return a structured JSON response: +which would involve a structured JSON response more like this: ```json { @@ -60,7 +50,7 @@ which would return a structured JSON response: } ``` -This has become even more tempting as LLM providers +This question becomes increasingly relevant as LLM providers continue to improve their tooling for reliably generating JSON. For example, [OpenAI recently announced](https://openai.com/index/introducing-structured-outputs-in-the-api/) @@ -68,10 +58,9 @@ the ability to strictly enforce that JSON responses will be syntactically correct and conform to a specified schema. - -But producing valid JSON is not sufficient for working with AI generated code. -The code inside the JSON has to correctly solve the requested task -and be free from syntax errors. +But just producing valid JSON is not sufficient for AI code generation -- +the code inside the JSON matters too. +It has to be high quality code that solves the assigned coding task without errors or bugs. Unfortunately, LLMs write worse code when they're asked to wrap it in JSON. @@ -90,7 +79,7 @@ own escape sequences. Would *you* write better code by typing it out normally -or as a properly escaped +or typing it as a properly escaped JSON string? @@ -102,26 +91,29 @@ the superiority of returning code as plain text compared to JSON-wrapped function calls. Those results were obtained over a year ago, against models far less capable than those available today. -OpenAI's newly announced support for "strict" JSON seemed like a good reason to -investigate whether the newest models are still handicapped when JSON-wrapping code. +OpenAI's newly announced support for "strict" JSON +suggests the possibility that modern models might be able +to return quality code inside a structured JSON response. -The results presented here were based on +The results presented here are based on the [aider "code editing" benchmark](/2023/07/02/benchmarks.html#the-benchmark) of 133 practice exercises from the Exercism python repository. -Models were -restricted to a single attempt to solve each task, -without a second try to fix errors as is normal in the aider benchmark. +The benchmark was simplified somewhat to focus on the differences between +plain text and JSON responses. +In particular, models were +restricted to a single attempt to solve each task +without a second try to fix errors. The performance of each model was compared across different strategies for returning code: - **Markdown** -- the model returned the whole source code file in standard markdown triple-backtick fences. -- **JSON** -- the model used a tool function call to return the whole source code file. This required the LLM to wrap the code in JSON. -- **JSON (strict)** -- the same as the "JSON" strategy, but with `strict=True`. Only gpt-4o-2024-08-06 supports this setting. +- **JSON** -- the model used a tool function call to return the whole source code file in a structured JSON response. +- **JSON (strict)** -- the same as the "JSON" strategy, but with `strict=True`. Only gpt-4o-2024-08-06 supported this setting. -The markdown strategy is the same as +The markdown strategy was the same as aider's "whole" edit format, where the -LLM returns a source file like this: +LLM returns an entire updated copy of the source file like this: ```` Here is the program you asked for which prints "Hello": @@ -133,9 +125,10 @@ def greeting(): ``` ```` -The JSON and JSON (strict) strategies required the LLM to call the `write_file` function with -two parameters, as shown below. -For maximum simplicity, the LLM didn't have to specify the filename, +Both JSON strategies required the LLM to call the `write_file` function with +an explanation/plan and +the entire updated copy of the source file. +The LLM didn't have to specify the filename, since the benchmark operates on one source file at a time. ```json @@ -145,15 +138,6 @@ since the benchmark operates on one source file at a time. } ``` -These strategies avoid actually *editing* source files, to keep -the task as -simple as possible. -The LLM is able to emit the whole source file intact, -which is much easier -than correctly formulating -instructions to edit -portions of a file. - This experimental setup was designed to quantify the effects of JSON-wrapping on the LLMs ability to write code to solve a task. @@ -169,13 +153,13 @@ to assess the impact of JSON-wrapping code: Each combination of model and code wrapping strategy was benchmarked 5 times. -## Overall coding skill +### Overall coding skill As shown in Figure 1, all of the models did worse on the benchmark when asked to -return JSON-wrapped code in a tool function call. +return code in a structured JSON response. Most did significantly worse, performing well below -the result obtained with the markdown strategy. +their result with the markdown strategy. Some noteworthy observations: @@ -187,20 +171,30 @@ as compared to non-strict JSON. Both JSON results were well below the markdown result. - The results from Sonnet and DeepSeek Coder suffered the worst harm from JSON wrapping. -## Syntax errors +### Syntax errors Models tend to make more syntax errors when asked to wrap code in JSON. Figure 2 shows the number of syntax errors found in the code produced by each -model and code wrapping strategy, -totaling up `SyntaxError` and `IndentationError` errors from all 5 runs. +model and code wrapping strategy. +It totals up the `SyntaxError` and `IndentationError` errors from all 5 runs, +for each model and strategy combination. +Below is an example of a `SyntaxError` created by gpt-4o-2024-05-13 using the +JSON code wrapping strategy. +It appears that the model got confused about escaping and quoting while trying +to format the JSON response. +The source code contains a single-quoted string which also +contains a single-quote character. +The word `There'll` should have been escaped as `There\'ll`. -Sonnet's results seems to indicate that the negative effects of JSON-wrapping -go beyond syntactic difficulties. -Sonnet avoided syntax errors regardless of the code wrapping strategy, -but its benchmark scores in Figure 1 were nonetheless lower with JSON. -This implies that JSON-wrapping may distract or challenge models in a way that -reduces their ability to reason about solving coding problems. +```python +Traceback (most recent call last): + ... + File "bottle-song/bottle_song.py", line 9 + lyrics.append(f'There'll be {i - 1} green bottles hanging on the wall.') + ^ +SyntaxError: unterminated string literal (detected at line 9) +``` {% include code-in-json-syntax.js %} @@ -208,23 +202,36 @@ reduces their ability to reason about solving coding problems. > totaled from 5 runs. > Models tend to make more syntax and formatting errors when asked to wrap code in JSON. +### Beyond syntax errors + +Sonnet's results seems to indicate that the negative effects of JSON-wrapping +go beyond just syntactic difficulties. +Sonnet avoided syntax errors regardless of the code wrapping strategy, +but its benchmark scores in Figure 1 were nonetheless lower with JSON. +This implies that JSON-wrapping may distract or challenge models in a way that +reduces their ability to reason about solving coding problems. + + ## Conclusions -While the quantitative results differ from the similar +While the specific results differ from the similar [July 2023 experiments](/2023/07/02/benchmarks.html), -the conclusion seems unchanged: LLMs are bad at wrapping code in JSON. +the conclusion remains unchanged: LLMs are bad at returning code in +structured JSON responses. -OpenAI appears to be making progress in allowing LLMs to return code in -structured JSON responses without harming the code quality. -But it still seems premature to consider switching from plain text +OpenAI appears to be making progress in allowing LLMs to +return JSON-wrapped code +without harming the code quality. +But it seems premature to consider switching from plain text to JSON-wrapped code. +--------- -## Notes on the aider leaderboard +#### Notes on the aider leaderboard -The results presented here are not directly comparable to results +*The results presented here are not directly comparable to results from the main [aider LLM leaderboard](https://aider.chat/docs/leaderboards/). A number of settings were changed to simplify the benchmark -in order to focus on comparing plain text and JSON-wrapped code. +in order to focus on comparing plain text and JSON-wrapped code.* From ed45baf85a5d0dcfa5638d3a567356a66c2ce700 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Fri, 16 Aug 2024 06:38:37 -0700 Subject: [PATCH 102/105] copy --- aider/website/_posts/2024-08-14-code-in-json.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index fa774eb2e..40a582f0e 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -224,7 +224,7 @@ OpenAI appears to be making progress in allowing LLMs to return JSON-wrapped code without harming the code quality. But it seems premature to consider switching from plain text -to JSON-wrapped code. +to JSON-wrapped code at this time. --------- From b1f2000f2a9a211d5d7d5f898d80f81208f6e6b1 Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Fri, 16 Aug 2024 06:39:26 -0700 Subject: [PATCH 103/105] copy --- .../website/_posts/2024-08-14-code-in-json.md | 1 - aider/website/assets/code-as-json.jpg | Bin 0 -> 161674 bytes 2 files changed, 1 deletion(-) create mode 100644 aider/website/assets/code-as-json.jpg diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 40a582f0e..7c8c88921 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -2,7 +2,6 @@ title: LLMs are bad at returning code in JSON excerpt: LLMs write worse code if you ask them to return the code wrapped in JSON via a tool function call. highlight_image: /assets/code-in-json.jpg -draft: true nav_exclude: true --- {% if page.date %} diff --git a/aider/website/assets/code-as-json.jpg b/aider/website/assets/code-as-json.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a7686a64a3d0d3f65ed0192f6aff7aaad3cf57cc GIT binary patch literal 161674 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
Oc-~L7C|GQ`DMh>!Y-HD-yRx+$x@}w^| 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 b!W4keuJ=DbA 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%0D9);P>?6{v$-H|Nr|Bt(|Xi z4qyL3m(*{uzCUBmO_^oo11BG!UwBlxsWmJ#dH3;f*dg3{@us zqHej=5zte>go4A4sn|+Nl0>V9;oh0>GVChJ=*pFB2U|w*)b)ugtSaQ>Q@FUz%hR)? zx7#d5KD8+aQ$!hqF!Fhh9RMj%O|qf{vW<8v!LiIPjYx^6K(^=odyD7sVI_x7Ocs4P z=Xc*k1S?~&&Em~z1_^^ei^}MswiutgIiI*^H(ON1O=O~tT}N8B#yQx!$#ID=K4W@r zksw+L&hvMAfV~g8ZtY-Q9j7auwn_pagbDi?wF_*-ejjOC=_WS^Pz!XgWmMq44mRR@nC_ykG>8GG`_g0OAs zmo`UiDujhwC;G)>6HxqJytJEeFj0W!&^v673E}%Ht2)aQqf*})9M}6Qh3k|ePrWqk zzW_;KFteI`D}udf(?k5&!vcEJ`AdE_8ApAT+}O4=raQ+QPMfyK=|kDbDUYWrsW;`p zLoDwsglK#Jt={tm+tSVZ$C8|MWqn4GcO6h(A7(SWT^Tjc%x@qA>uVo7u6H*X4h(lh zd5QEOKrWaBDGbp>s+H}`m7=8+LroUfeIQP)%xbTfCP$xJYQ&7rQwC6jbjdD@Bw%`N z1SH;_CMB%+HzG^_4dJH$#hB=?f1s1%pJBA$Vhlq%a1!%Hd&Cf;kO$Hw7efXr3k3ji zmInv@pag(*qxHK_TkM+d=*T3UNvz3sK*txUjHkB%isqO#K&y^uvmn1sv5SJYc^f_# zg411O!x{jy6<=D^DP(&&{N6-~qQzq5DYW|L5)&4XEYYYf)RxuipV3jZY~^XZ_&Bo$ zE=~YZi|a)jK?T0%SE(S3BBG18;#r*{$L)&VwY>3bg=*V(e4?XFCXZkrq)cP@SfK^~ zW+h7{i4>lvd1Cavk1N?Fr#t7?w&YzLX$K8uBm|5$3S;{4PL%{Yv-U<7@y!T#j_RSH zt~VI@d9B7+ni%46Bpd)~EFyE-l%*~*yb!XokLzg;Q?7XZ-VkN>OhtEdZf?KFYv3Vs zI-Xx549#jk4Z`cL<^1&1_(9{Y%RlZNkWODwFBKz=T^>y0JCg?U;=(@xD?*w# z_SD3Fgzw2fVfvFI!|KP#P6$ovz4lC-9=S=C>E~|=P=068&y~L)=%M5v2(!{YkXLt- z6kMb+Mv;N_5L!qIv{2eQNjLm(CEtQ`_y$X?D#dm+=jsO4WTS2zU!PbwZxDFbKHOq4t^8kH)0dffiNdQz3)e-{5lQDl7!#<` zy-nezdHYGZ>Mu>P$3dI6$3gKT!!i) Date: Fri, 16 Aug 2024 06:41:49 -0700 Subject: [PATCH 104/105] copy --- .../assets/{code-as-json.jpg => code-in-json.jpg} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename aider/website/assets/{code-as-json.jpg => code-in-json.jpg} (100%) diff --git a/aider/website/assets/code-as-json.jpg b/aider/website/assets/code-in-json.jpg similarity index 100% rename from aider/website/assets/code-as-json.jpg rename to aider/website/assets/code-in-json.jpg From dde7470f4ddffad16ce1d29210a53185e125283f Mon Sep 17 00:00:00 2001 From: Paul Gauthier Date: Fri, 16 Aug 2024 07:03:42 -0700 Subject: [PATCH 105/105] copy --- .../website/_posts/2024-08-14-code-in-json.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/aider/website/_posts/2024-08-14-code-in-json.md b/aider/website/_posts/2024-08-14-code-in-json.md index 7c8c88921..d5d695998 100644 --- a/aider/website/_posts/2024-08-14-code-in-json.md +++ b/aider/website/_posts/2024-08-14-code-in-json.md @@ -182,9 +182,6 @@ Below is an example of a `SyntaxError` created by gpt-4o-2024-05-13 using the JSON code wrapping strategy. It appears that the model got confused about escaping and quoting while trying to format the JSON response. -The source code contains a single-quoted string which also -contains a single-quote character. -The word `There'll` should have been escaped as `There\'ll`. ```python Traceback (most recent call last): @@ -195,6 +192,21 @@ Traceback (most recent call last): SyntaxError: unterminated string literal (detected at line 9) ``` +The problematic line of code contains a single-quoted string which also +contains a single-quote character. +It should have been output as the following chunk of JSON, with +a double slash in `There\\'ll`. +That is needed to JSON-escape the `\` so that it survives +JSON-decoding to +produce `There\'ll` in the resulting code. +That would correctly escape the single-quote inside the single-quoted string. + +``` +...lyrics.append(f'There\\'ll be {i - 1} green bottles hanging on the wall.')\n... +``` + + + {% include code-in-json-syntax.js %} > Figure 2: Number of `SyntaxError` and `IndentationError` errors found in model generated code,