diff --git a/.github/workflows/docker-build-test.yml b/.github/workflows/docker-build-test.yml
index 3bafc3cf5..f5872ce8b 100644
--- a/.github/workflows/docker-build-test.yml
+++ b/.github/workflows/docker-build-test.yml
@@ -4,14 +4,19 @@ on:
push:
paths-ignore:
- 'aider/website/**'
- - README.md
- - HISTORY.md
+ - 'README.md'
+ - 'HISTORY.md'
+ - '.github/workflows/*'
+ - '!.github/workflows/docker-build-test.yml'
branches:
- main
pull_request:
paths-ignore:
- 'aider/website/**'
- - README.md
+ - 'README.md'
+ - 'HISTORY.md'
+ - '.github/workflows/*'
+ - '!.github/workflows/docker-build-test.yml'
branches:
- main
@@ -31,12 +36,24 @@ jobs:
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
+ if: ${{ github.event_name != 'pull_request' }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- - name: Build and push Docker images
+ - name: Build Docker images (PR)
+ if: ${{ github.event_name == 'pull_request' }}
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ file: ./docker/Dockerfile
+ platforms: linux/amd64,linux/arm64
+ push: false
+ target: aider
+
+ - name: Build Docker images (Push)
+ if: ${{ github.event_name != 'pull_request' }}
uses: docker/build-push-action@v5
with:
context: .
@@ -46,7 +63,18 @@ jobs:
tags: ${{ secrets.DOCKERHUB_USERNAME }}/aider:dev
target: aider
- - name: Build and push Docker full image
+ - name: Build Docker full image (PR)
+ if: ${{ github.event_name == 'pull_request' }}
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ file: ./docker/Dockerfile
+ platforms: linux/amd64,linux/arm64
+ push: false
+ target: aider-full
+
+ - name: Build Docker full image (Push)
+ if: ${{ github.event_name != 'pull_request' }}
uses: docker/build-push-action@v5
with:
context: .
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 916742746..4454e832f 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -12,6 +12,7 @@ on:
- "main"
paths:
- "aider/website/**"
+ - ".github/workflows/pages.yml"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
@@ -55,10 +56,9 @@ jobs:
env:
JEKYLL_ENV: production
- name: Upload artifact
- # Automatically uploads an artifact from the './_site' directory by default
- uses: actions/upload-pages-artifact@v1
+ uses: actions/upload-pages-artifact@v3
with:
- path: "aider/website/_site/"
+ path: "aider/website/_site"
# Deployment job
deploy:
@@ -70,7 +70,7 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
- uses: actions/deploy-pages@v2
+ uses: actions/deploy-pages@v4
- name: Set up Python 3.12
uses: actions/setup-python@v5
diff --git a/.github/workflows/ubuntu-tests.yml b/.github/workflows/ubuntu-tests.yml
index 5efd26520..632c03757 100644
--- a/.github/workflows/ubuntu-tests.yml
+++ b/.github/workflows/ubuntu-tests.yml
@@ -4,14 +4,19 @@ on:
push:
paths-ignore:
- 'aider/website/**'
- - README.md
- - HISTORY.md
+ - 'README.md'
+ - 'HISTORY.md'
+ - '.github/workflows/*'
+ - '!.github/workflows/ubuntu-tests.yml'
branches:
- main
pull_request:
paths-ignore:
- 'aider/website/**'
- - README.md
+ - 'README.md'
+ - 'HISTORY.md'
+ - '.github/workflows/*'
+ - '!.github/workflows/ubuntu-tests.yml'
branches:
- main
diff --git a/.github/workflows/windows-tests.yml b/.github/workflows/windows-tests.yml
index bbc6a9b37..21799563e 100644
--- a/.github/workflows/windows-tests.yml
+++ b/.github/workflows/windows-tests.yml
@@ -4,14 +4,19 @@ on:
push:
paths-ignore:
- 'aider/website/**'
- - README.md
- - HISTORY.md
+ - 'README.md'
+ - 'HISTORY.md'
+ - '.github/workflows/*'
+ - '!.github/workflows/windows-tests.yml'
branches:
- main
pull_request:
paths-ignore:
- 'aider/website/**'
- - README.md
+ - 'README.md'
+ - 'HISTORY.md'
+ - '.github/workflows/*'
+ - '!.github/workflows/windows-tests.yml'
branches:
- main
diff --git a/HISTORY.md b/HISTORY.md
index b0c445176..956a35111 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,12 +1,35 @@
# Release history
+### Aider v0.72.3
+
+- Enforce user/assistant turn order to avoid R1 errors, by miradnanali.
+- Case-insensitive model name matching while preserving original case.
+- Aider wrote 67% of the code in this release.
+
+### Aider v0.72.2
+- Harden against user/assistant turn order problems which cause R1 errors.
+- Added environment variable AIDER_SANITY_CHECK_TURNS for turn order validation.
+
+### Aider v0.72.1
+- Fix model metadata for `openrouter/deepseek/deepseek-r1`
+
+### Aider v0.72.0
+- Support for DeepSeek R1.
+ - Use shortcut: `--model r1`
+ - Also via OpenRouter: `--model openrouter/deepseek/deepseek-r1`
+- Added Kotlin syntax support to repo map, by Paul Walker.
+- Added `--line-endings` for file writing, by Titusz Pan.
+- Added examples_as_sys_msg=True for GPT-4o models, improves benchmark scores.
+- Bumped all dependencies, to pick up litellm support for o1 system messages.
+- Bugfix for turn taking when reflecting lint/test errors.
+- Aider wrote 52% of the code in this release.
+
### Aider v0.71.1
- Fix permissions issue in Docker images.
-- Added read-only file announcements to chat.
+- Added read-only file announcements.
- Bugfix: ASCII fallback for unicode errors.
- Bugfix: integer indices for list slicing in repomap calculations.
-- Aider wrote 83% of the code in this release.
### Aider v0.71.0
diff --git a/README.md b/README.md
index 13f324766..675dd3468 100644
--- a/README.md
+++ b/README.md
@@ -52,11 +52,14 @@ aider-install
# Change directory into your code base
cd /to/your/project
+# Work with DeepSeek on your code
+aider --model deepseek --api-key deepseek=your-key-goes-here
+
# Work with Claude 3.5 Sonnet on your code
-aider --model sonnet --anthropic-api-key your-key-goes-here
+aider --model sonnet --api-key anthropic=your-key-goes-here
# Work with GPT-4o on your code
-aider --model gpt-4o --openai-api-key your-key-goes-here
+aider --model gpt-4o --api-key openai=your-key-goes-here
```
@@ -72,7 +75,7 @@ for more details.
- Ask for changes:
- Add new features or test cases.
- Describe a bug.
- - Paste in an error message or or GitHub issue URL.
+ - Paste in an error message or GitHub issue URL.
- Refactor code.
- Update docs.
- Aider will edit your files to complete your request.
diff --git a/aider/__init__.py b/aider/__init__.py
index daea92549..db534823f 100644
--- a/aider/__init__.py
+++ b/aider/__init__.py
@@ -1,6 +1,6 @@
from packaging import version
-__version__ = "0.71.2.dev"
+__version__ = "0.72.4.dev"
safe_version = __version__
try:
diff --git a/aider/args.py b/aider/args.py
index 642858ec3..b880605a9 100644
--- a/aider/args.py
+++ b/aider/args.py
@@ -766,6 +766,12 @@ def get_parser(default_config_files, git_root):
default="utf-8",
help="Specify the encoding for input and output (default: utf-8)",
)
+ group.add_argument(
+ "--line-endings",
+ choices=["platform", "lf", "crlf"],
+ default="platform",
+ help="Line endings to use when writing files (default: platform)",
+ )
group.add_argument(
"-c",
"--config",
diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py
index 8e7814372..bcb68bb68 100755
--- a/aider/coders/base_coder.py
+++ b/aider/coders/base_coder.py
@@ -459,6 +459,7 @@ class Coder:
self.summarizer_thread = None
self.summarized_done_messages = []
+ self.summarizing_messages = None
if not self.done_messages and restore_chat_history:
history_md = self.io.read_text(self.io.chat_history_file)
@@ -942,8 +943,9 @@ class Coder:
self.summarizer_thread.start()
def summarize_worker(self):
+ self.summarizing_messages = list(self.done_messages)
try:
- self.summarized_done_messages = self.summarizer.summarize(self.done_messages)
+ self.summarized_done_messages = self.summarizer.summarize(self.summarizing_messages)
except ValueError as err:
self.io.tool_warning(err.args[0])
@@ -957,7 +959,9 @@ class Coder:
self.summarizer_thread.join()
self.summarizer_thread = None
- self.done_messages = self.summarized_done_messages
+ if self.summarizing_messages == self.done_messages:
+ self.done_messages = self.summarized_done_messages
+ self.summarizing_messages = None
self.summarized_done_messages = []
def move_back_cur_messages(self, message):
@@ -1226,6 +1230,44 @@ class Coder:
return chunks
+ def check_tokens(self, messages):
+ """Check if the messages will fit within the model's token limits."""
+ input_tokens = self.main_model.token_count(messages)
+ max_input_tokens = self.main_model.info.get("max_input_tokens") or 0
+
+ proceed = None
+
+ if max_input_tokens and input_tokens >= max_input_tokens:
+ self.io.tool_error(
+ f"Your estimated chat context of {input_tokens:,} tokens exceeds the"
+ f" {max_input_tokens:,} token limit for {self.main_model.name}!"
+ )
+ self.io.tool_output("To reduce the chat context:")
+ self.io.tool_output("- Use /drop to remove unneeded files from the chat")
+ self.io.tool_output("- Use /clear to clear the chat history")
+ self.io.tool_output("- Break your code into smaller files")
+ proceed = "Y"
+ self.io.tool_output(
+ "It's probably safe to try and send the request, most providers won't charge if"
+ " the context limit is exceeded."
+ )
+
+ # Special warning for Ollama models about context window size
+ if self.main_model.name.startswith(("ollama/", "ollama_chat/")):
+ extra_params = getattr(self.main_model, "extra_params", None) or {}
+ num_ctx = extra_params.get("num_ctx", 2048)
+ if input_tokens > num_ctx:
+ proceed = "N"
+ self.io.tool_warning(f"""
+Your Ollama model is configured with num_ctx={num_ctx} tokens of context window.
+You are attempting to send {input_tokens} tokens.
+See https://aider.chat/docs/llms/ollama.html#setting-the-context-window-size
+""".strip()) # noqa
+
+ if proceed and not self.io.confirm_ask("Try to proceed anyway?", default=proceed):
+ return False
+ return True
+
def send_message(self, inp):
self.event("message_send_starting")
@@ -1235,6 +1277,8 @@ class Coder:
chunks = self.format_messages()
messages = chunks.all_messages()
+ if not self.check_tokens(messages):
+ return
self.warm_cache(chunks)
if self.verbose:
@@ -1322,7 +1366,17 @@ class Coder:
self.show_usage_report()
+ self.add_assistant_reply_to_cur_messages()
+
if exhausted:
+ if self.cur_messages and self.cur_messages[-1]["role"] == "user":
+ self.cur_messages += [
+ dict(
+ role="assistant",
+ content="FinishReasonLength exception: you sent too many tokens",
+ ),
+ ]
+
self.show_exhausted_error()
self.num_exhausted_context_windows += 1
return
@@ -1353,14 +1407,17 @@ class Coder:
interrupted = True
if interrupted:
- content += "\n^C KeyboardInterrupt"
- self.cur_messages += [dict(role="assistant", content=content)]
+ if self.cur_messages and self.cur_messages[-1]["role"] == "user":
+ self.cur_messages[-1]["content"] += "\n^C KeyboardInterrupt"
+ else:
+ self.cur_messages += [dict(role="user", content="^C KeyboardInterrupt")]
+ self.cur_messages += [
+ dict(role="assistant", content="I see that you interrupted my previous reply.")
+ ]
return
edited = self.apply_updates()
- self.update_cur_messages()
-
if edited:
self.aider_edited_files.update(edited)
saved_message = self.auto_commit(edited)
@@ -1381,7 +1438,6 @@ class Coder:
ok = self.io.confirm_ask("Attempt to fix lint errors?")
if ok:
self.reflected_message = lint_errors
- self.update_cur_messages()
return
shared_output = self.run_shell_commands()
@@ -1398,7 +1454,6 @@ class Coder:
ok = self.io.confirm_ask("Attempt to fix test errors?")
if ok:
self.reflected_message = test_errors
- self.update_cur_messages()
return
def reply_completed(self):
@@ -1474,7 +1529,7 @@ class Coder:
return res
- def update_cur_messages(self):
+ def add_assistant_reply_to_cur_messages(self):
if self.partial_response_content:
self.cur_messages += [dict(role="assistant", content=self.partial_response_content)]
if self.partial_response_function_call:
@@ -1827,7 +1882,16 @@ class Coder:
if new.rstrip() != new and not final:
new = new.rstrip()
- return cur + new
+
+ res = cur + new
+
+ if self.main_model.remove_reasoning:
+ pattern = (
+ f"<{self.main_model.remove_reasoning}>.*?{self.main_model.remove_reasoning}>"
+ )
+ res = re.sub(pattern, "", res, flags=re.DOTALL).strip()
+
+ return res
def get_rel_fname(self, fname):
try:
diff --git a/aider/coders/single_wholefile_func_coder.py b/aider/coders/single_wholefile_func_coder.py
index a10efdbb4..493581c46 100644
--- a/aider/coders/single_wholefile_func_coder.py
+++ b/aider/coders/single_wholefile_func_coder.py
@@ -38,7 +38,7 @@ class SingleWholeFileFunctionCoder(Coder):
self.gpt_prompts = SingleWholeFileFunctionPrompts()
super().__init__(*args, **kwargs)
- def update_cur_messages(self, edited):
+ def add_assistant_reply_to_cur_messages(self, edited):
if edited:
self.cur_messages += [
dict(role="assistant", content=self.gpt_prompts.redacted_edit_message)
diff --git a/aider/coders/wholefile_func_coder.py b/aider/coders/wholefile_func_coder.py
index 987010ea7..3c4fbd3ca 100644
--- a/aider/coders/wholefile_func_coder.py
+++ b/aider/coders/wholefile_func_coder.py
@@ -49,7 +49,7 @@ class WholeFileFunctionCoder(Coder):
self.gpt_prompts = WholeFileFunctionPrompts()
super().__init__(*args, **kwargs)
- def update_cur_messages(self, edited):
+ def add_assistant_reply_to_cur_messages(self, edited):
if edited:
self.cur_messages += [
dict(role="assistant", content=self.gpt_prompts.redacted_edit_message)
diff --git a/aider/commands.py b/aider/commands.py
index ab5f121a8..4d67ba92e 100644
--- a/aider/commands.py
+++ b/aider/commands.py
@@ -1070,7 +1070,7 @@ class Commands:
return self._generic_chat_command(args, self.coder.main_model.edit_format)
def cmd_architect(self, args):
- """Enter architect mode to discuss high-level design and architecture. If no prompt provided, switches to architect mode.""" # noqa
+ """Enter architect/editor mode using 2 different models. If no prompt provided, switches to architect/editor mode.""" # noqa
return self._generic_chat_command(args, "architect")
def _generic_chat_command(self, args, edit_format):
diff --git a/aider/history.py b/aider/history.py
index 2141a7f81..4f22f3a8e 100644
--- a/aider/history.py
+++ b/aider/history.py
@@ -26,6 +26,12 @@ class ChatSummary:
return sized
def summarize(self, messages, depth=0):
+ messages = self.summarize_real(messages)
+ if messages and messages[-1]["role"] != "assistant":
+ messages.append(dict(role="assistant", content="Ok."))
+ return messages
+
+ def summarize_real(self, messages, depth=0):
if not self.models:
raise ValueError("No models available for summarization")
@@ -88,7 +94,7 @@ class ChatSummary:
if summary_tokens + tail_tokens < self.max_tokens:
return result
- return self.summarize(result, depth + 1)
+ return self.summarize_real(result, depth + 1)
def summarize_all(self, messages):
content = ""
diff --git a/aider/io.py b/aider/io.py
index dc50b4178..87bce5b17 100644
--- a/aider/io.py
+++ b/aider/io.py
@@ -198,6 +198,7 @@ class InputOutput:
completion_menu_current_bg_color=None,
code_theme="default",
encoding="utf-8",
+ line_endings="platform",
dry_run=False,
llm_history_file=None,
editingmode=EditingMode.EMACS,
@@ -244,6 +245,15 @@ class InputOutput:
self.chat_history_file = None
self.encoding = encoding
+ valid_line_endings = {"platform", "lf", "crlf"}
+ if line_endings not in valid_line_endings:
+ raise ValueError(
+ f"Invalid line_endings value: {line_endings}. "
+ f"Must be one of: {', '.join(valid_line_endings)}"
+ )
+ self.newline = (
+ None if line_endings == "platform" else "\n" if line_endings == "lf" else "\r\n"
+ )
self.dry_run = dry_run
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@@ -342,10 +352,6 @@ class InputOutput:
try:
with open(str(filename), "r", encoding=self.encoding) as f:
return f.read()
- except OSError as err:
- if not silent:
- self.tool_error(f"{filename}: unable to read: {err}")
- return
except FileNotFoundError:
if not silent:
self.tool_error(f"{filename}: file not found error")
@@ -354,6 +360,10 @@ class InputOutput:
if not silent:
self.tool_error(f"{filename}: is a directory")
return
+ except OSError as err:
+ if not silent:
+ self.tool_error(f"{filename}: unable to read: {err}")
+ return
except UnicodeError as e:
if not silent:
self.tool_error(f"{filename}: {e}")
@@ -375,7 +385,7 @@ class InputOutput:
delay = initial_delay
for attempt in range(max_retries):
try:
- with open(str(filename), "w", encoding=self.encoding) as f:
+ with open(str(filename), "w", encoding=self.encoding, newline=self.newline) as f:
f.write(content)
return # Successfully wrote the file
except PermissionError as err:
@@ -722,6 +732,7 @@ class InputOutput:
question,
style=style,
complete_while_typing=False,
+ default=default,
)
else:
res = input(question)
diff --git a/aider/main.py b/aider/main.py
index 33b23c66d..943c74d21 100644
--- a/aider/main.py
+++ b/aider/main.py
@@ -552,6 +552,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
code_theme=args.code_theme,
dry_run=args.dry_run,
encoding=args.encoding,
+ line_endings=args.line_endings,
llm_history_file=args.llm_history_file,
editingmode=editing_mode,
fancy_input=args.fancy_input,
diff --git a/aider/models.py b/aider/models.py
index 6271b9ff8..006a976b2 100644
--- a/aider/models.py
+++ b/aider/models.py
@@ -1,4 +1,5 @@
import difflib
+import importlib.resources
import json
import math
import os
@@ -76,6 +77,7 @@ MODEL_ALIASES = {
"3": "gpt-3.5-turbo",
# Other models
"deepseek": "deepseek/deepseek-chat",
+ "r1": "deepseek/deepseek-reasoner",
"flash": "gemini/gemini-2.0-flash-exp",
}
@@ -99,720 +101,15 @@ class ModelSettings:
streaming: bool = True
editor_model_name: Optional[str] = None
editor_edit_format: Optional[str] = None
+ remove_reasoning: Optional[str] = None
-# https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo
-# https://platform.openai.com/docs/models/gpt-3-5-turbo
-# https://openai.com/pricing
-
-MODEL_SETTINGS = [
- # gpt-3.5
- ModelSettings(
- "gpt-3.5-turbo",
- "whole",
- weak_model_name="gpt-4o-mini",
- reminder="sys",
- ),
- ModelSettings(
- "gpt-3.5-turbo-0125",
- "whole",
- weak_model_name="gpt-4o-mini",
- reminder="sys",
- ),
- ModelSettings(
- "gpt-3.5-turbo-1106",
- "whole",
- weak_model_name="gpt-4o-mini",
- reminder="sys",
- ),
- ModelSettings(
- "gpt-3.5-turbo-0613",
- "whole",
- weak_model_name="gpt-4o-mini",
- reminder="sys",
- ),
- ModelSettings(
- "gpt-3.5-turbo-16k-0613",
- "whole",
- weak_model_name="gpt-4o-mini",
- reminder="sys",
- ),
- # gpt-4
- ModelSettings(
- "gpt-4-turbo-2024-04-09",
- "udiff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- lazy=True,
- reminder="sys",
- ),
- ModelSettings(
- "gpt-4-turbo",
- "udiff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- lazy=True,
- reminder="sys",
- ),
- ModelSettings(
- "openai/gpt-4o",
- "diff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- lazy=True,
- reminder="sys",
- editor_edit_format="editor-diff",
- ),
- ModelSettings(
- "openai/gpt-4o-2024-08-06",
- "diff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- lazy=True,
- reminder="sys",
- ),
- ModelSettings(
- "gpt-4o-2024-08-06",
- "diff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- lazy=True,
- reminder="sys",
- ),
- ModelSettings(
- "gpt-4o-2024-11-20",
- "diff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- lazy=True,
- reminder="sys",
- ),
- ModelSettings(
- "openai/gpt-4o-2024-11-20",
- "diff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- lazy=True,
- reminder="sys",
- ),
- ModelSettings(
- "gpt-4o",
- "diff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- lazy=True,
- reminder="sys",
- editor_edit_format="editor-diff",
- ),
- ModelSettings(
- "gpt-4o-mini",
- "whole",
- weak_model_name="gpt-4o-mini",
- lazy=True,
- reminder="sys",
- ),
- ModelSettings(
- "openai/gpt-4o-mini",
- "whole",
- weak_model_name="openai/gpt-4o-mini",
- lazy=True,
- reminder="sys",
- ),
- ModelSettings(
- "gpt-4-0125-preview",
- "udiff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- lazy=True,
- reminder="sys",
- examples_as_sys_msg=True,
- ),
- ModelSettings(
- "gpt-4-1106-preview",
- "udiff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- lazy=True,
- reminder="sys",
- ),
- ModelSettings(
- "gpt-4-vision-preview",
- "diff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- reminder="sys",
- ),
- ModelSettings(
- "gpt-4-0314",
- "diff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- reminder="sys",
- examples_as_sys_msg=True,
- ),
- ModelSettings(
- "gpt-4-0613",
- "diff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- reminder="sys",
- ),
- ModelSettings(
- "gpt-4-32k-0613",
- "diff",
- weak_model_name="gpt-4o-mini",
- use_repo_map=True,
- reminder="sys",
- ),
- # Claude
- ModelSettings(
- "claude-3-opus-20240229",
- "diff",
- weak_model_name="claude-3-5-haiku-20241022",
- use_repo_map=True,
- ),
- ModelSettings(
- "openrouter/anthropic/claude-3-opus",
- "diff",
- weak_model_name="openrouter/anthropic/claude-3-5-haiku",
- use_repo_map=True,
- ),
- ModelSettings(
- "claude-3-sonnet-20240229",
- "whole",
- weak_model_name="claude-3-5-haiku-20241022",
- ),
- ModelSettings(
- "claude-3-5-sonnet-20240620",
- "diff",
- weak_model_name="claude-3-5-haiku-20241022",
- editor_model_name="claude-3-5-sonnet-20240620",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- extra_params={
- "extra_headers": {
- "anthropic-beta": ANTHROPIC_BETA_HEADER,
- },
- "max_tokens": 8192,
- },
- cache_control=True,
- reminder="user",
- ),
- ModelSettings(
- "anthropic/claude-3-5-sonnet-20240620",
- "diff",
- weak_model_name="anthropic/claude-3-5-haiku-20241022",
- editor_model_name="anthropic/claude-3-5-sonnet-20240620",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- extra_params={
- "extra_headers": {
- "anthropic-beta": ANTHROPIC_BETA_HEADER,
- },
- "max_tokens": 8192,
- },
- cache_control=True,
- reminder="user",
- ),
- ModelSettings(
- "anthropic/claude-3-5-sonnet-20241022",
- "diff",
- weak_model_name="anthropic/claude-3-5-haiku-20241022",
- editor_model_name="anthropic/claude-3-5-sonnet-20241022",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- extra_params={
- "extra_headers": {
- "anthropic-beta": ANTHROPIC_BETA_HEADER,
- },
- "max_tokens": 8192,
- },
- cache_control=True,
- reminder="user",
- ),
- ModelSettings(
- "bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0",
- "diff",
- weak_model_name="bedrock/anthropic.claude-3-5-haiku-20241022-v1:0",
- editor_model_name="bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- extra_params={
- "extra_headers": {
- "anthropic-beta": ANTHROPIC_BETA_HEADER,
- },
- "max_tokens": 8192,
- },
- cache_control=True,
- reminder="user",
- ),
- ModelSettings(
- "anthropic/claude-3-5-sonnet-latest",
- "diff",
- weak_model_name="anthropic/claude-3-5-haiku-20241022",
- editor_model_name="anthropic/claude-3-5-sonnet-20241022",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- extra_params={
- "extra_headers": {
- "anthropic-beta": ANTHROPIC_BETA_HEADER,
- },
- "max_tokens": 8192,
- },
- cache_control=True,
- reminder="user",
- ),
- ModelSettings(
- "claude-3-5-sonnet-20241022",
- "diff",
- weak_model_name="claude-3-5-haiku-20241022",
- editor_model_name="claude-3-5-sonnet-20241022",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- extra_params={
- "extra_headers": {
- "anthropic-beta": ANTHROPIC_BETA_HEADER,
- },
- "max_tokens": 8192,
- },
- cache_control=True,
- reminder="user",
- ),
- ModelSettings(
- "anthropic/claude-3-haiku-20240307",
- "whole",
- weak_model_name="anthropic/claude-3-haiku-20240307",
- examples_as_sys_msg=True,
- extra_params={
- "extra_headers": {
- "anthropic-beta": ANTHROPIC_BETA_HEADER,
- },
- },
- cache_control=True,
- ),
- ModelSettings(
- "anthropic/claude-3-5-haiku-20241022",
- "diff",
- weak_model_name="anthropic/claude-3-5-haiku-20241022",
- use_repo_map=True,
- extra_params={
- "extra_headers": {
- "anthropic-beta": ANTHROPIC_BETA_HEADER,
- },
- },
- cache_control=True,
- ),
- ModelSettings(
- "bedrock/anthropic.claude-3-5-haiku-20241022-v1:0",
- "diff",
- weak_model_name="bedrock/anthropic.claude-3-5-haiku-20241022-v1:0",
- use_repo_map=True,
- extra_params={
- "extra_headers": {
- "anthropic-beta": ANTHROPIC_BETA_HEADER,
- },
- },
- cache_control=True,
- ),
- ModelSettings(
- "claude-3-5-haiku-20241022",
- "diff",
- weak_model_name="claude-3-5-haiku-20241022",
- use_repo_map=True,
- examples_as_sys_msg=True,
- extra_params={
- "extra_headers": {
- "anthropic-beta": ANTHROPIC_BETA_HEADER,
- },
- },
- cache_control=True,
- ),
- ModelSettings(
- "vertex_ai/claude-3-5-haiku@20241022",
- "diff",
- weak_model_name="vertex_ai/claude-3-5-haiku@20241022",
- use_repo_map=True,
- extra_params={
- "max_tokens": 4096,
- },
- ),
- ModelSettings(
- "claude-3-haiku-20240307",
- "whole",
- weak_model_name="claude-3-haiku-20240307",
- examples_as_sys_msg=True,
- extra_params={
- "extra_headers": {
- "anthropic-beta": ANTHROPIC_BETA_HEADER,
- },
- },
- cache_control=True,
- ),
- ModelSettings(
- "openrouter/anthropic/claude-3.5-sonnet",
- "diff",
- weak_model_name="openrouter/anthropic/claude-3-5-haiku",
- editor_model_name="openrouter/anthropic/claude-3.5-sonnet",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- extra_params={
- "max_tokens": 8192,
- },
- reminder="user",
- cache_control=True,
- ),
- ModelSettings(
- "openrouter/anthropic/claude-3.5-sonnet:beta",
- "diff",
- weak_model_name="openrouter/anthropic/claude-3-5-haiku:beta",
- editor_model_name="openrouter/anthropic/claude-3.5-sonnet:beta",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- extra_params={
- "max_tokens": 8192,
- },
- reminder="user",
- cache_control=True,
- ),
- # Vertex AI Claude models
- # Does not yet support 8k token
- ModelSettings(
- "vertex_ai/claude-3-5-sonnet@20240620",
- "diff",
- weak_model_name="vertex_ai/claude-3-5-haiku@20241022",
- editor_model_name="vertex_ai/claude-3-5-sonnet@20240620",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- extra_params={
- "max_tokens": 8192,
- },
- reminder="user",
- ),
- ModelSettings(
- "vertex_ai/claude-3-5-sonnet-v2@20241022",
- "diff",
- weak_model_name="vertex_ai/claude-3-5-haiku@20241022",
- editor_model_name="vertex_ai/claude-3-5-sonnet-v2@20241022",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- extra_params={
- "max_tokens": 8192,
- },
- reminder="user",
- ),
- ModelSettings(
- "vertex_ai/claude-3-opus@20240229",
- "diff",
- weak_model_name="vertex_ai/claude-3-5-haiku@20241022",
- use_repo_map=True,
- ),
- ModelSettings(
- "vertex_ai/claude-3-sonnet@20240229",
- "whole",
- weak_model_name="vertex_ai/claude-3-5-haiku@20241022",
- ),
- # Cohere
- ModelSettings(
- "command-r-plus",
- "whole",
- weak_model_name="command-r-plus",
- use_repo_map=True,
- ),
- # New Cohere models
- ModelSettings(
- "command-r-08-2024",
- "whole",
- weak_model_name="command-r-08-2024",
- use_repo_map=True,
- ),
- ModelSettings(
- "command-r-plus-08-2024",
- "whole",
- weak_model_name="command-r-plus-08-2024",
- use_repo_map=True,
- ),
- # Groq llama3
- ModelSettings(
- "groq/llama3-70b-8192",
- "diff",
- weak_model_name="groq/llama3-8b-8192",
- use_repo_map=False,
- send_undo_reply=False,
- examples_as_sys_msg=True,
- ),
- # Openrouter llama3
- ModelSettings(
- "openrouter/meta-llama/llama-3-70b-instruct",
- "diff",
- weak_model_name="openrouter/meta-llama/llama-3-70b-instruct",
- use_repo_map=False,
- send_undo_reply=False,
- examples_as_sys_msg=True,
- ),
- # Gemini
- ModelSettings(
- "gemini/gemini-1.5-pro-002",
- "diff",
- use_repo_map=True,
- ),
- ModelSettings(
- "gemini/gemini-1.5-flash-002",
- "whole",
- ),
- ModelSettings(
- "gemini/gemini-1.5-pro",
- "diff-fenced",
- use_repo_map=True,
- ),
- ModelSettings(
- "gemini/gemini-1.5-pro-latest",
- "diff-fenced",
- use_repo_map=True,
- ),
- ModelSettings(
- "gemini/gemini-1.5-pro-exp-0827",
- "diff-fenced",
- use_repo_map=True,
- ),
- ModelSettings(
- "gemini/gemini-exp-1206",
- "diff",
- use_repo_map=True,
- ),
- ModelSettings(
- "gemini/gemini-exp-1114",
- "diff",
- use_repo_map=True,
- ),
- ModelSettings(
- "gemini/gemini-exp-1121",
- "diff",
- use_repo_map=True,
- ),
- ModelSettings(
- "vertex_ai/gemini-pro-experimental",
- "diff-fenced",
- use_repo_map=True,
- ),
- ModelSettings(
- "gemini/gemini-1.5-flash-exp-0827",
- "whole",
- use_repo_map=False,
- send_undo_reply=False,
- ),
- ModelSettings(
- "gemini/gemini-2.0-flash-exp",
- "diff",
- use_repo_map=True,
- send_undo_reply=False,
- ),
- ModelSettings(
- "deepseek/deepseek-chat",
- "diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- reminder="sys",
- extra_params={
- "max_tokens": 8192,
- },
- ),
- ModelSettings(
- "deepseek/deepseek-coder",
- "diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- reminder="sys",
- caches_by_default=True,
- extra_params={
- "max_tokens": 8192,
- },
- ),
- ModelSettings(
- "deepseek-chat",
- "diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- reminder="sys",
- extra_params={
- "max_tokens": 8192,
- },
- ),
- ModelSettings(
- "deepseek-coder",
- "diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- reminder="sys",
- caches_by_default=True,
- extra_params={
- "max_tokens": 8192,
- },
- ),
- ModelSettings(
- "openrouter/deepseek/deepseek-coder",
- "diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- reminder="sys",
- ),
- ModelSettings(
- "openrouter/deepseek/deepseek-chat",
- "diff",
- use_repo_map=True,
- examples_as_sys_msg=True,
- reminder="sys",
- ),
- ModelSettings(
- "openrouter/openai/gpt-4o",
- "diff",
- weak_model_name="openrouter/openai/gpt-4o-mini",
- use_repo_map=True,
- lazy=True,
- reminder="sys",
- editor_edit_format="editor-diff",
- ),
- ModelSettings(
- "openai/o1-mini",
- "whole",
- weak_model_name="openai/gpt-4o-mini",
- editor_model_name="openai/gpt-4o",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- reminder="user",
- use_system_prompt=False,
- use_temperature=False,
- ),
- ModelSettings(
- "azure/o1-mini",
- "whole",
- weak_model_name="azure/gpt-4o-mini",
- editor_model_name="azure/gpt-4o",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- reminder="user",
- use_system_prompt=False,
- use_temperature=False,
- ),
- ModelSettings(
- "o1-mini",
- "whole",
- weak_model_name="gpt-4o-mini",
- editor_model_name="gpt-4o",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- reminder="user",
- use_system_prompt=False,
- use_temperature=False,
- ),
- ModelSettings(
- "openai/o1-preview",
- "diff",
- weak_model_name="openai/gpt-4o-mini",
- editor_model_name="openai/gpt-4o",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- reminder="user",
- use_system_prompt=False,
- use_temperature=False,
- ),
- ModelSettings(
- "azure/o1-preview",
- "diff",
- weak_model_name="azure/gpt-4o-mini",
- editor_model_name="azure/gpt-4o",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- reminder="user",
- use_system_prompt=False,
- use_temperature=False,
- ),
- ModelSettings(
- "o1-preview",
- "architect",
- weak_model_name="gpt-4o-mini",
- editor_model_name="gpt-4o",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- reminder="user",
- use_system_prompt=False,
- use_temperature=False,
- ),
- ModelSettings(
- "openrouter/openai/o1-mini",
- "whole",
- weak_model_name="openrouter/openai/gpt-4o-mini",
- editor_model_name="openrouter/openai/gpt-4o",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- reminder="user",
- use_system_prompt=False,
- use_temperature=False,
- streaming=False,
- ),
- ModelSettings(
- "openrouter/openai/o1-preview",
- "diff",
- weak_model_name="openrouter/openai/gpt-4o-mini",
- editor_model_name="openrouter/openai/gpt-4o",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- reminder="user",
- use_system_prompt=False,
- use_temperature=False,
- streaming=False,
- ),
- ModelSettings(
- "openrouter/openai/o1",
- "diff",
- weak_model_name="openrouter/openai/gpt-4o-mini",
- editor_model_name="openrouter/openai/gpt-4o",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- streaming=False,
- use_temperature=False,
- # extra_params=dict(extra_body=dict(reasoning_effort="high")),
- ),
- ModelSettings(
- "openai/o1",
- "diff",
- weak_model_name="openai/gpt-4o-mini",
- editor_model_name="openai/gpt-4o",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- streaming=False,
- use_temperature=False,
- # extra_params=dict(extra_body=dict(reasoning_effort="high")),
- ),
- ModelSettings(
- "o1",
- "diff",
- weak_model_name="gpt-4o-mini",
- editor_model_name="gpt-4o",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- streaming=False,
- use_temperature=False,
- # extra_params=dict(extra_body=dict(reasoning_effort="high")),
- ),
- ModelSettings(
- "openrouter/qwen/qwen-2.5-coder-32b-instruct",
- "diff",
- weak_model_name="openrouter/qwen/qwen-2.5-coder-32b-instruct",
- editor_model_name="openrouter/qwen/qwen-2.5-coder-32b-instruct",
- editor_edit_format="editor-diff",
- use_repo_map=True,
- ),
-]
+# Load model settings from package resource
+MODEL_SETTINGS = []
+with importlib.resources.open_text("aider.resources", "model-settings.yml") as f:
+ model_settings_list = yaml.safe_load(f)
+ for model_settings_dict in model_settings_list:
+ MODEL_SETTINGS.append(ModelSettings(**model_settings_dict))
class ModelInfoManager:
@@ -1309,8 +606,8 @@ def fuzzy_match_models(name):
name = name.lower()
chat_models = set()
- for model, attrs in litellm.model_cost.items():
- model = model.lower()
+ for orig_model, attrs in litellm.model_cost.items():
+ model = orig_model.lower()
if attrs.get("mode") != "chat":
continue
provider = attrs.get("litellm_provider", "").lower()
@@ -1319,12 +616,12 @@ def fuzzy_match_models(name):
provider += "/"
if model.startswith(provider):
- fq_model = model
+ fq_model = orig_model
else:
- fq_model = provider + model
+ fq_model = provider + orig_model
chat_models.add(fq_model)
- chat_models.add(model)
+ chat_models.add(orig_model)
chat_models = sorted(chat_models)
# exactly matching model
@@ -1358,16 +655,38 @@ def print_matching_models(io, search):
def get_model_settings_as_yaml():
+ from dataclasses import fields
+
import yaml
model_settings_list = []
- for ms in MODEL_SETTINGS:
- model_settings_dict = {
- field.name: getattr(ms, field.name) for field in fields(ModelSettings)
- }
- model_settings_list.append(model_settings_dict)
+ # Add default settings first with all field values
+ defaults = {}
+ for field in fields(ModelSettings):
+ defaults[field.name] = field.default
+ defaults["name"] = "(default values)"
+ model_settings_list.append(defaults)
- return yaml.dump(model_settings_list, default_flow_style=False)
+ # Sort model settings by name
+ for ms in sorted(MODEL_SETTINGS, key=lambda x: x.name):
+ # Create dict with explicit field order
+ model_settings_dict = {}
+ for field in fields(ModelSettings):
+ value = getattr(ms, field.name)
+ if value != field.default:
+ model_settings_dict[field.name] = value
+ model_settings_list.append(model_settings_dict)
+ # Add blank line between entries
+ model_settings_list.append(None)
+
+ # Filter out None values before dumping
+ yaml_str = yaml.dump(
+ [ms for ms in model_settings_list if ms is not None],
+ default_flow_style=False,
+ sort_keys=False, # Preserve field order from dataclass
+ )
+ # Add actual blank lines between entries
+ return yaml_str.replace("\n- ", "\n\n- ")
def main():
diff --git a/aider/queries/tree-sitter-kotlin-tags.scm b/aider/queries/tree-sitter-kotlin-tags.scm
new file mode 100644
index 000000000..9770a4c0e
--- /dev/null
+++ b/aider/queries/tree-sitter-kotlin-tags.scm
@@ -0,0 +1,27 @@
+; Definitions
+
+(class_declaration
+ (type_identifier) @name.definition.class) @definition.class
+
+(function_declaration
+ (simple_identifier) @name.definition.function) @definition.function
+
+(object_declaration
+ (type_identifier) @name.definition.object) @definition.object
+
+; References
+
+(call_expression
+ [
+ (simple_identifier) @name.reference.call
+ (navigation_expression
+ (navigation_suffix
+ (simple_identifier) @name.reference.call))
+ ]) @reference.call
+
+(delegation_specifier
+ [
+ (user_type) @name.reference.type
+ (constructor_invocation
+ (user_type) @name.reference.type)
+ ]) @reference.type
diff --git a/aider/resources/model-metadata.json b/aider/resources/model-metadata.json
index 2c63c0851..a2e2812a2 100644
--- a/aider/resources/model-metadata.json
+++ b/aider/resources/model-metadata.json
@@ -1,2 +1,34 @@
{
+ "deepseek-reasoner": {
+ "max_tokens": 8192,
+ "max_input_tokens": 64000,
+ "max_output_tokens": 8192,
+ "input_cost_per_token": 0.00000055,
+ "input_cost_per_token_cache_hit": 0.00000014,
+ "cache_read_input_token_cost": 0.00000014,
+ "cache_creation_input_token_cost": 0.0,
+ "output_cost_per_token": 0.00000219,
+ "litellm_provider": "deepseek",
+ "mode": "chat",
+ //"supports_function_calling": true,
+ "supports_assistant_prefill": true,
+ //"supports_tool_choice": true,
+ "supports_prompt_caching": true
+ },
+ "openrouter/deepseek/deepseek-r1": {
+ "max_tokens": 8192,
+ "max_input_tokens": 64000,
+ "max_output_tokens": 8192,
+ "input_cost_per_token": 0.00000055,
+ "input_cost_per_token_cache_hit": 0.00000014,
+ "cache_read_input_token_cost": 0.00000014,
+ "cache_creation_input_token_cost": 0.0,
+ "output_cost_per_token": 0.00000219,
+ "litellm_provider": "openrouter",
+ "mode": "chat",
+ //"supports_function_calling": true,
+ "supports_assistant_prefill": true,
+ //"supports_tool_choice": true,
+ "supports_prompt_caching": true
+ },
}
diff --git a/aider/resources/model-settings.yml b/aider/resources/model-settings.yml
new file mode 100644
index 000000000..3607d979f
--- /dev/null
+++ b/aider/resources/model-settings.yml
@@ -0,0 +1,580 @@
+- name: gpt-3.5-turbo
+ weak_model_name: gpt-4o-mini
+ reminder: sys
+
+- name: gpt-3.5-turbo-0125
+ weak_model_name: gpt-4o-mini
+ reminder: sys
+
+- name: gpt-3.5-turbo-1106
+ weak_model_name: gpt-4o-mini
+ reminder: sys
+
+- name: gpt-3.5-turbo-0613
+ weak_model_name: gpt-4o-mini
+ reminder: sys
+
+- name: gpt-3.5-turbo-16k-0613
+ weak_model_name: gpt-4o-mini
+ reminder: sys
+
+- name: gpt-4-turbo-2024-04-09
+ edit_format: udiff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+
+- name: gpt-4-turbo
+ edit_format: udiff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+
+- name: openai/gpt-4o
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+ editor_edit_format: editor-diff
+
+- name: openai/gpt-4o-2024-08-06
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: gpt-4o-2024-08-06
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: gpt-4o-2024-11-20
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: openai/gpt-4o-2024-11-20
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: gpt-4o
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+ editor_edit_format: editor-diff
+
+- name: gpt-4o-mini
+ weak_model_name: gpt-4o-mini
+ lazy: true
+ reminder: sys
+
+- name: openai/gpt-4o-mini
+ weak_model_name: openai/gpt-4o-mini
+ lazy: true
+ reminder: sys
+
+- name: gpt-4-0125-preview
+ edit_format: udiff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: gpt-4-1106-preview
+ edit_format: udiff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+
+- name: gpt-4-vision-preview
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ reminder: sys
+
+- name: gpt-4-0314
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: gpt-4-0613
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ reminder: sys
+
+- name: gpt-4-32k-0613
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ reminder: sys
+
+- name: claude-3-opus-20240229
+ edit_format: diff
+ weak_model_name: claude-3-5-haiku-20241022
+ use_repo_map: true
+
+- name: openrouter/anthropic/claude-3-opus
+ edit_format: diff
+ weak_model_name: openrouter/anthropic/claude-3-5-haiku
+ use_repo_map: true
+
+- name: claude-3-sonnet-20240229
+ weak_model_name: claude-3-5-haiku-20241022
+
+- name: claude-3-5-sonnet-20240620
+ edit_format: diff
+ weak_model_name: claude-3-5-haiku-20241022
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: claude-3-5-sonnet-20240620
+ editor_edit_format: editor-diff
+
+- name: anthropic/claude-3-5-sonnet-20240620
+ edit_format: diff
+ weak_model_name: anthropic/claude-3-5-haiku-20241022
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: anthropic/claude-3-5-sonnet-20240620
+ editor_edit_format: editor-diff
+
+- name: anthropic/claude-3-5-sonnet-20241022
+ edit_format: diff
+ weak_model_name: anthropic/claude-3-5-haiku-20241022
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: anthropic/claude-3-5-sonnet-20241022
+ editor_edit_format: editor-diff
+
+- name: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0
+ edit_format: diff
+ weak_model_name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0
+ editor_edit_format: editor-diff
+
+- name: anthropic/claude-3-5-sonnet-latest
+ edit_format: diff
+ weak_model_name: anthropic/claude-3-5-haiku-20241022
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: anthropic/claude-3-5-sonnet-20241022
+ editor_edit_format: editor-diff
+
+- name: claude-3-5-sonnet-20241022
+ edit_format: diff
+ weak_model_name: claude-3-5-haiku-20241022
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: claude-3-5-sonnet-20241022
+ editor_edit_format: editor-diff
+
+- name: anthropic/claude-3-haiku-20240307
+ weak_model_name: anthropic/claude-3-haiku-20240307
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ cache_control: true
+
+- name: anthropic/claude-3-5-haiku-20241022
+ edit_format: diff
+ weak_model_name: anthropic/claude-3-5-haiku-20241022
+ use_repo_map: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ cache_control: true
+
+- name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0
+ edit_format: diff
+ weak_model_name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0
+ use_repo_map: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ cache_control: true
+
+- name: claude-3-5-haiku-20241022
+ edit_format: diff
+ weak_model_name: claude-3-5-haiku-20241022
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ cache_control: true
+
+- name: vertex_ai/claude-3-5-haiku@20241022
+ edit_format: diff
+ weak_model_name: vertex_ai/claude-3-5-haiku@20241022
+ use_repo_map: true
+ extra_params:
+ max_tokens: 4096
+
+- name: claude-3-haiku-20240307
+ weak_model_name: claude-3-haiku-20240307
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ cache_control: true
+
+- name: openrouter/anthropic/claude-3.5-sonnet
+ edit_format: diff
+ weak_model_name: openrouter/anthropic/claude-3-5-haiku
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: openrouter/anthropic/claude-3.5-sonnet
+ editor_edit_format: editor-diff
+
+- name: openrouter/anthropic/claude-3.5-sonnet:beta
+ edit_format: diff
+ weak_model_name: openrouter/anthropic/claude-3-5-haiku:beta
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: openrouter/anthropic/claude-3.5-sonnet:beta
+ editor_edit_format: editor-diff
+
+- name: vertex_ai/claude-3-5-sonnet@20240620
+ edit_format: diff
+ weak_model_name: vertex_ai/claude-3-5-haiku@20241022
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ editor_model_name: vertex_ai/claude-3-5-sonnet@20240620
+ editor_edit_format: editor-diff
+
+- name: vertex_ai/claude-3-5-sonnet-v2@20241022
+ edit_format: diff
+ weak_model_name: vertex_ai/claude-3-5-haiku@20241022
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ editor_model_name: vertex_ai/claude-3-5-sonnet-v2@20241022
+ editor_edit_format: editor-diff
+
+- name: vertex_ai/claude-3-opus@20240229
+ edit_format: diff
+ weak_model_name: vertex_ai/claude-3-5-haiku@20241022
+ use_repo_map: true
+
+- name: vertex_ai/claude-3-sonnet@20240229
+ weak_model_name: vertex_ai/claude-3-5-haiku@20241022
+
+- name: command-r-plus
+ weak_model_name: command-r-plus
+ use_repo_map: true
+
+- name: command-r-08-2024
+ weak_model_name: command-r-08-2024
+ use_repo_map: true
+
+- name: command-r-plus-08-2024
+ weak_model_name: command-r-plus-08-2024
+ use_repo_map: true
+
+- name: groq/llama3-70b-8192
+ edit_format: diff
+ weak_model_name: groq/llama3-8b-8192
+ examples_as_sys_msg: true
+
+- name: openrouter/meta-llama/llama-3-70b-instruct
+ edit_format: diff
+ weak_model_name: openrouter/meta-llama/llama-3-70b-instruct
+ examples_as_sys_msg: true
+
+- name: gemini/gemini-1.5-pro-002
+ edit_format: diff
+ use_repo_map: true
+
+- name: gemini/gemini-1.5-flash-002
+
+- name: gemini/gemini-1.5-pro
+ edit_format: diff-fenced
+ use_repo_map: true
+
+- name: gemini/gemini-1.5-pro-latest
+ edit_format: diff-fenced
+ use_repo_map: true
+
+- name: gemini/gemini-1.5-pro-exp-0827
+ edit_format: diff-fenced
+ use_repo_map: true
+
+- name: gemini/gemini-exp-1206
+ edit_format: diff
+ use_repo_map: true
+
+- name: gemini/gemini-exp-1114
+ edit_format: diff
+ use_repo_map: true
+
+- name: gemini/gemini-exp-1121
+ edit_format: diff
+ use_repo_map: true
+
+- name: vertex_ai/gemini-pro-experimental
+ edit_format: diff-fenced
+ use_repo_map: true
+
+- name: gemini/gemini-1.5-flash-exp-0827
+
+- name: gemini/gemini-2.0-flash-exp
+ edit_format: diff
+ use_repo_map: true
+
+- name: openrouter/deepseek/deepseek-r1
+ edit_format: diff
+ weak_model_name: openrouter/deepseek/deepseek-chat
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ caches_by_default: true
+ use_temperature: false
+ editor_model_name: openrouter/deepseek/deepseek-chat
+ editor_edit_format: editor-diff
+
+- name: deepseek/deepseek-reasoner
+ edit_format: diff
+ weak_model_name: deepseek/deepseek-chat
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ caches_by_default: true
+ use_temperature: false
+ editor_model_name: deepseek/deepseek-chat
+ editor_edit_format: editor-diff
+
+- name: deepseek/deepseek-chat
+ edit_format: diff
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ caches_by_default: true
+
+- name: deepseek/deepseek-coder
+ edit_format: diff
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ caches_by_default: true
+
+- name: deepseek-chat
+ edit_format: diff
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+
+- name: deepseek-coder
+ edit_format: diff
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ caches_by_default: true
+
+- name: openrouter/deepseek/deepseek-coder
+ edit_format: diff
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: openrouter/deepseek/deepseek-chat
+ edit_format: diff
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: openrouter/openai/gpt-4o
+ edit_format: diff
+ weak_model_name: openrouter/openai/gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+ editor_edit_format: editor-diff
+
+- name: openai/o1-mini
+ weak_model_name: openai/gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ editor_model_name: openai/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: azure/o1-mini
+ weak_model_name: azure/gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ editor_model_name: azure/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: o1-mini
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ editor_model_name: gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openai/o1-preview
+ edit_format: diff
+ weak_model_name: openai/gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ editor_model_name: openai/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: azure/o1-preview
+ edit_format: diff
+ weak_model_name: azure/gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ editor_model_name: azure/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: azure/o1
+ edit_format: diff
+ weak_model_name: azure/gpt-4o-mini
+ use_repo_map: true
+ use_temperature: false
+ streaming: false
+ editor_model_name: azure/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: o1-preview
+ edit_format: architect
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ editor_model_name: gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openrouter/openai/o1-mini
+ weak_model_name: openrouter/openai/gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ streaming: false
+ editor_model_name: openrouter/openai/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openrouter/openai/o1-preview
+ edit_format: diff
+ weak_model_name: openrouter/openai/gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ streaming: false
+ editor_model_name: openrouter/openai/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openrouter/openai/o1
+ edit_format: diff
+ weak_model_name: openrouter/openai/gpt-4o-mini
+ use_repo_map: true
+ use_temperature: false
+ streaming: false
+ editor_model_name: openrouter/openai/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openai/o1
+ edit_format: diff
+ weak_model_name: openai/gpt-4o-mini
+ use_repo_map: true
+ use_temperature: false
+ streaming: false
+ editor_model_name: openai/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: o1
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ use_temperature: false
+ streaming: false
+ editor_model_name: gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openrouter/qwen/qwen-2.5-coder-32b-instruct
+ edit_format: diff
+ weak_model_name: openrouter/qwen/qwen-2.5-coder-32b-instruct
+ use_repo_map: true
+ editor_model_name: openrouter/qwen/qwen-2.5-coder-32b-instruct
+ editor_edit_format: editor-diff
diff --git a/aider/sendchat.py b/aider/sendchat.py
index a61ac5549..6d4ef61db 100644
--- a/aider/sendchat.py
+++ b/aider/sendchat.py
@@ -1,10 +1,12 @@
import hashlib
import json
+import os
import time
from aider.dump import dump # noqa: F401
from aider.exceptions import LiteLLMExceptions
from aider.llm import litellm
+from aider.utils import format_messages
# from diskcache import Cache
@@ -16,6 +18,65 @@ CACHE = None
RETRY_TIMEOUT = 60
+def sanity_check_messages(messages):
+ """Check if messages alternate between user and assistant roles.
+ System messages can be interspersed anywhere.
+ Also verifies the last non-system message is from the user.
+ Returns True if valid, False otherwise."""
+ last_role = None
+ last_non_system_role = None
+
+ for msg in messages:
+ role = msg.get("role")
+ if role == "system":
+ continue
+
+ if last_role and role == last_role:
+ turns = format_messages(messages)
+ raise ValueError("Messages don't properly alternate user/assistant:\n\n" + turns)
+
+ last_role = role
+ last_non_system_role = role
+
+ # Ensure last non-system message is from user
+ return last_non_system_role == "user"
+
+
+def ensure_alternating_roles(messages):
+ """Ensure messages alternate between 'assistant' and 'user' roles.
+
+ Inserts empty messages of the opposite role when consecutive messages
+ of the same role are found.
+
+ Args:
+ messages: List of message dictionaries with 'role' and 'content' keys.
+
+ Returns:
+ List of messages with alternating roles.
+ """
+ if not messages:
+ return messages
+
+ fixed_messages = []
+ prev_role = None
+
+ for msg in messages:
+ current_role = msg.get("role") # Get 'role', None if missing
+
+ # If current role same as previous, insert empty message
+ # of the opposite role
+ if current_role == prev_role:
+ if current_role == "user":
+ fixed_messages.append({"role": "assistant", "content": ""})
+ else:
+ fixed_messages.append({"role": "user", "content": ""})
+
+ fixed_messages.append(msg)
+ prev_role = current_role
+
+ return fixed_messages
+
+
def send_completion(
model_name,
messages,
@@ -24,6 +85,16 @@ def send_completion(
temperature=0,
extra_params=None,
):
+ #
+ #
+ if os.environ.get("AIDER_SANITY_CHECK_TURNS"):
+ sanity_check_messages(messages)
+ #
+ #
+
+ if "deepseek-reasoner" in model_name:
+ messages = ensure_alternating_roles(messages)
+
kwargs = dict(
model=model_name,
messages=messages,
@@ -41,6 +112,7 @@ def send_completion(
kwargs.update(extra_params)
key = json.dumps(kwargs, sort_keys=True).encode()
+ # dump(kwargs)
# Generate SHA1 hash of kwargs and append it to chat_completion_call_hashes
hash_object = hashlib.sha1(key)
@@ -59,6 +131,9 @@ def send_completion(
def simple_send_with_retries(model, messages):
litellm_ex = LiteLLMExceptions()
+ if "deepseek-reasoner" in model.name:
+ messages = ensure_alternating_roles(messages)
+
retry_delay = 0.125
while True:
try:
diff --git a/aider/utils.py b/aider/utils.py
index ae850248d..322a44316 100644
--- a/aider/utils.py
+++ b/aider/utils.py
@@ -112,7 +112,7 @@ def format_messages(messages, title=None):
output.append(f"{title.upper()} {'*' * 50}")
for msg in messages:
- output.append("")
+ output.append("-------")
role = msg["role"].upper()
content = msg.get("content")
if isinstance(content, list): # Handle list content (e.g., image messages)
diff --git a/aider/website/HISTORY.md b/aider/website/HISTORY.md
index d97db8c0b..bfe49a998 100644
--- a/aider/website/HISTORY.md
+++ b/aider/website/HISTORY.md
@@ -23,13 +23,36 @@ cog.out(text)
]]]-->
+### Aider v0.72.3
+
+- Enforce user/assistant turn order to avoid R1 errors, by miradnanali.
+- Case-insensitive model name matching while preserving original case.
+- Aider wrote 67% of the code in this release.
+
+### Aider v0.72.2
+- Harden against user/assistant turn order problems which cause R1 errors.
+- Added environment variable AIDER_SANITY_CHECK_TURNS for turn order validation.
+
+### Aider v0.72.1
+- Fix model metadata for `openrouter/deepseek/deepseek-r1`
+
+### Aider v0.72.0
+- Support for DeepSeek R1.
+ - Use shortcut: `--model r1`
+ - Also via OpenRouter: `--model openrouter/deepseek/deepseek-r1`
+- Added Kotlin syntax support to repo map, by Paul Walker.
+- Added `--line-endings` for file writing, by Titusz Pan.
+- Added examples_as_sys_msg=True for GPT-4o models, improves benchmark scores.
+- Bumped all dependencies, to pick up litellm support for o1 system messages.
+- Bugfix for turn taking when reflecting lint/test errors.
+- Aider wrote 52% of the code in this release.
+
### Aider v0.71.1
- Fix permissions issue in Docker images.
-- Added read-only file announcements to chat.
+- Added read-only file announcements.
- Bugfix: ASCII fallback for unicode errors.
- Bugfix: integer indices for list slicing in repomap calculations.
-- Aider wrote 83% of the code in this release.
### Aider v0.71.0
diff --git a/aider/website/_data/blame.yml b/aider/website/_data/blame.yml
index a807dcb89..42345cf76 100644
--- a/aider/website/_data/blame.yml
+++ b/aider/website/_data/blame.yml
@@ -3545,3 +3545,145 @@
mdk: 34
start_tag: v0.69.0
total_lines: 1179
+- aider_percentage: 60.36
+ aider_total: 236
+ end_date: '2025-01-10'
+ end_tag: v0.71.0
+ file_counts:
+ aider/__init__.py:
+ Paul Gauthier: 1
+ aider/args.py:
+ Paul Gauthier: 2
+ aider/coders/base_coder.py:
+ Paul Gauthier: 7
+ Paul Gauthier (aider): 13
+ aider/commands.py:
+ Paul Gauthier: 1
+ Paul Gauthier (aider): 22
+ aider/io.py:
+ Paul Gauthier: 3
+ Paul Gauthier (aider): 16
+ aider/linter.py:
+ Aaron Weisberg: 5
+ aider/main.py:
+ Paul Gauthier: 7
+ Paul Gauthier (aider): 13
+ apaz-cli: 18
+ aider/mdstream.py:
+ Paul Gauthier: 38
+ Paul Gauthier (aider): 58
+ aider/models.py:
+ Paul Gauthier: 11
+ Paul Gauthier (aider): 2
+ aider/repo.py:
+ Krazer: 10
+ Paul Gauthier: 5
+ aider/run_cmd.py:
+ Aaron Weisberg: 2
+ aider/utils.py:
+ Paul Gauthier: 9
+ aider/voice.py:
+ Paul Gauthier: 11
+ Paul Gauthier (aider): 13
+ aider/watch.py:
+ Paul Gauthier: 1
+ benchmark/Dockerfile:
+ Josh Vera: 1
+ Paul Maunders: 12
+ benchmark/benchmark.py:
+ Nimesh Ghelani: 1
+ Paul Gauthier: 6
+ Paul Gauthier (aider): 30
+ benchmark/problem_stats.py:
+ Paul Gauthier (aider): 5
+ docker/Dockerfile:
+ Paul Gauthier (aider): 32
+ scripts/update-history.py:
+ Paul Gauthier (aider): 1
+ tests/basic/test_commands.py:
+ Paul Gauthier: 2
+ tests/basic/test_io.py:
+ Paul Gauthier (aider): 6
+ tests/basic/test_linter.py:
+ Aaron Weisberg: 2
+ tests/basic/test_models.py:
+ Paul Gauthier (aider): 25
+ grand_total:
+ Aaron Weisberg: 9
+ Josh Vera: 1
+ Krazer: 10
+ Nimesh Ghelani: 1
+ Paul Gauthier: 104
+ Paul Gauthier (aider): 236
+ Paul Maunders: 12
+ apaz-cli: 18
+ start_tag: v0.70.0
+ total_lines: 391
+- aider_percentage: 51.69
+ aider_total: 138
+ end_date: '2025-01-20'
+ end_tag: v0.72.0
+ file_counts:
+ .github/workflows/docker-build-test.yml:
+ Paul Gauthier (aider): 38
+ .github/workflows/pages.yml:
+ Paul Gauthier: 3
+ Paul Gauthier (aider): 1
+ .github/workflows/ubuntu-tests.yml:
+ Paul Gauthier (aider): 8
+ .github/workflows/windows-tests.yml:
+ Paul Gauthier (aider): 8
+ aider/__init__.py:
+ Paul Gauthier: 1
+ aider/args.py:
+ Titusz Pan: 6
+ aider/coders/base_coder.py:
+ Paul Gauthier: 11
+ aider/coders/single_wholefile_func_coder.py:
+ Paul Gauthier: 1
+ aider/coders/wholefile_func_coder.py:
+ Paul Gauthier: 1
+ aider/commands.py:
+ Paul Gauthier: 3
+ aider/history.py:
+ Paul Gauthier: 7
+ aider/io.py:
+ Paul Gauthier (aider): 14
+ Titusz Pan: 2
+ aider/main.py:
+ Titusz Pan: 1
+ aider/models.py:
+ Paul Gauthier: 16
+ aider/queries/tree-sitter-kotlin-tags.scm:
+ Paul Walker: 27
+ aider/repomap.py:
+ Paul Gauthier (aider): 2
+ aider/sendchat.py:
+ Paul Gauthier: 9
+ Paul Gauthier (aider): 22
+ aider/utils.py:
+ Paul Gauthier: 1
+ aider/website/docs/leaderboards/index.md:
+ Paul Gauthier: 2
+ benchmark/benchmark.py:
+ Paul Gauthier: 9
+ benchmark/rsync.sh:
+ Paul Gauthier: 21
+ docker/Dockerfile:
+ Paul Gauthier: 2
+ Paul Gauthier (aider): 6
+ scripts/my_models.py:
+ Paul Gauthier: 3
+ scripts/update-docs.sh:
+ Paul Gauthier: 2
+ tests/basic/test_io.py:
+ Paul Gauthier (aider): 39
+ tests/basic/test_repomap.py:
+ Paul Walker: 1
+ grand_total:
+ Paul Gauthier: 92
+ Paul Gauthier (aider): 138
+ Paul Walker: 28
+ Titusz Pan: 9
+ start_tag: v0.71.0
+ total_lines: 267
diff --git a/aider/website/_data/deepseek-down.yml b/aider/website/_data/deepseek-down.yml
new file mode 100644
index 000000000..75942a2e5
--- /dev/null
+++ b/aider/website/_data/deepseek-down.yml
@@ -0,0 +1,130 @@
+- dirname: 2024-12-25-13-31-51--deepseekv3preview-diff2
+ test_cases: 225
+ model: DeepSeek
+ edit_format: diff
+ commit_hash: 0a23c4a-dirty
+ pass_rate_1: 22.7
+ pass_rate_2: 48.4
+ pass_num_1: 51
+ pass_num_2: 109
+ percent_cases_well_formed: 98.7
+ error_outputs: 7
+ num_malformed_responses: 7
+ num_with_malformed_responses: 3
+ user_asks: 19
+ lazy_comments: 0
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 0
+ test_timeouts: 8
+ total_tests: 225
+ command: aider --model deepseek/deepseek-chat
+ date: 2024-12-25
+ versions: 0.69.2.dev
+ seconds_per_case: 34.8
+ total_cost: 0.3369
+
+
+- dirname: 2025-01-28-17-47-49--v3-fireworks
+ test_cases: 225
+ model: Fireworks
+ edit_format: diff
+ commit_hash: 0336a98-dirty
+ pass_rate_1: 22.2
+ pass_rate_2: 48.4
+ pass_num_1: 50
+ pass_num_2: 109
+ percent_cases_well_formed: 96.9
+ error_outputs: 18
+ num_malformed_responses: 16
+ num_with_malformed_responses: 7
+ user_asks: 14
+ lazy_comments: 0
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 2
+ test_timeouts: 9
+ total_tests: 225
+ command: aider --model fireworks_ai/accounts/fireworks/models/deepseek-v3
+ date: 2025-01-28
+ versions: 0.72.4.dev
+ seconds_per_case: 115.9
+ total_cost: 2.1177
+
+- dirname: 2025-01-28-19-25-32--or-v3-deepinfra-diff
+ test_cases: 222
+ model: "OpenRouter: DeepInfra"
+ edit_format: diff
+ commit_hash: bfc5745, 77d2bc5-dirty
+ pass_rate_1: 23.9
+ pass_rate_2: 48.0
+ pass_num_1: 53
+ pass_num_2: 108
+ percent_cases_well_formed: 99.5
+ error_outputs: 18
+ num_malformed_responses: 1
+ num_with_malformed_responses: 1
+ user_asks: 17
+ lazy_comments: 0
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 2
+ test_timeouts: 4
+ total_tests: 225
+ command: aider --model openrouter/deepseek/deepseek-chat
+ date: 2025-01-28
+ versions: 0.72.4.dev
+ seconds_per_case: 187.0
+ total_cost: 0.2733
+
+- dirname: 2025-01-28-21-07-23--or-v3-novita-diff
+ test_cases: 225
+ model: "OpenRouter: Novita"
+ edit_format: diff
+ commit_hash: 66025a0
+ pass_rate_1: 20.4
+ pass_rate_2: 42.7
+ pass_num_1: 46
+ pass_num_2: 96
+ percent_cases_well_formed: 84.0
+ error_outputs: 265
+ num_malformed_responses: 67
+ num_with_malformed_responses: 36
+ user_asks: 5
+ lazy_comments: 0
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 0
+ test_timeouts: 8
+ total_tests: 225
+ command: aider --model openrouter/deepseek/deepseek-chat
+ date: 2025-01-28
+ versions: 0.72.4.dev
+ seconds_per_case: 472.5
+ total_cost: 0.0000
+
+- dirname: 2025-01-29-00-36-49--v3-hyperolic-diff
+ test_cases: 224
+ model: Hyperbolic
+ edit_format: diff
+ commit_hash: 298f713
+ pass_rate_1: 20.5
+ pass_rate_2: 48.4
+ pass_num_1: 46
+ pass_num_2: 109
+ percent_cases_well_formed: 97.3
+ error_outputs: 29
+ num_malformed_responses: 6
+ num_with_malformed_responses: 6
+ user_asks: 7
+ lazy_comments: 0
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 0
+ test_timeouts: 7
+ total_tests: 225
+ command: OPENAI_API_BASE=https://api.hyperbolic.xyz/v1/ aider --model openai/deepseek-ai/DeepSeek-V3
+ date: 2025-01-29
+ versions: 0.72.4.dev
+ seconds_per_case: 365.4
+ total_cost: 0.0000
\ No newline at end of file
diff --git a/aider/website/_data/polyglot_leaderboard.yml b/aider/website/_data/polyglot_leaderboard.yml
index eba1773bc..c3566e75a 100644
--- a/aider/website/_data/polyglot_leaderboard.yml
+++ b/aider/website/_data/polyglot_leaderboard.yml
@@ -24,58 +24,84 @@
seconds_per_case: 17.3
total_cost: 0.3236
-- dirname: 2024-12-21-18-44-28--polyglot-sonnet
+- dirname: 2025-01-17-19-44-33--sonnet-baseline-jan-17
test_cases: 225
model: claude-3-5-sonnet-20241022
edit_format: diff
- commit_hash: a755079-dirty
- pass_rate_1: 18.7
- pass_rate_2: 45.3
- pass_num_1: 42
- pass_num_2: 102
- percent_cases_well_formed: 100.0
- error_outputs: 1
- num_malformed_responses: 0
- num_with_malformed_responses: 0
- user_asks: 14
+ commit_hash: 6451d59
+ pass_rate_1: 22.2
+ pass_rate_2: 51.6
+ pass_num_1: 50
+ pass_num_2: 116
+ percent_cases_well_formed: 99.6
+ error_outputs: 2
+ num_malformed_responses: 1
+ num_with_malformed_responses: 1
+ user_asks: 11
lazy_comments: 0
syntax_errors: 0
indentation_errors: 0
exhausted_context_windows: 1
- test_timeouts: 12
+ test_timeouts: 8
total_tests: 225
command: aider --model claude-3-5-sonnet-20241022
- date: 2024-12-21
- versions: 0.69.2.dev
- seconds_per_case: 30.8
- total_cost: 13.4847
-
-- dirname: 2024-12-21-18-52-34--polyglot-gpt-4o-diff
+ date: 2025-01-17
+ versions: 0.71.2.dev
+ seconds_per_case: 21.4
+ total_cost: 14.4063
+
+- dirname: 2024-12-30-20-57-12--gpt-4o-2024-11-20-ex-as-sys
test_cases: 225
model: gpt-4o-2024-11-20
edit_format: diff
- commit_hash: a755079-dirty
+ commit_hash: 09ee197-dirty
pass_rate_1: 4.9
- pass_rate_2: 15.1
+ pass_rate_2: 18.2
pass_num_1: 11
- pass_num_2: 34
- percent_cases_well_formed: 96.0
+ pass_num_2: 41
+ percent_cases_well_formed: 95.1
error_outputs: 12
- num_malformed_responses: 11
- num_with_malformed_responses: 9
- user_asks: 34
+ num_malformed_responses: 12
+ num_with_malformed_responses: 11
+ user_asks: 53
lazy_comments: 0
syntax_errors: 0
indentation_errors: 0
- exhausted_context_windows: 1
- test_timeouts: 19
+ exhausted_context_windows: 0
+ test_timeouts: 12
total_tests: 225
command: aider --model gpt-4o-2024-11-20
- date: 2024-12-21
- versions: 0.69.2.dev
- seconds_per_case: 22.2
- total_cost: 7.1835
-
+ date: 2024-12-30
+ versions: 0.70.1.dev
+ seconds_per_case: 12.1
+ total_cost: 6.7351
+
+- dirname: 2024-12-30-20-44-54--gpt4o-ex-as-sys-clean-prompt
+ test_cases: 225
+ model: gpt-4o-2024-08-06
+ edit_format: diff
+ commit_hash: 09ee197-dirty
+ pass_rate_1: 4.9
+ pass_rate_2: 23.1
+ pass_num_1: 11
+ pass_num_2: 52
+ percent_cases_well_formed: 94.2
+ error_outputs: 21
+ num_malformed_responses: 21
+ num_with_malformed_responses: 13
+ user_asks: 65
+ lazy_comments: 0
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 0
+ test_timeouts: 3
+ total_tests: 225
+ command: aider --model gpt-4o-2024-08-06
+ date: 2024-12-30
+ versions: 0.70.1.dev
+ seconds_per_case: 16.0
+ total_cost: 7.0286
+
- dirname: 2024-12-21-19-23-03--polyglot-o1-hard-diff
test_cases: 224
model: o1-2024-12-17 (high)
@@ -312,7 +338,7 @@
- dirname: 2024-12-26-00-55-20--Qwen2.5-Coder-32B-Instruct
test_cases: 225
- model: openai/Qwen2.5-Coder-32B-Instruct
+ model: Qwen2.5-Coder-32B-Instruct
edit_format: whole
commit_hash: b51768b0
pass_rate_1: 4.9
@@ -336,3 +362,82 @@
seconds_per_case: 42.0
total_cost: 0.0000
+- dirname: 2025-01-13-18-17-25--codestral-whole2
+ test_cases: 225
+ model: Codestral 25.01
+ edit_format: whole
+ commit_hash: 0cba898-dirty
+ pass_rate_1: 4.0
+ pass_rate_2: 11.1
+ pass_num_1: 9
+ pass_num_2: 25
+ percent_cases_well_formed: 100.0
+ error_outputs: 0
+ num_malformed_responses: 0
+ num_with_malformed_responses: 0
+ user_asks: 47
+ lazy_comments: 0
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 0
+ test_timeouts: 4
+ total_tests: 225
+ command: aider --model mistral/codestral-latest
+ date: 2025-01-13
+ versions: 0.71.2.dev
+ seconds_per_case: 9.3
+ total_cost: 1.9834
+
+- dirname: 2025-01-20-19-11-38--ds-turns-upd-cur-msgs-fix-with-summarizer
+ test_cases: 225
+ model: DeepSeek R1
+ edit_format: diff
+ commit_hash: 5650697-dirty
+ pass_rate_1: 26.7
+ pass_rate_2: 56.9
+ pass_num_1: 60
+ pass_num_2: 128
+ percent_cases_well_formed: 96.9
+ error_outputs: 8
+ num_malformed_responses: 7
+ num_with_malformed_responses: 7
+ user_asks: 15
+ lazy_comments: 0
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 1
+ test_timeouts: 5
+ total_tests: 225
+ command: aider --model deepseek/deepseek-reasoner
+ date: 2025-01-20
+ versions: 0.71.2.dev
+ seconds_per_case: 113.7
+ total_cost: 5.4193
+
+- dirname: 2025-01-23-19-14-48--r1-architect-sonnet
+ test_cases: 225
+ model: DeepSeek R1 + claude-3-5-sonnet-20241022
+ edit_format: architect
+ commit_hash: 05a77c7
+ editor_model: claude-3-5-sonnet-20241022
+ editor_edit_format: editor-diff
+ pass_rate_1: 27.1
+ pass_rate_2: 64.0
+ pass_num_1: 61
+ pass_num_2: 144
+ percent_cases_well_formed: 100.0
+ error_outputs: 2
+ num_malformed_responses: 0
+ num_with_malformed_responses: 0
+ user_asks: 392
+ lazy_comments: 6
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 0
+ test_timeouts: 5
+ total_tests: 225
+ command: aider --architect --model r1 --editor-model sonnet
+ date: 2025-01-23
+ versions: 0.72.3.dev
+ seconds_per_case: 251.6
+ total_cost: 13.2933
diff --git a/aider/website/_data/r1_architect.yml b/aider/website/_data/r1_architect.yml
new file mode 100644
index 000000000..5467e0fc7
--- /dev/null
+++ b/aider/website/_data/r1_architect.yml
@@ -0,0 +1,138 @@
+
+
+
+- dirname: 2025-01-23-19-14-48--r1-architect-sonnet
+ test_cases: 225
+ model: R1+Sonnet
+ edit_format: architect
+ commit_hash: 05a77c7
+ editor_model: claude-3-5-sonnet-20241022
+ editor_edit_format: editor-diff
+ pass_rate_1: 27.1
+ pass_rate_2: 64.0
+ pass_num_1: 61
+ pass_num_2: 144
+ percent_cases_well_formed: 100.0
+ error_outputs: 2
+ num_malformed_responses: 0
+ num_with_malformed_responses: 0
+ user_asks: 392
+ lazy_comments: 6
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 0
+ test_timeouts: 5
+ total_tests: 225
+ command: aider --architect --model r1 --editor-model sonnet
+ date: 2025-01-23
+ versions: 0.72.3.dev
+ seconds_per_case: 251.6
+ total_cost: 13.2933
+
+- dirname: 2025-01-20-19-11-38--ds-turns-upd-cur-msgs-fix-with-summarizer
+ test_cases: 225
+ model: R1
+ edit_format: diff
+ commit_hash: 5650697-dirty
+ pass_rate_1: 26.7
+ pass_rate_2: 56.9
+ pass_num_1: 60
+ pass_num_2: 128
+ percent_cases_well_formed: 96.9
+ error_outputs: 8
+ num_malformed_responses: 7
+ num_with_malformed_responses: 7
+ user_asks: 15
+ lazy_comments: 0
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 1
+ test_timeouts: 5
+ total_tests: 225
+ command: aider --model r1
+ date: 2025-01-20
+ versions: 0.71.2.dev
+ seconds_per_case: 113.7
+ total_cost: 5.4193
+
+
+- dirname: 2024-12-21-19-23-03--polyglot-o1-hard-diff
+ test_cases: 224
+ model: o1
+ edit_format: diff
+ commit_hash: a755079-dirty
+ pass_rate_1: 23.7
+ pass_rate_2: 61.7
+ pass_num_1: 53
+ pass_num_2: 139
+ percent_cases_well_formed: 91.5
+ error_outputs: 25
+ num_malformed_responses: 24
+ num_with_malformed_responses: 19
+ user_asks: 16
+ lazy_comments: 0
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 0
+ test_timeouts: 2
+ total_tests: 225
+ command: aider --model o1
+ date: 2024-12-21
+ versions: 0.69.2.dev
+ seconds_per_case: 133.2
+ total_cost: 186.4958
+
+
+- dirname: 2024-12-25-13-31-51--deepseekv3preview-diff2
+ test_cases: 225
+ model: DeepSeek V3
+ edit_format: diff
+ commit_hash: 0a23c4a-dirty
+ pass_rate_1: 22.7
+ pass_rate_2: 48.4
+ pass_num_1: 51
+ pass_num_2: 109
+ percent_cases_well_formed: 98.7
+ error_outputs: 7
+ num_malformed_responses: 7
+ num_with_malformed_responses: 3
+ user_asks: 19
+ lazy_comments: 0
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 0
+ test_timeouts: 8
+ total_tests: 225
+ command: aider --model deepseek
+ date: 2024-12-25
+ versions: 0.69.2.dev
+ seconds_per_case: 34.8
+ total_cost: 0.3369
+
+
+
+- dirname: 2025-01-17-19-44-33--sonnet-baseline-jan-17
+ test_cases: 225
+ model: Sonnet
+ edit_format: diff
+ commit_hash: 6451d59
+ pass_rate_1: 22.2
+ pass_rate_2: 51.6
+ pass_num_1: 50
+ pass_num_2: 116
+ percent_cases_well_formed: 99.6
+ error_outputs: 2
+ num_malformed_responses: 1
+ num_with_malformed_responses: 1
+ user_asks: 11
+ lazy_comments: 0
+ syntax_errors: 0
+ indentation_errors: 0
+ exhausted_context_windows: 1
+ test_timeouts: 8
+ total_tests: 225
+ command: aider --model sonnet
+ date: 2025-01-17
+ versions: 0.71.2.dev
+ seconds_per_case: 21.4
+ total_cost: 14.4063
diff --git a/aider/website/_includes/get-started.md b/aider/website/_includes/get-started.md
index 425110d28..fe2ccd29a 100644
--- a/aider/website/_includes/get-started.md
+++ b/aider/website/_includes/get-started.md
@@ -8,9 +8,12 @@ aider-install
# Change directory into your code base
cd /to/your/project
+# Work with DeepSeek on your code
+aider --model deepseek --api-key deepseek=your-key-goes-here
+
# Work with Claude 3.5 Sonnet on your code
-aider --model sonnet --anthropic-api-key your-key-goes-here
+aider --model sonnet --api-key anthropic=your-key-goes-here
# Work with GPT-4o on your code
-aider --model gpt-4o --openai-api-key your-key-goes-here
+aider --model gpt-4o --api-key openai=your-key-goes-here
```
diff --git a/aider/website/_includes/leaderboard.js b/aider/website/_includes/leaderboard.js
index 841852a29..f43dee7f9 100644
--- a/aider/website/_includes/leaderboard.js
+++ b/aider/website/_includes/leaderboard.js
@@ -96,7 +96,7 @@ document.addEventListener('DOMContentLoaded', function () {
options: {
plugins: {
legend: {
- display: true,
+ display: {% if show_legend == false %}false{% else %}true{% endif %},
labels: {
generateLabels: function(chart) {
return [
diff --git a/aider/website/_posts/2025-01-15-uv.md b/aider/website/_posts/2025-01-15-uv.md
new file mode 100644
index 000000000..3f0d045c6
--- /dev/null
+++ b/aider/website/_posts/2025-01-15-uv.md
@@ -0,0 +1,102 @@
+---
+title: Using uv as an installer
+excerpt: Reliably packaging & distributing python CLI tools is hard. Aider uses uv in novel ways to make it easy to install the aider CLI, its dependencies and python 3.12. All in an isolated env.
+draft: false
+nav_exclude: true
+---
+{% if page.date %}
+
{{ page.date | date: "%B %d, %Y" }}
+{% endif %}
+
+# Using uv as an installer
+{: .no_toc }
+
+It's hard to reliably
+package and distribute python command line tools
+to end users.
+Users frequently encounter challenges:
+dependency version conflicts, virtual environment management,
+needing to install python or a specific version of python, etc.
+
+Aider employs [uv](https://github.com/astral-sh/uv)
+in a couple of novel ways to streamline the installation process:
+
+1. Install aider with
+`curl https://aider.chat/install.sh | sh` even if python isn't already installed.
+
+2. Users who have python 3.8+ installed can `pip install aider-install && aider-install`.
+
+Both methods use uv to **globally** install the `aider` command line program,
+with all of its dependencies in an **isolated environment**.
+They ensure that aider will run with **python 3.12**, and install that version
+if it is not already available.
+
+These uv install methods are especially helpful for aider, because it
+has a large set of very specific dependencies.
+Since not all of aider's dependencies are available on all python versions,
+it requires python 3.9-3.12.
+
+Most users don't want to worry about these details --
+they just want a quick way to install and run aider.
+
+
+## One-liners
+
+Users can install aider with a shell one-liner, without even having python previously installed:
+
+```bash
+curl -LsSf https://aider.chat/install.sh | sh
+```
+
+This installs uv, then uses it to install python 3.12,
+install the `aider` command line tool
+and update the user's shell path.
+Under the hood, it is simply a copy of
+uv's own install script `https://astral.sh/uv/install.sh`
+with [one line added](https://github.com/Aider-AI/aider/blob/4251e976b3aa52c2a3af08da4b203d4d524c8e92/aider/website/install.sh#L1181), to install aider as a tool:
+
+```
+ensure "${_install_dir}/uv" tool install --force --python python3.12 aider-chat@latest
+```
+
+
+## aider-install
+
+The aider-install python package allows quick global installation of aider
+for users who already have python 3.8+ installed.
+It simply provides the `aider-install` command line program,
+which users just need to run once.
+
+```bash
+pip install aider-install
+aider-install
+```
+
+The `pip install aider-install` installs only two packages:
+aider-install and the [uv python package](https://pypi.org/project/uv/).
+This ensures that uv is available
+in the user's environment.
+Everything else is installed in a stand-alone environment created by uv.
+
+When the user runs `aider-install`, it runs uv
+to install aider as a tool and update the user's shell path if needed:
+
+```bash
+uv tool install --force --python python3.12 aider-chat
+uv tool update-shell
+```
+
+
+## Benefits
+
+These uv install methods have been popular with users,
+providing a hassle free way to install aider and quickly get started.
+Installs are also extremely fast, much faster than pip or pipx installs
+even when uv is also installing python 3.12!
+
+There are also a number of benefits from the perspective of the tool developer/publisher.
+Since providing these install methods, far fewer users report dependency problems and
+version conflicts as compared to users who `pip install aider-chat`.
+There is also less pressure to rapidly support the newest python versions,
+since aider always installs with python 3.12.
+
diff --git a/aider/website/_posts/2025-01-24-r1-sonnet.md b/aider/website/_posts/2025-01-24-r1-sonnet.md
new file mode 100644
index 000000000..909f69c23
--- /dev/null
+++ b/aider/website/_posts/2025-01-24-r1-sonnet.md
@@ -0,0 +1,118 @@
+---
+title: R1+Sonnet set SOTA on aider's polyglot benchmark
+excerpt: R1+Sonnet has set a new SOTA on the aider polyglot benchmark. At 14X less cost compared to o1.
+highlight_image: /assets/r1-sonnet-sota.jpg
+draft: false
+nav_exclude: true
+---
+{% if page.date %}
+{{ page.date | date: "%B %d, %Y" }}
+{% endif %}
+
+# R1+Sonnet set SOTA on aider's polyglot benchmark
+{: .no_toc }
+
+
+
+Aider supports [using a pair of models for coding](https://aider.chat/2024/09/26/architect.html):
+
+- An Architect model is asked to describe how to solve the coding problem. Thinking/reasoning models often work well in this role.
+- An Editor model is given the Architect's solution and asked to produce specific code editing instructions to apply those changes to existing source files.
+
+**R1 as architect with Sonnet as editor has set a new SOTA of 64.0%** on the
+[aider polyglot benchmark](/2024/12/21/polyglot.html).
+They achieve this at **14X less cost** compared to the previous o1 SOTA result.
+
+o1 paired with Sonnet didn't produce better results than just using o1 alone.
+Using various other models as editor didn't seem to improve o1 or R1 versus their solo scores.
+This is in contrast to the first wave of thinking models like o1-preview and o1-mini,
+which improved when paired with many different editor models.
+
+o1 was set with reasoning effort high for these tests.
+
+## Try it
+
+Once you [install aider](https://aider.chat/docs/install.html),
+you can use aider, R1 and Sonnet like this:
+
+```bash
+export DEEPSEEK_API_KEY=
+export ANTHROPIC_API_KEY=
+
+aider --architect --model r1 --editor-model sonnet
+```
+
+Or if you have an [OpenRouter](https://openrouter.ai) account:
+
+```bash
+export OPENROUTER_API_KEY=
+
+aider --architect --model openrouter/deepseek/deepseek-r1 --editor-model openrouter/anthropic/claude-3.5-sonnet
+```
+
+## Thinking output
+
+There has been
+[some recent discussion](https://github.com/Aider-AI/aider/pull/2973)
+about extracting the `` tokens from R1's responses
+and feeding them to Sonnet.
+That was an interesting experiment, for sure.
+
+To be clear, the results above are *not* using R1's thinking tokens, just the normal
+final output.
+R1 is configured in aider's standard architect role with Sonnet as editor.
+The benchmark results that used the thinking tokens appear to be worse than
+the architect/editor results shared here.
+
+## Results
+
+
+
+
+ Model |
+ Percent completed correctly |
+ Percent using correct edit format |
+ Command |
+ Edit format |
+ Total Cost |
+
+
+
+ {% assign edit_sorted = site.data.r1_architect | sort: 'pass_rate_2' | reverse %}
+ {% for row in edit_sorted %}
+
+ {{ row.model }} |
+ {{ row.pass_rate_2 }}% |
+ {{ row.percent_cases_well_formed }}% |
+ {{ row.command }} |
+ {{ row.edit_format }} |
+ {% if row.total_cost == 0 %}?{% else %}${{ row.total_cost | times: 1.0 | round: 2 }}{% endif %} |
+
+ {% endfor %}
+
+
+
+
+
+
+
diff --git a/aider/website/_posts/2025-01-28-deepseek-down.md b/aider/website/_posts/2025-01-28-deepseek-down.md
new file mode 100644
index 000000000..b3145ce93
--- /dev/null
+++ b/aider/website/_posts/2025-01-28-deepseek-down.md
@@ -0,0 +1,257 @@
+---
+title: Alternative DeepSeek V3 providers
+excerpt: DeepSeek's API has been experiencing reliability issues. Here are alternative providers you can use.
+#highlight_image: /assets/deepseek-down.jpg
+draft: false
+nav_exclude: true
+---
+{% if page.date %}
+{{ page.date | date: "%B %d, %Y" }}
+{% endif %}
+
+# Alternative DeepSeek V3 providers
+{: .no_toc }
+
+
+
+DeepSeek's API has been experiencing significant reliability issues for the past 24-48+ hours, with many users reporting downtime and overload problems.
+Their [status page](https://status.deepseek.com) notes an ongoing incident.
+
+If you're affected by these issues, several alternative providers offer access to DeepSeek V3. This article compares their performance on aider's polyglot benchmark to help you choose a reliable alternative.
+
+## Providers
+{: .no_toc }
+
+* TOC
+{:toc}
+
+## OpenRouter
+
+[OpenRouter offers many DeepSeek providers](https://openrouter.ai/deepseek/deepseek-chat/providers)
+through their unified API.
+You can use aider with OpenRouter like this:
+
+```bash
+# Set your API key using environment variables
+export OPENROUTER_API_KEY=
+aider --model openrouter/deepseek/deepseek-chat
+
+# Or use the --api-key command line option
+aider --model openrouter/deepseek/deepseek-chat --api-key openrouter=
+
+# Or add it to .aider.conf.yml in your home directory or project root:
+api-key:
+ - openrouter=
+```
+
+OpenRouter automatically monitors their providers and routes requests to stable
+APIs and away from those experiencing unreliable performance.
+
+But not all providers serve the same version of open source models, and not
+all have the same privacy guarantees.
+You can control which OpenRouter providers are used to serve the model via
+[aider's model settings](https://aider.chat/docs/config/adv-model-settings.html#model-settings).
+Create a `.aider.model.settings.yml` file in your home directory or git project root with settings like this:
+
+```yaml
+- name: openrouter/deepseek/deepseek-chat
+ extra_params:
+ extra_body:
+ provider:
+ # Only use these providers, in this order
+ order: ["Novita"]
+ # Don't fall back to other providers
+ allow_fallbacks: false
+```
+
+See [OpenRouter's provider routing docs](https://openrouter.ai/docs/provider-routing) for more details.
+
+
+## Fireworks
+
+```bash
+# Set your API key using environment variables
+export FIREWORKS_API_KEY=
+aider --model fireworks_ai/accounts/fireworks/models/deepseek-chat
+
+# Or use the --api-key command line option
+aider --model fireworks_ai/accounts/fireworks/models/deepseek-chat --api-key fireworks=
+
+# Or add it to .aider.conf.yml in your home directory or project root:
+api-key:
+ - fireworks=
+```
+
+Create a `.aider.model.settings.yml` file in your home directory or git project root with settings like this:
+
+```yaml
+- name: fireworks_ai/accounts/fireworks/models/deepseek-chat
+ edit_format: diff
+ weak_model_name: null
+ use_repo_map: true
+ send_undo_reply: false
+ lazy: false
+ reminder: sys
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ cache_control: false
+ caches_by_default: true
+ use_system_prompt: true
+ use_temperature: true
+ streaming: true
+```
+
+
+## Hyperbolic
+
+You can use [Hyperbolic's API](https://hyperbolic.xyz) as an OpenAI-compatible provider:
+
+```bash
+# Set your API key using environment variables
+export OPENAI_API_BASE=https://api.hyperbolic.xyz/v1/
+export OPENAI_API_KEY=
+aider --model openai/deepseek-ai/DeepSeek-V3
+
+# Or use the --api-key command line option
+aider --model openai/deepseek-ai/DeepSeek-V3 --api-key openai=
+
+# Or add it to .aider.conf.yml in your home directory or project root:
+api-key:
+ - openai=
+```
+
+Create a `.aider.model.settings.yml` file in your home directory or git project root with settings like this:
+
+```yaml
+- name: openai/deepseek-ai/DeepSeek-V3
+ edit_format: diff
+ weak_model_name: null
+ use_repo_map: true
+ send_undo_reply: false
+ lazy: false
+ reminder: sys
+ examples_as_sys_msg: true
+ cache_control: false
+ caches_by_default: true
+ use_system_prompt: true
+ use_temperature: true
+ streaming: true
+ editor_model_name: null
+ editor_edit_format: null
+ extra_params:
+ max_tokens: 65536
+```
+
+## Ollama
+
+You can run [DeepSeek V3 via Ollama](https://ollama.com/library/deepseek-v3).
+
+```bash
+# Pull the model
+ollama pull deepseek-v3
+
+# Start your ollama server
+ollama serve
+
+# In another terminal window...
+export OLLAMA_API_BASE=http://127.0.0.1:11434 # Mac/Linux
+setx OLLAMA_API_BASE http://127.0.0.1:11434 # Windows, restart shell after setx
+
+aider --model ollama/deepseek-v3
+```
+
+It's important to provide model settings, especially the `num_ctx` parameter to
+set the context window.
+Ollama uses a 2k context window by default, which is very small for working with aider.
+Larger context windows will allow you to work with larger amounts of code,
+but will use memory and increase latency.
+
+Unlike most other LLM servers, Ollama does not throw an error if you submit a request that exceeds the context window. Instead, it just silently truncates the request by discarding the “oldest” messages in the chat to make it fit within the context window.
+
+So if your context window is too small, you won’t get an explicit error. The biggest symptom will be that aider says it can’t see (some of) the files you added to the chat. That’s because ollama is silently discarding them because they exceed the context window.
+
+Create a `.aider.model.settings.yml` file in your home directory or git project root with settings like this:
+
+```yaml
+- name: ollama/deepseek-v3
+ edit_format: diff
+ weak_model_name: null
+ use_repo_map: true
+ send_undo_reply: false
+ lazy: false
+ reminder: sys
+ examples_as_sys_msg: true
+ cache_control: false
+ caches_by_default: true
+ use_system_prompt: true
+ use_temperature: true
+ streaming: true
+ extra_params:
+ num_ctx: 8192 # How large a context window?
+```
+
+## Other providers
+
+You will need to properly configure aider to work with DeepSeek V3 when served
+via other providers:
+
+- Determine the `--model` name to use.
+- Provide your API key to aider.
+- Add model settings to `.aider.model.settings.yml`.
+
+
+Adapt the `.aider.model.settings.yml` shown above for Fireworks. You will need to change the `name` field to match you chosen provider's model naming scheme.
+
+See [Advanced model settings](https://aider.chat/docs/config/adv-model-settings.html#model-settings) for details about all aider model settings
+
+## Results
+
+
+
+
+
+ Model |
+ Percent completed correctly |
+ Percent using correct edit format |
+ Command |
+ Edit format |
+
+
+
+ {% assign edit_sorted = site.data.deepseek-down | sort: 'pass_rate_2' | reverse %}
+ {% for row in edit_sorted %}
+
+ {{ row.model }} |
+ {{ row.pass_rate_2 }}% |
+ {{ row.percent_cases_well_formed }}% |
+ {{ row.command }} |
+ {{ row.edit_format }} |
+
+ {% endfor %}
+
+
+
+
+
+
+
diff --git a/aider/website/assets/r1-sonnet-sota.jpg b/aider/website/assets/r1-sonnet-sota.jpg
new file mode 100644
index 000000000..aba06f40f
Binary files /dev/null and b/aider/website/assets/r1-sonnet-sota.jpg differ
diff --git a/aider/website/assets/sample-analytics.jsonl b/aider/website/assets/sample-analytics.jsonl
index 9c3fa2fe4..680024c36 100644
--- a/aider/website/assets/sample-analytics.jsonl
+++ b/aider/website/assets/sample-analytics.jsonl
@@ -1,1000 +1,1000 @@
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736438263}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736438264}
-{"event": "repo", "properties": {"num_files": 18}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736438266}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736438266}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 3838, "completion_tokens": 1843, "total_tokens": 5681, "cost": 0.0010533600000000001, "total_cost": 0.0010533600000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736438311}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440041}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440043}
-{"event": "repo", "properties": {"num_files": 18}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440045}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440045}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 5367, "completion_tokens": 846, "total_tokens": 6213, "cost": 0.0009882600000000001, "total_cost": 0.0009882600000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440068}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440073}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440075}
-{"event": "repo", "properties": {"num_files": 18}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440077}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440077}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 3876, "completion_tokens": 750, "total_tokens": 4626, "cost": 0.0007526400000000001, "total_cost": 0.0007526400000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440096}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440101}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440103}
-{"event": "repo", "properties": {"num_files": 18}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440104}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440104}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4568, "completion_tokens": 4035, "total_tokens": 8603, "cost": 0.00176932, "total_cost": 0.00176932}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440364}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440371}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440374}
-{"event": "repo", "properties": {"num_files": 18}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440377}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440377}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4543, "completion_tokens": 770, "total_tokens": 5313, "cost": 0.0008516200000000001, "total_cost": 0.0008516200000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440395}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736440398}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736442977}
-{"event": "repo", "properties": {"num_files": 18}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736442979}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736442979}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736442994}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443000}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443178}
-{"event": "repo", "properties": {"num_files": 18}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443179}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443183}
-{"event": "command_reset", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443184}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443187}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443193}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 5349, "completion_tokens": 1052, "total_tokens": 6401, "cost": 0.0010434200000000002, "total_cost": 0.0010434200000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443218}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443227}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443236}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443255}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443256}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 20028, "completion_tokens": 535, "total_tokens": 20563, "cost": 0.00295372, "total_cost": 0.00399714}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443274}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443285}
-{"event": "repo", "properties": {"num_files": 19}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443287}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443287}
-{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443289}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 3244, "completion_tokens": 748, "total_tokens": 3992, "cost": 0.0006636000000000001, "total_cost": 0.0006636000000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443304}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443306}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443308}
-{"event": "repo", "properties": {"num_files": 19}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443309}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443309}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 3201, "completion_tokens": 619, "total_tokens": 3820, "cost": 0.00062146, "total_cost": 0.00062146}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443324}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443564}
-{"event": "command_reset", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443777}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443787}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443806}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443806}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "ask", "prompt_tokens": 6361, "completion_tokens": 567, "total_tokens": 6928, "cost": 0.0010493000000000002, "total_cost": 0.00504644}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443821}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443945}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443945}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "ask", "prompt_tokens": 6952, "completion_tokens": 539, "total_tokens": 7491, "cost": 0.0011242000000000001, "total_cost": 0.00617064}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736443959}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736444381}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736444385}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 5677, "completion_tokens": 181, "total_tokens": 5858, "cost": 0.00084546, "total_cost": 0.0070161}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736444391}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736444393}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 6029, "completion_tokens": 195, "total_tokens": 6224, "cost": 0.0008986600000000001, "total_cost": 0.00791476}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736444400}
-{"event": "command_reset", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736444404}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736445473}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736445474}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736445474}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736445713}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736445743}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 8739, "completion_tokens": 319, "total_tokens": 9058, "cost": 0.00131278, "total_cost": 0.00922754}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736445752}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736445792}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 9183, "completion_tokens": 266, "total_tokens": 9449, "cost": 0.0013601000000000002, "total_cost": 0.010587639999999999}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736445800}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736447092}
-{"event": "repo", "properties": {"num_files": 61}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736447094}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736447094}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 3329, "completion_tokens": 58, "total_tokens": 3387, "cost": 0.0004823, "total_cost": 0.0004823}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736447098}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736447098}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736447364}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448117}
-{"event": "repo", "properties": {"num_files": 21}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448119}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448119}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 3502, "completion_tokens": 326, "total_tokens": 3828, "cost": 0.0005815600000000001, "total_cost": 0.0005815600000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448127}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448150}
-{"event": "repo", "properties": {"num_files": 21}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448152}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448152}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 3510, "completion_tokens": 161, "total_tokens": 3671, "cost": 0.00053648, "total_cost": 0.00053648}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448157}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448160}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448162}
-{"event": "repo", "properties": {"num_files": 21}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448164}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448164}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4303, "completion_tokens": 216, "total_tokens": 4519, "cost": 0.0006629, "total_cost": 0.0006629}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448171}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448172}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448173}
-{"event": "repo", "properties": {"num_files": 21}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448175}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448175}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 3505, "completion_tokens": 75, "total_tokens": 3580, "cost": 0.0005117, "total_cost": 0.0005117}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448179}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448179}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448181}
-{"event": "repo", "properties": {"num_files": 21}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448182}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448183}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4166, "completion_tokens": 225, "total_tokens": 4391, "cost": 0.0006462400000000001, "total_cost": 0.0006462400000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448190}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448192}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448194}
-{"event": "repo", "properties": {"num_files": 21}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448196}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448196}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4141, "completion_tokens": 121, "total_tokens": 4262, "cost": 0.00061362, "total_cost": 0.00061362}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448200}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448201}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448202}
-{"event": "repo", "properties": {"num_files": 21}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448204}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448204}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 5753, "completion_tokens": 238, "total_tokens": 5991, "cost": 0.00087206, "total_cost": 0.00087206}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448212}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448214}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448216}
-{"event": "repo", "properties": {"num_files": 21}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448217}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448218}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4268, "completion_tokens": 185, "total_tokens": 4453, "cost": 0.00064932, "total_cost": 0.00064932}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448223}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448228}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448230}
-{"event": "repo", "properties": {"num_files": 21}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448232}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448232}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 5162, "completion_tokens": 306, "total_tokens": 5468, "cost": 0.00080836, "total_cost": 0.00080836}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448240}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448247}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448249}
-{"event": "repo", "properties": {"num_files": 21}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448250}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448251}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4839, "completion_tokens": 344, "total_tokens": 5183, "cost": 0.0007737800000000001, "total_cost": 0.0007737800000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448260}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736448263}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449570}
-{"event": "repo", "properties": {"num_files": 22}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449572}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449572}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449590}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449590}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449590}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 6071, "completion_tokens": 631, "total_tokens": 6702, "cost": 0.0010266200000000002, "total_cost": 0.0010266200000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449606}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449754}
-{"event": "repo", "properties": {"num_files": 22}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449756}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449756}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449759}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449775}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 8618, "completion_tokens": 185, "total_tokens": 8803, "cost": 0.00125832, "total_cost": 0.00125832}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449782}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449787}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449887}
-{"event": "repo", "properties": {"num_files": 22}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449888}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449888}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449901}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449909}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449909}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "ask", "prompt_tokens": 6477, "completion_tokens": 187, "total_tokens": 6664, "cost": 0.00095914, "total_cost": 0.00095914}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736449915}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450000}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450000}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450636}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450636}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450703}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450705}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450705}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450715}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450715}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 1979, "completion_tokens": 778, "total_tokens": 2757, "cost": 0.0004949, "total_cost": 0.0004949}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450733}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450736}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 4991, "completion_tokens": 1252, "total_tokens": 6243, "cost": 0.0010493, "total_cost": 0.0015442}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450764}
-{"event": "command_diff", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736450768}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736451421}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736451421}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736451565}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736451566}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736451566}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736451901}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736451903}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736451903}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736451910}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736451933}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736451934}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736451934}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452461}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452462}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452462}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452491}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452549}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452564}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452565}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452565}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 23399, "completion_tokens": 425, "total_tokens": 23824, "cost": 0.0033948600000000004, "total_cost": 0.0033948600000000004}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452581}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452581}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452607}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452609}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452609}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452616}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452616}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 1987, "completion_tokens": 240, "total_tokens": 2227, "cost": 0.00034538, "total_cost": 0.00034538}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452623}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452632}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 4622, "completion_tokens": 318, "total_tokens": 4940, "cost": 0.00073612, "total_cost": 0.0010815}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452641}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452656}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452657}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452657}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 23160, "completion_tokens": 490, "total_tokens": 23650, "cost": 0.0033796000000000004, "total_cost": 0.0033796000000000004}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452675}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452675}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452822}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452824}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452825}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452825}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 22997, "completion_tokens": 237, "total_tokens": 23234, "cost": 0.0032859399999980404, "total_cost": 0.0032859399999980404}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452837}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736452837}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736453047}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736453047}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736453047}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458561}
-{"event": "repo", "properties": {"num_files": 22}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458563}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458563}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458567}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458567}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458570}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 6342, "completion_tokens": 467, "total_tokens": 6809, "cost": 0.0010186400000000001, "total_cost": 0.0010186400000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458582}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458591}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458630}
-{"event": "repo", "properties": {"num_files": 22}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458632}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458632}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458633}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458633}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458633}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 6072, "completion_tokens": 414, "total_tokens": 6486, "cost": 0.0009660000000000001, "total_cost": 0.0009660000000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458645}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458681}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458681}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 6830, "completion_tokens": 176, "total_tokens": 7006, "cost": 0.00100548, "total_cost": 0.0019714800000000003}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736458686}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736459425}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736461726}
-{"event": "repo", "properties": {"num_files": 22}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736461728}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736461728}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736461739}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736461739}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736461739}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 6140, "completion_tokens": 401, "total_tokens": 6541, "cost": 0.00097188, "total_cost": 0.00097188}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736461750}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736461764}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 6727, "completion_tokens": 763, "total_tokens": 7490, "cost": 0.00115542, "total_cost": 0.0021273000000000004}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736461780}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736461781}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 8402, "completion_tokens": 422, "total_tokens": 8824, "cost": 0.00129444, "total_cost": 0.0034217400000000004}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736461792}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736463690}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736463692}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736463696}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736464010}
-{"event": "command_editor", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736464012}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736464108}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736464108}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 7604, "completion_tokens": 206, "total_tokens": 7810, "cost": 0.00112224, "total_cost": 0.00454398}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736464113}
-{"event": "command_diff", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736464269}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736464784}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736464784}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 8077, "completion_tokens": 251, "total_tokens": 8328, "cost": 0.00120106, "total_cost": 0.005745040000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736464790}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736464987}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736465010}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736465010}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "ask", "prompt_tokens": 3956, "completion_tokens": 278, "total_tokens": 4234, "cost": 0.00063168, "total_cost": 0.006376720000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736465016}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736465025}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736465025}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "ask", "prompt_tokens": 4251, "completion_tokens": 347, "total_tokens": 4598, "cost": 0.0006923000000000001, "total_cost": 0.0070690200000000005}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736465033}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736465050}
-{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736470870}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736470875}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736470950}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 6184, "completion_tokens": 800, "total_tokens": 6984, "cost": 0.00108976, "total_cost": 0.008158780000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736470968}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736471569}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 7644, "completion_tokens": 142, "total_tokens": 7786, "cost": 0.0011099200000000001, "total_cost": 0.009268700000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736471574}
-{"event": "command_editor", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736471619}
-{"event": "command_editor", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736471727}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736471761}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 7926, "completion_tokens": 553, "total_tokens": 8479, "cost": 0.0012644800000000001, "total_cost": 0.010533180000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736471774}
-{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736471824}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736471827}
-{"event": "command_editor", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736471833}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736471902}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 7149, "completion_tokens": 1656, "total_tokens": 8805, "cost": 0.00146454, "total_cost": 0.011997720000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736471929}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736472022}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 7377, "completion_tokens": 172, "total_tokens": 7549, "cost": 0.00108094, "total_cost": 0.013078660000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736472027}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736472149}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736473993}
-{"event": "repo", "properties": {"num_files": 23}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736473996}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736473996}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736473997}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736473997}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736473997}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4007, "completion_tokens": 309, "total_tokens": 4316, "cost": 0.0006475, "total_cost": 0.0006475}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474005}
-{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474267}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474273}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4380, "completion_tokens": 158, "total_tokens": 4538, "cost": 0.00065744, "total_cost": 0.00130494}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474277}
-{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474283}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474285}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474287}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4149, "completion_tokens": 107, "total_tokens": 4256, "cost": 0.00061082, "total_cost": 0.00191576}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474290}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474296}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474296}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "ask", "prompt_tokens": 1913, "completion_tokens": 392, "total_tokens": 2305, "cost": 0.00037758, "total_cost": 0.00229334}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474305}
-{"event": "command_reset", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474581}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474590}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474650}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 3821, "completion_tokens": 489, "total_tokens": 4310, "cost": 0.00067186, "total_cost": 0.0029652000000000003}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474661}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474688}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4612, "completion_tokens": 159, "total_tokens": 4771, "cost": 0.0006902000000000001, "total_cost": 0.0036554000000000005}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736474694}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736475528}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4813, "completion_tokens": 315, "total_tokens": 5128, "cost": 0.00076202, "total_cost": 0.00441742}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736475536}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736475769}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736475770}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "ask", "prompt_tokens": 3099, "completion_tokens": 415, "total_tokens": 3514, "cost": 0.00055006, "total_cost": 0.00496748}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736475780}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736475781}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 5672, "completion_tokens": 34, "total_tokens": 5706, "cost": 0.0008036, "total_cost": 0.00577108}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736475784}
-{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736475979}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736475982}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736475991}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 3744, "completion_tokens": 209, "total_tokens": 3953, "cost": 0.0005826800000000001, "total_cost": 0.00635376}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736475998}
-{"event": "command_reset", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476175}
-{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476193}
-{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476197}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476204}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476215}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 7694, "completion_tokens": 118, "total_tokens": 7812, "cost": 0.0011102, "total_cost": 0.00746396}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476220}
-{"event": "command_reset", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476378}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476383}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476410}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476410}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "ask", "prompt_tokens": 1623, "completion_tokens": 438, "total_tokens": 2061, "cost": 0.00034986, "total_cost": 0.00781382}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476421}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476466}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476466}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "ask", "prompt_tokens": 2087, "completion_tokens": 403, "total_tokens": 2490, "cost": 0.00040502, "total_cost": 0.008218840000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476476}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476482}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476799}
-{"event": "repo", "properties": {"num_files": 196}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476801}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476801}
-{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476804}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476815}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 3852, "completion_tokens": 136, "total_tokens": 3988, "cost": 0.0005773600000000001, "total_cost": 0.0005773600000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476820}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476832}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736476832}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479667}
-{"event": "repo", "properties": {"num_files": 196}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479669}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479669}
-{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479676}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479679}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479699}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 7935, "completion_tokens": 975, "total_tokens": 8910, "cost": 0.0013839000000000002, "total_cost": 0.0013839000000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479725}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479738}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 9287, "completion_tokens": 496, "total_tokens": 9783, "cost": 0.0014390600000000003, "total_cost": 0.0028229600000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479752}
-{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479778}
-{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479779}
-{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479784}
-{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479786}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479788}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479843}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 7956, "completion_tokens": 828, "total_tokens": 8784, "cost": 0.0013456800000000001, "total_cost": 0.00416864}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479864}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479884}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479898}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 9002, "completion_tokens": 491, "total_tokens": 9493, "cost": 0.00139776, "total_cost": 0.005566400000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479913}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479914}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 10090, "completion_tokens": 329, "total_tokens": 10419, "cost": 0.0015047200000000002, "total_cost": 0.007071120000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736479925}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480002}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480002}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480229}
-{"event": "repo", "properties": {"num_files": 196}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480231}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480231}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480236}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480236}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480236}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 6875, "completion_tokens": 268, "total_tokens": 7143, "cost": 0.00103754, "total_cost": 0.00103754}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480246}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480315}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480320}
-{"event": "repo", "properties": {"num_files": 196}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480322}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480327}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480904}
-{"event": "repo", "properties": {"num_files": 196}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480906}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480906}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480909}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480954}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 3777, "completion_tokens": 399, "total_tokens": 4176, "cost": 0.0006405000000000001, "total_cost": 0.0006405000000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736480965}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481059}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4276, "completion_tokens": 250, "total_tokens": 4526, "cost": 0.00066864, "total_cost": 0.00130914}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481066}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481440}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481440}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481440}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 7940, "completion_tokens": 168, "total_tokens": 8108, "cost": 0.00115864, "total_cost": 0.00246778}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481445}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481470}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481536}
-{"event": "repo", "properties": {"num_files": 196}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481539}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481539}
-{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481554}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481565}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481565}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481565}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 62215, "completion_tokens": 0, "total_tokens": 62215, "cost": 0.0087101, "total_cost": 0.0087101}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481567}
-{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481578}
-{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481581}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481588}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481588}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481598}
-{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481610}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481617}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481617}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 9383, "completion_tokens": 193, "total_tokens": 9576, "cost": 0.0013676600000000001, "total_cost": 0.01007776}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481623}
-{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481716}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481718}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481720}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481723}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4074, "completion_tokens": 323, "total_tokens": 4397, "cost": 0.0006608, "total_cost": 0.01073856}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736481731}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482181}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4540, "completion_tokens": 238, "total_tokens": 4778, "cost": 0.00070224, "total_cost": 0.0114408}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482187}
-{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482199}
-{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482204}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482206}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482207}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 3962, "completion_tokens": 241, "total_tokens": 4203, "cost": 0.015501000000000001, "total_cost": 0.026941800000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482213}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482232}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482233}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 2110, "completion_tokens": 263, "total_tokens": 2373, "cost": 0.010275, "total_cost": 0.0372168}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482238}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482255}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482255}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 2400, "completion_tokens": 187, "total_tokens": 2587, "cost": 0.010005, "total_cost": 0.0472218}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482259}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482268}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 4743, "completion_tokens": 308, "total_tokens": 5051, "cost": 0.018849, "total_cost": 0.0660708}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482274}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482509}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 5125, "completion_tokens": 165, "total_tokens": 5290, "cost": 0.01785, "total_cost": 0.0839208}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736482513}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736517456}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736517462}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736517470}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736517470}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 2082, "completion_tokens": 244, "total_tokens": 2326, "cost": 0.009906, "total_cost": 0.0938268}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736517476}
-{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736517485}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736517488}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736517496}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 3771, "completion_tokens": 144, "total_tokens": 3915, "cost": 0.013473, "total_cost": 0.1072998}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736517501}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520328}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520328}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520328}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 7240, "completion_tokens": 321, "total_tokens": 7561, "cost": 0.026535, "total_cost": 0.1338348}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520335}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520627}
-{"event": "repo", "properties": {"num_files": 197}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520629}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520633}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520766}
-{"event": "repo", "properties": {"num_files": 197}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520767}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520770}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520898}
-{"event": "repo", "properties": {"num_files": 197}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520900}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736520902}
-{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521014}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521016}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521018}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521034}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521034}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 1660, "completion_tokens": 303, "total_tokens": 1963, "cost": 0.009525, "total_cost": 0.1433598}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521041}
-{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521105}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521118}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521118}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 2385, "completion_tokens": 274, "total_tokens": 2659, "cost": 0.011265, "total_cost": 0.1546248}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521129}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521149}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 4832, "completion_tokens": 315, "total_tokens": 5147, "cost": 0.019221000000000002, "total_cost": 0.1738458}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521157}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521158}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 5441, "completion_tokens": 120, "total_tokens": 5561, "cost": 0.018123, "total_cost": 0.1919688}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521162}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521191}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521195}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521199}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 5541, "completion_tokens": 285, "total_tokens": 5826, "cost": 0.020898, "total_cost": 0.2128668}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736521205}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736536711}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736536711}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736536711}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 6429, "completion_tokens": 202, "total_tokens": 6631, "cost": 0.022317000000000004, "total_cost": 0.2351838}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736536718}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544490}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544492}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544492}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544493}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 36, "total_tokens": 2239, "cost": 0.0003185, "total_cost": 0.0003185}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544496}
-{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544499}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544500}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544538}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544540}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544541}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544541}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544543}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 2203, "completion_tokens": 36, "total_tokens": 2239, "cost": 0.0003185, "total_cost": 0.0003185}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544545}
-{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544547}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544548}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544590}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544591}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544593}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544593}
-{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544594}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544595}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544608}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544610}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544611}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544611}
-{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544612}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544615}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544622}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544624}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544624}
-{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544627}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544692}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544694}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544694}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544694}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 2347, "completion_tokens": 36, "total_tokens": 2383, "cost": 0.00033865999999804005, "total_cost": 0.00033865999999804005}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544697}
-{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544698}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544699}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544703}
-{"event": "message_send", "properties": {"main_model": "o1", "weak_model": "gpt-4o-mini", "editor_model": "gpt-4o", "edit_format": "diff", "prompt_tokens": 2409, "completion_tokens": 181, "total_tokens": 2590, "cost": 0.046995, "total_cost": 0.04733365999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544703}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544709}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544711}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544715}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544760}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544939}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544945}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544946}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544946}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544957}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 4798, "completion_tokens": 130, "total_tokens": 4928, "cost": 0.0007081199999980401, "total_cost": 0.0007081199999980401}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544963}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544969}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 24424, "completion_tokens": 466, "total_tokens": 24890, "cost": 0.0035498399999980405, "total_cost": 0.00425795999999608}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736544985}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545010}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545011}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545011}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 3597, "completion_tokens": 85, "total_tokens": 3682, "cost": 0.0005273799999980401, "total_cost": 0.0005273799999980401}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545016}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545016}
-{"event": "command_diff", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545021}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545052}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545054}
-{"event": "command_tokens", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545054}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545054}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545065}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545067}
-{"event": "command_tokens", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545067}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545067}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545090}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545092}
-{"event": "command_tokens", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545092}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545093}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545111}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545113}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545113}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545118}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545121}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545123}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545123}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 4713, "completion_tokens": 128, "total_tokens": 4841, "cost": 0.00069565999999804, "total_cost": 0.00069565999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545128}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545128}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545148}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545149}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545149}
-{"event": "command_tokens", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545154}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545156}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545156}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545166}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545167}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545167}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 4573, "completion_tokens": 136, "total_tokens": 4709, "cost": 0.00067829999999804, "total_cost": 0.00067829999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545173}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545173}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545218}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545220}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545220}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 4580, "completion_tokens": 52, "total_tokens": 4632, "cost": 0.0006557599999980401, "total_cost": 0.0006557599999980401}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545224}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736545224}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546050}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546052}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546052}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 4572, "completion_tokens": 54, "total_tokens": 4626, "cost": 0.0006551999999980401, "total_cost": 0.0006551999999980401}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546056}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546056}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546317}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546317}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546322}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546323}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546323}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546325}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546325}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546328}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546330}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546330}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546345}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546370}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546371}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546372}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546418}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546425}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546425}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546440}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546442}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546442}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546444}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 4360, "completion_tokens": 71, "total_tokens": 4431, "cost": 0.0006302799999980401, "total_cost": 0.0006302799999980401}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546449}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546463}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546467}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546467}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546508}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546510}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546510}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546518}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546557}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546557}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546560}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546562}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546562}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546565}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546595}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546595}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 8007, "completion_tokens": 308, "total_tokens": 8315, "cost": 0.0012072199999980401, "total_cost": 0.0012072199999980401}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546605}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546619}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 10363, "completion_tokens": 365, "total_tokens": 10728, "cost": 0.00155301999999804, "total_cost": 0.00276023999999608}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546631}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546639}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546641}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546641}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546647}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546664}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546668}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546668}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546670}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546672}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546682}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 11845, "completion_tokens": 300, "total_tokens": 12145, "cost": 0.00174229999999804, "total_cost": 0.00174229999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546692}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546697}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546785}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546785}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546785}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546786}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546788}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546788}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546791}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546831}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 14491, "completion_tokens": 256, "total_tokens": 14747, "cost": 0.00210041999999804, "total_cost": 0.00210041999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546842}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546853}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546856}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546857}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546857}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546858}
-{"event": "command_code", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546861}
-{"event": "command_architect", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546865}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546867}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546867}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546871}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546872}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546872}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546877}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546877}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 2155, "completion_tokens": 225, "total_tokens": 2380, "cost": 0.00036469999999804006, "total_cost": 0.00036469999999804006}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546885}
-{"event": "command_diff", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546886}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546889}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546898}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736546898}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547107}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547107}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547107}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547255}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547256}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547256}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 25808, "completion_tokens": 632, "total_tokens": 26440, "cost": 0.00379007999999804, "total_cost": 0.00379007999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547278}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547278}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547430}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547432}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547432}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547435}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 2402, "completion_tokens": 107, "total_tokens": 2509, "cost": 0.00036623999999804, "total_cost": 0.00036623999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547439}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547443}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547464}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547465}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547465}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547466}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 2437, "completion_tokens": 101, "total_tokens": 2538, "cost": 0.00036945999999804004, "total_cost": 0.00036945999999804004}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547470}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547481}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547481}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547505}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547506}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547506}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547508}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 2622, "completion_tokens": 79, "total_tokens": 2701, "cost": 0.00038919999999804, "total_cost": 0.00038919999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547511}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547520}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547520}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547546}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547547}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547547}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 2622, "completion_tokens": 74, "total_tokens": 2696, "cost": 0.00038779999999804003, "total_cost": 0.00038779999999804003}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547551}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547551}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547593}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547595}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547602}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547817}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547819}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547822}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547835}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547837}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547837}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547844}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547846}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547854}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 12535, "completion_tokens": 284, "total_tokens": 12819, "cost": 0.00183441999999804, "total_cost": 0.00183441999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547865}
-{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547885}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547890}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 13599, "completion_tokens": 195, "total_tokens": 13794, "cost": 0.00195845999999804, "total_cost": 0.00379287999999608}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547897}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547925}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547926}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547926}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547927}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547927}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547952}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547954}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547954}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547955}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547955}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547961}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547963}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547966}
-{"event": "command_reset", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547977}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736547987}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548007}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548007}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548156}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548158}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548158}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548245}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548376}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548377}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548377}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548402}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548405}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548450}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548452}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548452}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548539}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548540}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548542}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548542}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548645}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548646}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548648}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548648}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548650}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548650}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548661}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548663}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548663}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548668}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548668}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548680}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548681}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548692}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 16626, "completion_tokens": 151, "total_tokens": 16777, "cost": 0.0023699199999980404, "total_cost": 0.0023699199999980404}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548700}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548708}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548726}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548728}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548728}
-{"event": "command_reset", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548731}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548746}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 10026, "completion_tokens": 111, "total_tokens": 10137, "cost": 0.00143471999999804, "total_cost": 0.00143471999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548753}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548767}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548772}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548774}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 17794, "completion_tokens": 465, "total_tokens": 18259, "cost": 0.0026213599999980403, "total_cost": 0.0040560799999960805}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548788}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548915}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548919}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548963}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548965}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548965}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 27953, "completion_tokens": 820, "total_tokens": 28773, "cost": 0.0041430199999980405, "total_cost": 0.0041430199999980405}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548990}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736548990}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549095}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549095}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549095}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549200}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549202}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549202}
-{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549212}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549224}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 13281, "completion_tokens": 183, "total_tokens": 13464, "cost": 0.00191057999999804, "total_cost": 0.00191057999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549232}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549338}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549351}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549352}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549356}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549431}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549431}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549431}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549444}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549445}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549445}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549447}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549470}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 17467, "completion_tokens": 323, "total_tokens": 17790, "cost": 0.00253581999999804, "total_cost": 0.00253581999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549483}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549673}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549678}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549743}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549743}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736549743}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550079}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550079}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550079}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550370}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550370}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550370}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550472}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550503}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550505}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550505}
-{"event": "command_help", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550505}
-{"event": "command_help", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550511}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550512}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550512}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550548}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550548}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736550548}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736551148}
-{"event": "repo", "properties": {"num_files": 197}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736551150}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736551151}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736551156}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736551156}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736551159}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4456, "completion_tokens": 154, "total_tokens": 4610, "cost": 0.0006669600000000001, "total_cost": 0.0006669600000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736551165}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736551174}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736551177}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 6628, "completion_tokens": 235, "total_tokens": 6863, "cost": 0.00099372, "total_cost": 0.00166068}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736551184}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736551250}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736551250}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736553069}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736553071}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736553071}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736553103}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736553103}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736553103}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-coder", "weak_model": "deepseek/deepseek-coder", "editor_model": "deepseek/deepseek-coder", "edit_format": "diff", "prompt_tokens": 4553, "completion_tokens": 229, "total_tokens": 4782, "cost": 0.0007015400000000001, "total_cost": 0.0007015400000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736553110}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736553160}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736553253}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736553254}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736553254}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736606809}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736606811}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736606811}
-{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736606822}
-{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736606829}
-{"event": "command_editor", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736606852}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736606865}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736606865}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 7100, "completion_tokens": 347, "total_tokens": 7447, "cost": 0.00109115999999804, "total_cost": 0.00109115999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736606877}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736606892}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 9733, "completion_tokens": 401, "total_tokens": 10134, "cost": 0.0014748999999980399, "total_cost": 0.0025660599999960797}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736606904}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736606968}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607055}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607078}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607101}
-{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607131}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607132}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 24137, "completion_tokens": 441, "total_tokens": 24578, "cost": 0.079026, "total_cost": 0.08159205999999608}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607147}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607194}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607194}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 22430, "completion_tokens": 203, "total_tokens": 22633, "cost": 0.07033500000000001, "total_cost": 0.1519270599999961}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607202}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607220}
-{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607269}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607283}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607284}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607284}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607924}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607924}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 8733, "completion_tokens": 507, "total_tokens": 9240, "cost": 0.033804, "total_cost": 0.1857310599999961}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607934}
-{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607947}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607984}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736607984}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608142}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608146}
-{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608154}
-{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608157}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608178}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 8403, "completion_tokens": 502, "total_tokens": 8905, "cost": 0.0013169800000000001, "total_cost": 0.18704803999999609}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608191}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608222}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608223}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 6782, "completion_tokens": 733, "total_tokens": 7515, "cost": 0.0011547200000000001, "total_cost": 0.18820275999999608}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608241}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608286}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608286}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608293}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608296}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608339}
-{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608346}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608349}
-{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608354}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608359}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 8579, "completion_tokens": 620, "total_tokens": 9199, "cost": 0.035037, "total_cost": 0.22323975999999607}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608374}
-{"event": "command_diff", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608395}
-{"event": "command_diff", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608415}
-{"event": "command_diff", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608417}
-{"event": "command_diff", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608418}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608486}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608486}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 7206, "completion_tokens": 209, "total_tokens": 7415, "cost": 0.024753, "total_cost": 0.24799275999999607}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608493}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608518}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608519}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 7441, "completion_tokens": 458, "total_tokens": 7899, "cost": 0.029193, "total_cost": 0.27718575999999606}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608527}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608538}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 9586, "completion_tokens": 981, "total_tokens": 10567, "cost": 0.043473000000000005, "total_cost": 0.32065875999999605}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736608554}
-{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609259}
-{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609259}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609259}
-{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 25523, "completion_tokens": 205, "total_tokens": 25728, "cost": 0.07964399999999999, "total_cost": 0.40030275999999604}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609266}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609376}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609672}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609674}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609674}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609678}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609691}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609691}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609694}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609696}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609696}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609698}
-{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609709}
-{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609721}
-{"event": "command_editor", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609724}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609963}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609964}
-{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736609969}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736610007}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736610012}
-{"event": "message_send", "properties": {"main_model": "o1", "weak_model": "gpt-4o-mini", "editor_model": "gpt-4o", "edit_format": "ask", "prompt_tokens": 7911, "completion_tokens": 1543, "total_tokens": 9454, "cost": 0.21124500000000002, "total_cost": 0.21124500000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736610034}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736610058}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736610071}
-{"event": "message_send", "properties": {"main_model": "o1", "weak_model": "gpt-4o-mini", "editor_model": "gpt-4o", "edit_format": "ask", "prompt_tokens": 8062, "completion_tokens": 2642, "total_tokens": 10704, "cost": 0.27945, "total_cost": 0.490695}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736610110}
-{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736610225}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736610244}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 8075, "completion_tokens": 137, "total_tokens": 8212, "cost": 0.00116886, "total_cost": 0.49186386}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736610251}
-{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736610373}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638779}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638781}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638781}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638790}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 13848, "completion_tokens": 135, "total_tokens": 13983, "cost": 0.00197651999999804, "total_cost": 0.00197651999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638798}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638812}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 16203, "completion_tokens": 327, "total_tokens": 16530, "cost": 0.00235997999999804, "total_cost": 0.00433649999999608}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638822}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638842}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 16610, "completion_tokens": 246, "total_tokens": 16856, "cost": 0.00239427999999804, "total_cost": 0.00673077999999412}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638851}
-{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638865}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638870}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 19105, "completion_tokens": 873, "total_tokens": 19978, "cost": 0.0029191399999980404, "total_cost": 0.00964991999999216}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638891}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638902}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 21785, "completion_tokens": 135, "total_tokens": 21920, "cost": 0.0030876999999980407, "total_cost": 0.0127376199999902}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638911}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638930}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 22896, "completion_tokens": 1355, "total_tokens": 24251, "cost": 0.0035848399999980404, "total_cost": 0.016322459999988242}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638960}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638969}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 20971, "completion_tokens": 360, "total_tokens": 21331, "cost": 0.00303673999999804, "total_cost": 0.019359199999986282}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638980}
-{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638988}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736638991}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 22062, "completion_tokens": 654, "total_tokens": 22716, "cost": 0.0032717999999980407, "total_cost": 0.022630999999984323}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639007}
-{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639019}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639022}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 23367, "completion_tokens": 199, "total_tokens": 23566, "cost": 0.0033270999999980406, "total_cost": 0.025958099999982363}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639031}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639042}
-{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639045}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639048}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 19889, "completion_tokens": 271, "total_tokens": 20160, "cost": 0.0028603399999980405, "total_cost": 0.028818439999980402}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639059}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639070}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639072}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639072}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639074}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 9977, "completion_tokens": 36, "total_tokens": 10013, "cost": 0.00140685999999804, "total_cost": 0.00140685999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639079}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639089}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639089}
-{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639149}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639174}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 15450, "completion_tokens": 518, "total_tokens": 15968, "cost": 0.00230803999999804, "total_cost": 0.031126479999978442}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639187}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639200}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639200}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 13931, "completion_tokens": 333, "total_tokens": 14264, "cost": 0.00204357999999804, "total_cost": 0.033170059999976485}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639210}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639271}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 16501, "completion_tokens": 471, "total_tokens": 16972, "cost": 0.0024420199999980402, "total_cost": 0.035612079999974525}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639284}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639292}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639292}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639357}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639358}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639358}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639363}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639365}
-{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639365}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639375}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 15096, "completion_tokens": 103, "total_tokens": 15199, "cost": 0.00214227999999804, "total_cost": 0.00214227999999804}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639381}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639387}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 14360, "completion_tokens": 301, "total_tokens": 14661, "cost": 0.00209467999999804, "total_cost": 0.00423695999999608}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639396}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639424}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639424}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 12364, "completion_tokens": 238, "total_tokens": 12602, "cost": 0.00179759999999804, "total_cost": 0.006034559999994121}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639433}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639471}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639471}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 12621, "completion_tokens": 334, "total_tokens": 12955, "cost": 0.00186045999999804, "total_cost": 0.00789501999999216}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639481}
-{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639497}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639497}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 13008, "completion_tokens": 347, "total_tokens": 13355, "cost": 0.00191827999999804, "total_cost": 0.0098132999999902}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639507}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639526}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639526}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639588}
-{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639588}
-{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639588}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639781}
-{"event": "repo", "properties": {"num_files": 423}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639783}
-{"event": "cli session", "properties": {"main_model": "huggingface/REDACTED", "weak_model": "huggingface/REDACTED", "editor_model": "huggingface/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639783}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639784}
-{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639792}
-{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736639792}
-{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736640202}
-{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736640204}
-{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736640204}
-{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 4692, "completion_tokens": 202, "total_tokens": 4894, "cost": 0.0007134399999980401, "total_cost": 0.0007134399999980401}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736640209}
-{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1736640209}
+{"event": "cli session", "properties": {"main_model": "openai/REDACTED", "weak_model": "openai/REDACTED", "editor_model": "openai/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426453}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426454}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426486}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426486}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426495}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426497}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426497}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426498}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426601}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426603}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426603}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426604}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426814}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426816}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426816}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426887}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426889}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426889}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737426892}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737483818}
+{"event": "repo", "properties": {"num_files": 197}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737483820}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737483824}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737494990}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737494992}
+{"event": "command_tokens", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737494992}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737494993}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737495000}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737495001}
+{"event": "command_tokens", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737495001}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737495002}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565134}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565137}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565137}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565140}
+{"event": "message_send_exception", "properties": {"exception": "name 'os' is not defined"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565141}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565148}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565150}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565152}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565152}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565153}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565162}
+{"event": "message_send_exception", "properties": {"exception": "Messages don't properly alternate user/assistant:\n\n-------\nSYSTEM Act as an expert software developer.\nSYSTEM Always use best practices when coding.\nSYSTEM Respect and use existing conventions, libraries, etc that are already present in the code base.\nSYSTEM \nSYSTEM Take requests for changes to the supplied code.\nSYSTEM If the request is ambiguous, ask questions.\nSYSTEM \nSYSTEM Always reply to the user in the same language they are using.\nSYSTEM \nSYSTEM Once you understand the request you MUST:\nSYSTEM \nSYSTEM 1. Decide if you need to propose *SEARCH/REPLACE* edits to any files that haven't been added to the chat. You can create new files without asking!\nSYSTEM \nSYSTEM But if you need to propose edits to existing files not already added to the chat, you *MUST* tell the user their full path names and ask them to *add the files to the chat*.\nSYSTEM End your reply and wait for their approval.\nSYSTEM You can keep asking if you then decide you need to edit more files.\nSYSTEM \nSYSTEM 2. Think step-by-step and explain the needed changes in a few short sentences.\nSYSTEM \nSYSTEM 3. Describe each change with a *SEARCH/REPLACE block* per the examples below.\nSYSTEM \nSYSTEM All changes to files must use this *SEARCH/REPLACE block* format.\nSYSTEM ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!\nSYSTEM \nSYSTEM 4. *Concisely* suggest any shell commands the user might want to run in ```bash blocks.\nSYSTEM \nSYSTEM Just suggest shell commands this way, not example code.\nSYSTEM Only suggest complete shell commands that are ready to execute, without placeholders.\nSYSTEM Only suggest at most a few shell commands at a time, not more than 1-3, one per line.\nSYSTEM Do not suggest multi-line shell commands.\nSYSTEM All shell commands will run from the root directory of the user's project.\nSYSTEM \nSYSTEM Use the appropriate shell based on the user's system info:\nSYSTEM - Platform: macOS-15.2-x86_64-i386-64bit\nSYSTEM - Shell: SHELL=/usr/local/Cellar/bash/5.2.26/bin/bash\nSYSTEM - Language: en_US\nSYSTEM - Current date: 2025-01-22\nSYSTEM - The user is operating inside a git repository\nSYSTEM - The user's pre-commit runs these lint commands, don't suggest running them:\nSYSTEM - /Users/gauthier/Projects/aider/tmp.lint.sh\nSYSTEM \nSYSTEM Examples of when to suggest shell commands:\nSYSTEM \nSYSTEM - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.\nSYSTEM - If you changed a CLI program, suggest the command to run it to see the new behavior.\nSYSTEM - If you added a test, suggest how to run it with the testing tool used by the project.\nSYSTEM - Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.\nSYSTEM - If your code changes add new dependencies, suggest the command to install them.\nSYSTEM - Etc.\nSYSTEM \nSYSTEM \nSYSTEM # Example conversations:\nSYSTEM \nSYSTEM ## USER: Change get_factorial() to use math.factorial\nSYSTEM \nSYSTEM ## ASSISTANT: To make this change we need to modify `mathweb/flask/app.py` to:\nSYSTEM \nSYSTEM 1. Import the math package.\nSYSTEM 2. Remove the existing factorial() function.\nSYSTEM 3. Update get_factorial() to call math.factorial instead.\nSYSTEM \nSYSTEM Here are the *SEARCH/REPLACE* blocks:\nSYSTEM \nSYSTEM mathweb/flask/app.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM from flask import Flask\nSYSTEM =======\nSYSTEM import math\nSYSTEM from flask import Flask\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM mathweb/flask/app.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM def factorial(n):\nSYSTEM \"compute factorial\"\nSYSTEM \nSYSTEM if n == 0:\nSYSTEM return 1\nSYSTEM else:\nSYSTEM return n * factorial(n-1)\nSYSTEM \nSYSTEM =======\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM mathweb/flask/app.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM return str(factorial(n))\nSYSTEM =======\nSYSTEM return str(math.factorial(n))\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM \nSYSTEM ## USER: Refactor hello() into its own file.\nSYSTEM \nSYSTEM ## ASSISTANT: To make this change we need to modify `main.py` and make a new file `hello.py`:\nSYSTEM \nSYSTEM 1. Make a new hello.py file with hello() in it.\nSYSTEM 2. Remove hello() from main.py and replace it with an import.\nSYSTEM \nSYSTEM Here are the *SEARCH/REPLACE* blocks:\nSYSTEM \nSYSTEM hello.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM =======\nSYSTEM def hello():\nSYSTEM \"print a greeting\"\nSYSTEM \nSYSTEM print(\"hello\")\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM main.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM def hello():\nSYSTEM \"print a greeting\"\nSYSTEM \nSYSTEM print(\"hello\")\nSYSTEM =======\nSYSTEM from hello import hello\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM # *SEARCH/REPLACE block* Rules:\nSYSTEM \nSYSTEM Every *SEARCH/REPLACE block* must use this format:\nSYSTEM 1. The *FULL* file path alone on a line, verbatim. No bold asterisks, no quotes around it, no escaping of characters, etc.\nSYSTEM 2. The opening fence and code language, eg: ```python\nSYSTEM 3. The start of search block: <<<<<<< SEARCH\nSYSTEM 4. A contiguous chunk of lines to search for in the existing source code\nSYSTEM 5. The dividing line: =======\nSYSTEM 6. The lines to replace into the source code\nSYSTEM 7. The end of the replace block: >>>>>>> REPLACE\nSYSTEM 8. The closing fence: ```\nSYSTEM \nSYSTEM Use the *FULL* file path, as shown to you by the user.\nSYSTEM \nSYSTEM Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.\nSYSTEM 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.\nSYSTEM \nSYSTEM *SEARCH/REPLACE* blocks will *only* replace the first match occurrence.\nSYSTEM Including multiple unique *SEARCH/REPLACE* blocks if needed.\nSYSTEM Include enough lines in each SEARCH section to uniquely match each set of lines that need to change.\nSYSTEM \nSYSTEM Keep *SEARCH/REPLACE* blocks concise.\nSYSTEM Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.\nSYSTEM Include just the changing lines, and a few surrounding lines if needed for uniqueness.\nSYSTEM Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.\nSYSTEM \nSYSTEM Only create *SEARCH/REPLACE* blocks for files that the user has added to the chat!\nSYSTEM \nSYSTEM To move code within a file, use 2 *SEARCH/REPLACE* blocks: 1 to delete it from its current location, 1 to insert it in the new location.\nSYSTEM \nSYSTEM Pay attention to which filenames the user wants you to edit, especially if they are asking you to create a new file.\nSYSTEM \nSYSTEM If you want to put code in a new file, use a *SEARCH/REPLACE block* with:\nSYSTEM - A new file path, including dir name if needed\nSYSTEM - An empty `SEARCH` section\nSYSTEM - The new file's contents in the `REPLACE` section\nSYSTEM \nSYSTEM To rename files which have been added to the chat, use shell commands at the end of your response.\nSYSTEM \nSYSTEM If the user just says something like \"ok\" or \"go ahead\" or \"do that\" they probably want you to make SEARCH/REPLACE blocks for the code changes you just proposed.\nSYSTEM The user will say when they've applied your edits. If they haven't explicitly confirmed the edits have been applied, they probably want proper SEARCH/REPLACE blocks.\nSYSTEM \nSYSTEM \nSYSTEM ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!\nSYSTEM \nSYSTEM Examples of when to suggest shell commands:\nSYSTEM \nSYSTEM - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.\nSYSTEM - If you changed a CLI program, suggest the command to run it to see the new behavior.\nSYSTEM - If you added a test, suggest how to run it with the testing tool used by the project.\nSYSTEM - Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.\nSYSTEM - If your code changes add new dependencies, suggest the command to install them.\nSYSTEM - Etc.\nSYSTEM \n-------\nUSER Here are summaries of some files present in my git repository.\nUSER Do not propose changes to these files, treat them as *read-only*.\nUSER If you need to edit any of these files, ask me to *add them to the chat* first.\nUSER \nUSER aider/analytics.py:\nUSER \u22ee...\nUSER \u2502def compute_hex_threshold(percent):\nUSER \u22ee...\nUSER \u2502def is_uuid_in_percentage(uuid_str, percent):\nUSER \u22ee...\nUSER \u2502class Analytics:\nUSER \u2502 # providers\nUSER \u2502 mp = None\nUSER \u22ee...\nUSER \u2502 def disable(self, permanently):\nUSER \u22ee...\nUSER \u2502 def need_to_ask(self, args_analytics):\nUSER \u22ee...\nUSER \u2502 def get_data_file_path(self):\nUSER \u22ee...\nUSER \u2502 def get_or_create_uuid(self):\nUSER \u22ee...\nUSER \u2502 def load_data(self):\nUSER \u22ee...\nUSER \u2502 def save_data(self):\nUSER \u22ee...\nUSER \u2502 def get_system_info(self):\nUSER \u22ee...\nUSER \u2502 def event(self, event_name, main_model=None, **kwargs):\nUSER \u22ee...\nUSER \nUSER aider/args.py:\nUSER \u22ee...\nUSER \u2502def get_parser(default_config_files, git_root):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/args_formatter.py:\nUSER \u22ee...\nUSER \u2502class DotEnvFormatter(argparse.HelpFormatter):\nUSER \u2502 def start_section(self, heading):\nUSER \u2502 res = \"\\n\\n\"\nUSER \u2502 res += \"#\" * (len(heading) + 3)\nUSER \u2502 res += f\"\\n# {heading}\"\nUSER \u22ee...\nUSER \u2502 def _format_usage(self, usage, actions, groups, prefix):\nUSER \u22ee...\nUSER \u2502class YamlHelpFormatter(argparse.HelpFormatter):\nUSER \u2502 def start_section(self, heading):\nUSER \u2502 res = \"\\n\\n\"\nUSER \u2502 res += \"#\" * (len(heading) + 3)\nUSER \u2502 res += f\"\\n# {heading}\"\nUSER \u22ee...\nUSER \u2502 def _format_usage(self, usage, actions, groups, prefix):\nUSER \u22ee...\nUSER \u2502class MarkdownHelpFormatter(argparse.HelpFormatter):\nUSER \u2502 def start_section(self, heading):\nUSER \u22ee...\nUSER \u2502 def _format_usage(self, usage, actions, groups, prefix):\nUSER \u22ee...\nUSER \nUSER aider/coders/architect_prompts.py:\nUSER \u22ee...\nUSER \u2502class ArchitectPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/ask_prompts.py:\nUSER \u22ee...\nUSER \u2502class AskPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/base_coder.py:\nUSER \u22ee...\nUSER \u2502class Coder:\nUSER \u2502 abs_fnames = None\nUSER \u22ee...\nUSER \u2502 @classmethod\nUSER \u2502 def create(\nUSER \u2502 self,\nUSER \u2502 main_model=None,\nUSER \u2502 edit_format=None,\nUSER \u2502 io=None,\nUSER \u2502 from_coder=None,\nUSER \u2502 summarize_from_coder=True,\nUSER \u2502 **kwargs,\nUSER \u22ee...\nUSER \u2502 def get_announcements(self):\nUSER \u22ee...\nUSER \u2502 def show_announcements(self):\nUSER \u22ee...\nUSER \u2502 def add_rel_fname(self, rel_fname):\nUSER \u22ee...\nUSER \u2502 def drop_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def abs_root_path(self, path):\nUSER \u22ee...\nUSER \u2502 def get_repo_map(self, force_refresh=False):\nUSER \u22ee...\nUSER \u2502 def run_stream(self, user_message):\nUSER \u22ee...\nUSER \u2502 def run(self, with_message=None, preproc=True):\nUSER \u22ee...\nUSER \u2502 def fmt_system_prompt(self, prompt):\nUSER \u22ee...\nUSER \u2502 def format_messages(self):\nUSER \u22ee...\nUSER \u2502 def get_multi_response_content(self, final=False):\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def get_inchat_relative_files(self):\nUSER \u22ee...\nUSER \u2502 def get_all_relative_files(self):\nUSER \u22ee...\nUSER \u2502 def allowed_to_edit(self, path):\nUSER \u22ee...\nUSER \u2502 def check_added_files(self):\nUSER \u22ee...\nUSER \u2502 def apply_updates(self):\nUSER \u22ee...\nUSER \u2502 def parse_partial_args(self):\nUSER \u22ee...\nUSER \nUSER aider/coders/base_prompts.py:\nUSER \u2502class CoderPrompts:\nUSER \u22ee...\nUSER \nUSER aider/coders/chat_chunks.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ChatChunks:\nUSER \u2502 system: List = field(default_factory=list)\nUSER \u22ee...\nUSER \u2502 def all_messages(self):\nUSER \u22ee...\nUSER \u2502 def add_cache_control(self, messages):\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_coder.py:\nUSER \u22ee...\nUSER \u2502def do_replace(fname, content, before_text, after_text, fence=None):\nUSER \u22ee...\nUSER \u2502def find_original_update_blocks(content, fence=DEFAULT_FENCE, valid_fnames=None):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_fenced_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditBlockFencedPrompts(EditBlockPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_func_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditBlockFunctionPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditBlockPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/editor_editblock_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditorEditBlockPrompts(EditBlockPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/editor_whole_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditorWholeFilePrompts(WholeFilePrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/help_prompts.py:\nUSER \u22ee...\nUSER \u2502class HelpPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/search_replace.py:\nUSER \u22ee...\nUSER \u2502def try_strategy(texts, strategy, preproc):\nUSER \u22ee...\nUSER \u2502def read_text(fname):\nUSER \u22ee...\nUSER \u2502def main(dnames):\nUSER \u22ee...\nUSER \nUSER aider/coders/single_wholefile_func_prompts.py:\nUSER \u22ee...\nUSER \u2502class SingleWholeFileFunctionPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/udiff_coder.py:\nUSER \u22ee...\nUSER \u2502def do_replace(fname, content, hunk):\nUSER \u22ee...\nUSER \u2502def directly_apply_hunk(content, hunk):\nUSER \u22ee...\nUSER \u2502def hunk_to_before_after(hunk, lines=False):\nUSER \u22ee...\nUSER \nUSER aider/coders/wholefile_func_prompts.py:\nUSER \u22ee...\nUSER \u2502class WholeFileFunctionPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/wholefile_prompts.py:\nUSER \u22ee...\nUSER \u2502class WholeFilePrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/commands.py:\nUSER \u22ee...\nUSER \u2502class Commands:\nUSER \u2502 voice = None\nUSER \u22ee...\nUSER \u2502 def get_raw_completions(self, cmd):\nUSER \u22ee...\nUSER \u2502 def get_completions(self, cmd):\nUSER \u22ee...\nUSER \u2502 def get_commands(self):\nUSER \u22ee...\nUSER \u2502 def matching_commands(self, inp):\nUSER \u22ee...\nUSER \u2502 def run(self, inp):\nUSER \u22ee...\nUSER \u2502 def cmd_tokens(self, args):\nUSER \u2502 \"Report on the number of tokens used by the current chat context\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def fmt(v):\nUSER \u22ee...\nUSER \u2502 def cmd_undo(self, args):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/copypaste.py:\nUSER \u22ee...\nUSER \u2502class ClipboardWatcher:\nUSER \u2502 \"\"\"Watches clipboard for changes and updates IO placeholder\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def start(self):\nUSER \u22ee...\nUSER \u2502 def stop(self):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/diffs.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \u2502def diff_partial_update(lines_orig, lines_updated, final=False, fname=None):\nUSER \u22ee...\nUSER \nUSER aider/dump.py:\nUSER \u22ee...\nUSER \u2502def cvt(s):\nUSER \u22ee...\nUSER \u2502def dump(*vals):\nUSER \u22ee...\nUSER \nUSER aider/editor.py:\nUSER \u22ee...\nUSER \u2502def print_status_message(success, message, style=None):\nUSER \u22ee...\nUSER \u2502def write_temp_file(\nUSER \u2502 input_data=\"\",\nUSER \u2502 suffix=None,\nUSER \u2502 prefix=None,\nUSER \u2502 dir=None,\nUSER \u22ee...\nUSER \u2502def get_environment_editor(default=None):\nUSER \u22ee...\nUSER \u2502def discover_editor(editor_override=None):\nUSER \u22ee...\nUSER \u2502def pipe_editor(input_data=\"\", suffix=None, editor=None):\nUSER \u22ee...\nUSER \nUSER aider/exceptions.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ExInfo:\nUSER \u22ee...\nUSER \u2502class LiteLLMExceptions:\nUSER \u2502 exceptions = dict()\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def _load(self, strict=False):\nUSER \u22ee...\nUSER \u2502 def exceptions_tuple(self):\nUSER \u22ee...\nUSER \u2502 def get_ex_info(self, ex):\nUSER \u22ee...\nUSER \nUSER aider/format_settings.py:\nUSER \u2502def scrub_sensitive_info(args, text):\nUSER \u22ee...\nUSER \nUSER aider/gui.py:\nUSER \u22ee...\nUSER \u2502class CaptureIO(InputOutput):\nUSER \u2502 lines = []\nUSER \u2502\nUSER \u2502 def tool_output(self, msg, log_only=False):\nUSER \u22ee...\nUSER \u2502 def tool_error(self, msg):\nUSER \u22ee...\nUSER \u2502 def tool_warning(self, msg):\nUSER \u22ee...\nUSER \u2502 def get_captured_lines(self):\nUSER \u22ee...\nUSER \u2502def search(text=None):\nUSER \u22ee...\nUSER \u2502class State:\nUSER \u2502 keys = set()\nUSER \u2502\nUSER \u2502 def init(self, key, val=None):\nUSER \u22ee...\nUSER \u2502@st.cache_resource\nUSER \u2502def get_state():\nUSER \u22ee...\nUSER \u2502@st.cache_resource\nUSER \u2502def get_coder():\nUSER \u22ee...\nUSER \u2502class GUI:\nUSER \u2502 prompt = None\nUSER \u22ee...\nUSER \u2502 def announce(self):\nUSER \u22ee...\nUSER \u2502 def show_edit_info(self, edit):\nUSER \u22ee...\nUSER \u2502 def add_undo(self, commit_hash):\nUSER \u22ee...\nUSER \u2502 def do_sidebar(self):\nUSER \u22ee...\nUSER \u2502 def do_add_to_chat(self):\nUSER \u22ee...\nUSER \u2502 def do_add_files(self):\nUSER \u22ee...\nUSER \u2502 def do_add_web_page(self):\nUSER \u22ee...\nUSER \u2502 def do_clear_chat_history(self):\nUSER \u22ee...\nUSER \u2502 def do_recent_msgs(self):\nUSER \u22ee...\nUSER \u2502 def do_messages_container(self):\nUSER \u22ee...\nUSER \u2502 def initialize_state(self):\nUSER \u22ee...\nUSER \u2502 def button(self, args, **kwargs):\nUSER \u22ee...\nUSER \u2502 def prompt_pending(self):\nUSER \u22ee...\nUSER \u2502 def process_chat(self):\nUSER \u22ee...\nUSER \u2502 def info(self, message, echo=True):\nUSER \u22ee...\nUSER \u2502 def do_web(self):\nUSER \u22ee...\nUSER \u2502 def do_undo(self, commit_hash):\nUSER \u22ee...\nUSER \u2502def gui_main():\nUSER \u22ee...\nUSER \nUSER aider/help.py:\nUSER \u22ee...\nUSER \u2502def get_package_files():\nUSER \u22ee...\nUSER \u2502def fname_to_url(filepath):\nUSER \u22ee...\nUSER \u2502def get_index():\nUSER \u22ee...\nUSER \nUSER aider/history.py:\nUSER \u22ee...\nUSER \u2502class ChatSummary:\nUSER \u2502 def __init__(self, models=None, max_tokens=1024):\nUSER \u2502 if not models:\nUSER \u2502 raise ValueError(\"At least one model must be provided\")\nUSER \u2502 self.models = models if isinstance(models, list) else [models]\nUSER \u2502 self.max_tokens = max_tokens\nUSER \u22ee...\nUSER \u2502 def too_big(self, messages):\nUSER \u22ee...\nUSER \u2502 def tokenize(self, messages):\nUSER \u22ee...\nUSER \u2502 def summarize(self, messages, depth=0):\nUSER \u22ee...\nUSER \u2502 def summarize_real(self, messages, depth=0):\nUSER \u22ee...\nUSER \u2502 def summarize_all(self, messages):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/io.py:\nUSER \u22ee...\nUSER \u2502class AutoCompleter(Completer):\nUSER \u2502 def __init__(\nUSER \u2502 self, root, rel_fnames, addable_rel_fnames, commands, encoding, abs_read_only_fnames=None\nUSER \u22ee...\nUSER \u2502 def tokenize(self):\nUSER \u22ee...\nUSER \u2502 def get_command_completions(self, document, complete_event, text, words):\nUSER \u22ee...\nUSER \u2502 def get_completions(self, document, complete_event):\nUSER \u22ee...\nUSER \u2502class InputOutput:\nUSER \u2502 num_error_outputs = 0\nUSER \u22ee...\nUSER \u2502 def _get_style(self):\nUSER \u22ee...\nUSER \u2502 def read_image(self, filename):\nUSER \u22ee...\nUSER \u2502 def read_text(self, filename, silent=False):\nUSER \u22ee...\nUSER \u2502 def write_text(self, filename, content, max_retries=5, initial_delay=0.1):\nUSER \u22ee...\nUSER \u2502 def rule(self):\nUSER \u22ee...\nUSER \u2502 def interrupt_input(self):\nUSER \u22ee...\nUSER \u2502 def get_input(\nUSER \u2502 self,\nUSER \u2502 root,\nUSER \u2502 rel_fnames,\nUSER \u2502 addable_rel_fnames,\nUSER \u2502 commands,\nUSER \u2502 abs_read_only_fnames=None,\nUSER \u2502 edit_format=None,\nUSER \u2502 ):\nUSER \u2502 self.rule()\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def suspend_to_bg(event):\nUSER \u22ee...\nUSER \u2502 def add_to_input_history(self, inp):\nUSER \u22ee...\nUSER \u2502 def get_input_history(self):\nUSER \u22ee...\nUSER \u2502 def display_user_input(self, inp):\nUSER \u22ee...\nUSER \u2502 def user_input(self, inp, log_only=True):\nUSER \u22ee...\nUSER \u2502 def offer_url(self, url, prompt=\"Open URL for more info?\", allow_never=True):\nUSER \u22ee...\nUSER \u2502 def confirm_ask(\nUSER \u2502 self,\nUSER \u2502 question,\nUSER \u2502 default=\"y\",\nUSER \u2502 subject=None,\nUSER \u2502 explicit_yes_required=False,\nUSER \u2502 group=None,\nUSER \u2502 allow_never=False,\nUSER \u22ee...\nUSER \u2502 def tool_error(self, message=\"\", strip=True):\nUSER \u22ee...\nUSER \u2502 def tool_warning(self, message=\"\", strip=True):\nUSER \u22ee...\nUSER \u2502 def tool_output(self, *messages, log_only=False, bold=False):\nUSER \u22ee...\nUSER \u2502 def print(self, message=\"\"):\nUSER \u22ee...\nUSER \u2502 def append_chat_history(self, text, linebreak=False, blockquote=False, strip=True):\nUSER \u22ee...\nUSER \u2502 def format_files_for_input(self, rel_fnames, rel_read_only_fnames):\nUSER \u22ee...\nUSER \u2502def get_rel_fname(fname, root):\nUSER \u22ee...\nUSER \nUSER aider/linter.py:\nUSER \u22ee...\nUSER \u2502class Linter:\nUSER \u2502 def __init__(self, encoding=\"utf-8\", root=None):\nUSER \u2502 self.encoding = encoding\nUSER \u2502 self.root = root\nUSER \u2502\nUSER \u2502 self.languages = dict(\nUSER \u2502 python=self.py_lint,\nUSER \u2502 )\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def run_cmd(self, cmd, rel_fname, code):\nUSER \u22ee...\nUSER \u2502 def lint(self, fname, cmd=None):\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class LintResult:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/llm.py:\nUSER \u22ee...\nUSER \u2502class LazyLiteLLM:\nUSER \u22ee...\nUSER \nUSER aider/main.py:\nUSER \u22ee...\nUSER \u2502def sanity_check_repo(repo, io):\nUSER \u22ee...\nUSER \u2502def main(argv=None, input=None, output=None, force_git_root=None, return_coder=False):\nUSER \u22ee...\nUSER \nUSER aider/mdstream.py:\nUSER \u22ee...\nUSER \u2502class MarkdownStream:\nUSER \u2502 \"\"\"Streaming markdown renderer that progressively displays content with a live updating window.\nUSER \u2502\nUSER \u2502 Uses rich.console and rich.live to render markdown content with smooth scrolling\nUSER \u2502 and partial updates. Maintains a sliding window of visible content while streaming\nUSER \u2502 in new markdown text.\nUSER \u22ee...\nUSER \u2502 def update(self, text, final=False):\nUSER \u22ee...\nUSER \nUSER aider/models.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ModelSettings:\nUSER \u22ee...\nUSER \u2502class ModelInfoManager:\nUSER \u2502 MODEL_INFO_URL = (\nUSER \u2502 \"https://raw.githubusercontent.com/BerriAI/litellm/main/\"\nUSER \u2502 \"model_prices_and_context_window.json\"\nUSER \u22ee...\nUSER \u2502 def get_model_from_cached_json_db(self, model):\nUSER \u22ee...\nUSER \u2502 def get_model_info(self, model):\nUSER \u22ee...\nUSER \u2502class Model(ModelSettings):\nUSER \u2502 def __init__(self, model, weak_model=None, editor_model=None, editor_edit_format=None):\nUSER \u2502 # Map any alias to its canonical name\nUSER \u2502 model = MODEL_ALIASES.get(model, model)\nUSER \u2502\nUSER \u2502 self.name = model\nUSER \u2502\nUSER \u2502 self.max_chat_history_tokens = 1024\nUSER \u2502 self.weak_model = None\nUSER \u2502 self.editor_model = None\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def get_model_info(self, model):\nUSER \u22ee...\nUSER \u2502 def token_count(self, messages):\nUSER \u22ee...\nUSER \u2502 def validate_environment(self):\nUSER \u22ee...\nUSER \u2502def validate_variables(vars):\nUSER \u22ee...\nUSER \u2502def sanity_check_model(io, model):\nUSER \u22ee...\nUSER \u2502def fuzzy_match_models(name):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/repo.py:\nUSER \u22ee...\nUSER \u2502class GitRepo:\nUSER \u2502 repo = None\nUSER \u22ee...\nUSER \u2502 def commit(self, fnames=None, context=None, message=None, aider_edits=False):\nUSER \u22ee...\nUSER \u2502 def get_commit_message(self, diffs, context):\nUSER \u22ee...\nUSER \u2502 def get_diffs(self, fnames=None):\nUSER \u22ee...\nUSER \u2502 def diff_commits(self, pretty, from_commit, to_commit):\nUSER \u22ee...\nUSER \u2502 def get_tracked_files(self):\nUSER \u22ee...\nUSER \u2502 def normalize_path(self, path):\nUSER \u22ee...\nUSER \u2502 def refresh_aider_ignore(self):\nUSER \u22ee...\nUSER \u2502 def git_ignored_file(self, path):\nUSER \u22ee...\nUSER \u2502 def ignored_file(self, fname):\nUSER \u22ee...\nUSER \u2502 def ignored_file_raw(self, fname):\nUSER \u22ee...\nUSER \u2502 def path_in_repo(self, path):\nUSER \u22ee...\nUSER \u2502 def abs_root_path(self, path):\nUSER \u22ee...\nUSER \u2502 def is_dirty(self, path=None):\nUSER \u22ee...\nUSER \u2502 def get_head_commit(self):\nUSER \u22ee...\nUSER \u2502 def get_head_commit_sha(self, short=False):\nUSER \u22ee...\nUSER \nUSER aider/repomap.py:\nUSER \u22ee...\nUSER \u2502class RepoMap:\nUSER \u2502 CACHE_VERSION = 3\nUSER \u22ee...\nUSER \u2502 def token_count(self, text):\nUSER \u22ee...\nUSER \u2502 def get_repo_map(\nUSER \u2502 self,\nUSER \u2502 chat_files,\nUSER \u2502 other_files,\nUSER \u2502 mentioned_fnames=None,\nUSER \u2502 mentioned_idents=None,\nUSER \u2502 force_refresh=False,\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def tags_cache_error(self, original_error=None):\nUSER \u22ee...\nUSER \nUSER aider/report.py:\nUSER \u22ee...\nUSER \u2502def report_github_issue(issue_text, title=None, confirm=True):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/run_cmd.py:\nUSER \u22ee...\nUSER \u2502def run_cmd(command, verbose=False, error_print=None, cwd=None):\nUSER \u22ee...\nUSER \u2502def get_windows_parent_process_name():\nUSER \u22ee...\nUSER \u2502def run_cmd_subprocess(command, verbose=False, cwd=None, encoding=sys.stdout.encoding):\nUSER \u22ee...\nUSER \u2502def run_cmd_pexpect(command, verbose=False, cwd=None):\nUSER \u22ee...\nUSER \nUSER aider/scrape.py:\nUSER \u22ee...\nUSER \u2502class Scraper:\nUSER \u2502 pandoc_available = None\nUSER \u22ee...\nUSER \u2502 def scrape(self, url):\nUSER \u22ee...\nUSER \u2502def main(url):\nUSER \u22ee...\nUSER \nUSER aider/sendchat.py:\nUSER \u22ee...\nUSER \u2502def sanity_check_messages(messages):\nUSER \u22ee...\nUSER \u2502def send_completion(\nUSER \u2502 model_name,\nUSER \u2502 messages,\nUSER \u2502 functions,\nUSER \u2502 stream,\nUSER \u2502 temperature=0,\nUSER \u2502 extra_params=None,\nUSER \u22ee...\nUSER \u2502def simple_send_with_retries(model, messages):\nUSER \u22ee...\nUSER \nUSER aider/special.py:\nUSER \u22ee...\nUSER \u2502def is_important(file_path):\nUSER \u22ee...\nUSER \u2502def filter_important_files(file_paths):\nUSER \u22ee...\nUSER \nUSER aider/utils.py:\nUSER \u22ee...\nUSER \u2502class IgnorantTemporaryDirectory:\nUSER \u2502 def __init__(self):\nUSER \u2502 if sys.version_info >= (3, 10):\nUSER \u2502 self.temp_dir = tempfile.TemporaryDirectory(ignore_cleanup_errors=True)\nUSER \u2502 else:\nUSER \u22ee...\nUSER \u2502 def cleanup(self):\nUSER \u22ee...\nUSER \u2502class GitTemporaryDirectory(ChdirTemporaryDirectory):\nUSER \u22ee...\nUSER \u2502def make_repo(path=None):\nUSER \u22ee...\nUSER \u2502def is_image_file(file_name):\nUSER \u22ee...\nUSER \u2502def safe_abs_path(res):\nUSER \u22ee...\nUSER \u2502def format_content(role, content):\nUSER \u22ee...\nUSER \u2502def format_messages(messages, title=None):\nUSER \u22ee...\nUSER \u2502def split_chat_history_markdown(text, include_tool=False):\nUSER \u2502 messages = []\nUSER \u22ee...\nUSER \u2502 def append_msg(role, lines):\nUSER \u22ee...\nUSER \u2502def get_pip_install(args):\nUSER \u22ee...\nUSER \u2502def run_install(cmd):\nUSER \u22ee...\nUSER \u2502class Spinner:\nUSER \u2502 unicode_spinner = [\"\u280b\", \"\u2819\", \"\u2839\", \"\u2838\", \"\u283c\", \"\u2834\", \"\u2826\", \"\u2827\", \"\u2807\", \"\u280f\"]\nUSER \u22ee...\nUSER \u2502 def step(self):\nUSER \u22ee...\nUSER \u2502 def end(self):\nUSER \u22ee...\nUSER \u2502def check_pip_install_extra(io, module, prompt, pip_install_cmd, self_update=False):\nUSER \u22ee...\nUSER \u2502def printable_shell_command(cmd_list):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/voice.py:\nUSER \u22ee...\nUSER \u2502class SoundDeviceError(Exception):\nUSER \u22ee...\nUSER \u2502class Voice:\nUSER \u2502 max_rms = 0\nUSER \u22ee...\nUSER \u2502 def record_and_transcribe(self, history=None, language=None):\nUSER \u22ee...\nUSER \u2502 def raw_record_and_transcribe(self, history, language):\nUSER \u22ee...\nUSER \nUSER aider/watch.py:\nUSER \u22ee...\nUSER \u2502def load_gitignores(gitignore_paths: list[Path]) -> Optional[PathSpec]:\nUSER \u22ee...\nUSER \u2502class FileWatcher:\nUSER \u2502 \"\"\"Watches source files for changes and AI comments\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def start(self):\nUSER \u22ee...\nUSER \u2502 def stop(self):\nUSER \u22ee...\nUSER \u2502 def process_changes(self):\nUSER \u22ee...\nUSER \u2502 def get_ai_comments(self, filepath):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/code-in-json-benchmark.js:\nUSER \u22ee...\nUSER \u2502 function getAspectRatio() {\nUSER \u2502 var width = chartContainer.offsetWidth;\nUSER \u2502 // Gradually change aspect ratio from 2 (landscape) to 1 (square)\nUSER \u2502 return Math.max(1, Math.min(2, width / 300));\nUSER \u22ee...\nUSER \u2502 function resizeChart() {\nUSER \u2502 chart.options.aspectRatio = getAspectRatio();\nUSER \u2502 chart.resize();\nUSER \u22ee...\nUSER \u2502function createStripedCanvas(isStrict) {\nUSER \u2502 const patternCanvas = document.createElement('canvas');\nUSER \u2502 const patternContext = patternCanvas.getContext('2d');\nUSER \u2502 const size = 10;\nUSER \u2502 patternCanvas.width = size;\nUSER \u2502 patternCanvas.height = size;\nUSER \u2502\nUSER \u2502 patternContext.fillStyle = 'rgba(255, 99, 132, 0.8)';\nUSER \u2502 patternContext.fillRect(0, 0, size, size);\nUSER \u2502\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/code-in-json-syntax.js:\nUSER \u22ee...\nUSER \u2502 function getAspectRatio() {\nUSER \u2502 var width = chartContainer.offsetWidth;\nUSER \u2502 // Gradually change aspect ratio from 2 (landscape) to 1 (square)\nUSER \u2502 return Math.max(1, Math.min(2, width / 300));\nUSER \u22ee...\nUSER \u2502 function resizeChart() {\nUSER \u2502 chart.options.aspectRatio = getAspectRatio();\nUSER \u2502 chart.resize();\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/leaderboard.js:\nUSER \u22ee...\nUSER \u2502 function updateChart() {\nUSER \u2502 var selectedRows = document.querySelectorAll('tr.selected');\nUSER \u2502 var showAll = selectedRows.length === 0;\nUSER \u2502\nUSER \u2502 displayedData = [];\nUSER \u2502 leaderboardData.labels = [];\nUSER \u2502 leaderboardData.datasets[0].data = [];\nUSER \u2502\nUSER \u2502 allData.forEach(function(row, index) {\nUSER \u2502 var rowElement = document.getElementById('edit-row-' + index);\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/quant-chart.js:\nUSER \u22ee...\nUSER \u2502 function updateChart(filterText) {\nUSER \u2502 var filteredData = allData.filter(row => \nUSER \u2502 row.model.toLowerCase().includes(filterText.toLowerCase())\nUSER \u2502 );\nUSER \u2502 \nUSER \u2502 var chartData = {\nUSER \u2502 labels: filteredData.map(row => row.model),\nUSER \u2502 datasets: [{\nUSER \u2502 label: 'Percent completed correctly',\nUSER \u2502 data: filteredData.map(row => row.pass_rate_2),\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/qwq-chart.js:\nUSER \u22ee...\nUSER \u2502 function updateChart(filterText) {\nUSER \u2502 var filteredData = allData.filter(row => \nUSER \u2502 row.model.toLowerCase().includes(filterText.toLowerCase())\nUSER \u2502 );\nUSER \u2502 \nUSER \u2502 var chartData = {\nUSER \u2502 labels: filteredData.map(row => row.model),\nUSER \u2502 datasets: [{\nUSER \u2502 data: filteredData.map(row => row.pass_rate_2),\nUSER \u2502 backgroundColor: filteredData.map(row => \nUSER \u22ee...\nUSER \nUSER benchmark/benchmark.py:\nUSER \u22ee...\nUSER \u2502@app.command()\nUSER \u2502def main(\nUSER \u2502 dirnames: Optional[List[str]] = typer.Argument(None, help=\"Directory names\"),\nUSER \u2502 graphs: bool = typer.Option(False, \"--graphs\", help=\"Generate graphs\"),\nUSER \u2502 model: str = typer.Option(\"gpt-3.5-turbo\", \"--model\", \"-m\", help=\"Model name\"),\nUSER \u2502 sleep: float = typer.Option(\nUSER \u2502 0, \"--sleep\", help=\"Sleep seconds between tests when single threaded\"\nUSER \u2502 ),\nUSER \u2502 languages: str = typer.Option(\nUSER \u2502 None, \"--languages\", \"-l\", help=\"Only run tests for specific languages (comma separated)\"\nUSER \u2502 ),\nUSER \u22ee...\nUSER \u2502def load_results(dirname, stats_languages=None):\nUSER \u22ee...\nUSER \u2502def summarize_results(dirname, stats_languages=None):\nUSER \u2502 all_results = load_results(dirname, stats_languages)\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def show(stat, red=\"red\"):\nUSER \u22ee...\nUSER \u2502def cleanup_test_output(output, testdir):\nUSER \u22ee...\nUSER \nUSER benchmark/over_time.py:\nUSER \u22ee...\nUSER \u2502class BenchmarkPlotter:\nUSER \u2502 LABEL_FONT_SIZE = 16\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def load_data(self, yaml_file: str) -> List[ModelData]:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER benchmark/problem_stats.py:\nUSER \u22ee...\nUSER \u2502def load_results(dirname):\nUSER \u22ee...\nUSER \nUSER benchmark/refactor_tools.py:\nUSER \u22ee...\nUSER \u2502class ParentNodeTransformer(ast.NodeTransformer):\nUSER \u2502 \"\"\"\nUSER \u2502 This transformer sets the 'parent' attribute on each node.\nUSER \u22ee...\nUSER \u2502 def generic_visit(self, node):\nUSER \u22ee...\nUSER \u2502def main(paths):\nUSER \u22ee...\nUSER \nUSER benchmark/rungrid.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \u2502def run(dirname, model, edit_format):\nUSER \u22ee...\nUSER \nUSER benchmark/swe_bench.py:\nUSER \u22ee...\nUSER \u2502def plot_swe_bench(data_file, is_lite):\nUSER \u22ee...\nUSER \nUSER scripts/blame.py:\nUSER \u22ee...\nUSER \u2502def run(cmd):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/issues.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/my_models.py:\nUSER \u22ee...\nUSER \u2502def collect_model_stats(n_lines=1000):\nUSER \u22ee...\nUSER \u2502def format_text_table(model_stats):\nUSER \u22ee...\nUSER \nUSER scripts/update-history.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/versionbump.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/yank-old-versions.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER tests/basic/test_sanity_check_repo.py:\nUSER \u22ee...\nUSER \u2502def mock_repo_wrapper(repo_obj, git_repo_error=None):\nUSER \u22ee...\nUSER \nUSER tests/basic/test_watch.py:\nUSER \u22ee...\nUSER \u2502def test_ai_comment_pattern():\nUSER \u2502 # Create minimal IO and Coder instances for testing\nUSER \u2502 class MinimalCoder:\nUSER \u2502 def __init__(self, io):\nUSER \u2502 self.io = io\nUSER \u2502 self.root = \".\"\nUSER \u2502 self.abs_fnames = set()\nUSER \u2502\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/c/test.c:\nUSER \u22ee...\nUSER \u2502int main() {\nUSER \u2502 printf(\"Hello, World!\\n\");\nUSER \u2502 return 0;\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/cpp/test.cpp:\nUSER \u22ee...\nUSER \u2502int main() {\nUSER \u2502 std::cout << \"Hello, World!\" << std::endl;\nUSER \u2502 return 0;\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/csharp/test.cs:\nUSER \u22ee...\nUSER \u2502namespace Greetings {\nUSER \u2502 public interface IGreeter {\nUSER \u2502 string Greet(string name);\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public class Person {\nUSER \u2502 public string Name { get; set; }\nUSER \u2502 public int Age { get; set; }\nUSER \u2502\nUSER \u2502 public Person(string name, int age) {\nUSER \u2502 Name = name;\nUSER \u2502 Age = age;\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502 public class FormalGreeter : IGreeter {\nUSER \u2502 private const string PREFIX = \"Good day\";\nUSER \u2502 private static readonly int MAX_AGE = 150;\nUSER \u2502\nUSER \u2502 public string Greet(string name) {\nUSER \u2502 return $\"{PREFIX}, {name}!\";\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public string GreetPerson(Person person) {\nUSER \u2502 return $\"{PREFIX}, {person.Name} ({person.Age})!\";\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elisp/test.el:\nUSER \u22ee...\nUSER \u2502(defun create-formal-greeter ()\nUSER \u22ee...\nUSER \u2502(defun main ()\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elixir/test.ex:\nUSER \u2502defmodule Greeter do\nUSER \u2502 def hello(name) do\nUSER \u2502 IO.puts(\"Hello, #{name}!\")\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elm/test.elm:\nUSER \u22ee...\nUSER \u2502type Greeting\nUSER \u2502 = Formal\nUSER \u22ee...\nUSER \u2502greet style person =\nUSER \u2502 let\nUSER \u2502 prefix =\nUSER \u22ee...\nUSER \u2502defaultPerson =\nUSER \u22ee...\nUSER \u2502main =\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/go/test.go:\nUSER \u22ee...\nUSER \u2502type Person struct {\nUSER \u2502 Name string\nUSER \u2502 Age int\nUSER \u22ee...\nUSER \u2502type Greeter interface {\nUSER \u2502 Greet(p Person) string\nUSER \u22ee...\nUSER \u2502type FormalGreeter struct {\nUSER \u2502 Prefix string\nUSER \u22ee...\nUSER \u2502)\nUSER \u2502\nUSER \u2502func (g FormalGreeter) Greet(p Person) string {\nUSER \u2502 return fmt.Sprintf(\"%s, %s! You are %d years old.\",\nUSER \u2502 g.Prefix, p.Name, p.Age)\nUSER \u2502}\nUSER \u2502\nUSER \u2502func NewFormalGreeter() *FormalGreeter {\nUSER \u2502 return &FormalGreeter{Prefix: \"Good day\"}\nUSER \u2502}\nUSER \u2502\nUSER \u2502func main() {\nUSER \u2502 greeter := NewFormalGreeter()\nUSER \u2502 person := Person{Name: DefaultName, Age: 42}\nUSER \u2502 fmt.Println(greeter.Greet(person))\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/java/test.java:\nUSER \u2502public interface Greeting {\nUSER \u2502 String greet(String name);\nUSER \u22ee...\nUSER \u2502public class Test implements Greeting {\nUSER \u2502 private String prefix = \"Hello\";\nUSER \u2502\nUSER \u2502 public String greet(String name) {\nUSER \u2502 return prefix + \", \" + name + \"!\";\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public static void main(String[] args) {\nUSER \u2502 Test greeter = new Test();\nUSER \u2502 System.out.println(greeter.greet(\"World\"));\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/javascript/test.js:\nUSER \u22ee...\nUSER \u2502class Person {\nUSER \u2502 constructor(name) {\nUSER \u2502 this.name = name;\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 sayHello() {\nUSER \u2502 return `Hello, ${this.name}!`;\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502function greet(person) {\nUSER \u2502 return person.sayHello();\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/kotlin/test.kt:\nUSER \u2502interface Greeting {\nUSER \u2502 fun greet(name: String): String\nUSER \u22ee...\nUSER \u2502class Test : Greeting {\nUSER \u2502 private val prefix = \"Hello\"\nUSER \u2502\nUSER \u2502 override fun greet(name: String): String {\nUSER \u2502 return \"$prefix, $name!\"\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502fun main(args: Array) {\nUSER \u2502 val greeter = Test()\nUSER \u2502 println(greeter.greet(\"World\"))\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ocaml/test.ml:\nUSER \u22ee...\nUSER \u2502module Greeter = struct\nUSER \u2502 type person = {\nUSER \u2502 name: string;\nUSER \u2502 age: int\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 let create_person name age =\nUSER \u2502 {name; age}\nUSER \u2502\nUSER \u2502 let greet person =\nUSER \u2502 Printf.printf \"Hello, %s! You are %d years old.\\n\"\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/php/test.php:\nUSER \u22ee...\nUSER \u2502function greet($name) {\nUSER \u2502 echo \"Hello, $name!\";\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/python/test.py:\nUSER \u22ee...\nUSER \u2502class Person:\nUSER \u2502 \"\"\"A class representing a person.\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def greet(self, formal: bool = False) -> str:\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ql/test.ql:\nUSER \u2502predicate greet(string name) {\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ruby/test.rb:\nUSER \u2502def greet(name)\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/rust/test.rs:\nUSER \u22ee...\nUSER \u2502trait Greeting {\nUSER \u2502 fn greet(&self) -> String;\nUSER \u22ee...\nUSER \u2502struct Person {\nUSER \u2502 name: String,\nUSER \u2502 age: u32,\nUSER \u22ee...\nUSER \u2502impl Greeting for Person {\nUSER \u2502 fn greet(&self) -> String {\nUSER \u2502 format!(\"Hello, {}! You are {} years old.\", self.name, self.age)\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502fn main() {\nUSER \u2502 let person = Person::new(DEFAULT_NAME.to_string(), 30);\nUSER \u2502 println!(\"{}\", person.greet());\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/typescript/test.ts:\nUSER \u2502function greet(name: string): void {\nUSER \u22ee...\nUSER \nUSER tests/fixtures/sample-code-base/sample.js:\nUSER \u22ee...\nUSER \u2502function greet(name) {\nUSER \u2502 return `Hello, ${name}!`;\nUSER \u22ee...\nUSER \u2502function calculateCircleArea(radius) {\nUSER \u2502 return Math.PI * radius * radius;\nUSER \u22ee...\nUSER \u2502function isPrime(number) {\nUSER \u2502 if (number <= 1) return false;\nUSER \u2502 for (let i = 2; i <= Math.sqrt(number); i++) {\nUSER \u2502 if (number % i === 0) return false;\nUSER \u2502 }\nUSER \u2502 return true;\nUSER \u22ee...\nUSER \u2502function reverseString(str) {\nUSER \u2502 return str.split('').reverse().join('');\nUSER \u22ee...\nUSER \u2502function getRandomNumber(min, max) {\nUSER \u2502 return Math.floor(Math.random() * (max - min + 1)) + min;\nUSER \u22ee...\nUSER \u2502function filterEvenNumbers(numbers) {\nUSER \u2502 return numbers.filter(num => num % 2 !== 0);\nUSER \u22ee...\nUSER \u2502function factorial(n) {\nUSER \u2502 if (n === 0 || n === 1) return 1;\nUSER \u2502 return n * factorial(n - 1);\nUSER \u22ee...\nUSER \nUSER tests/fixtures/sample-code-base/sample.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\n-------\nASSISTANT Ok, I won't try and edit those files without asking first.\n-------\nUSER Don't try and edit any existing code without asking me to add the files to the chat!\nUSER Tell me which files in my repo are the most likely to **need changes** to solve the requests I make, and then stop so I can add them to the chat.\nUSER Only include the files that are most likely to actually need to be edited.\nUSER Don't include files that might contain relevant context, just files that will need to be changed.\n-------\nASSISTANT Ok, based on your requests I will suggest which files need to be edited and then stop and wait for your approval.\n-------\nUSER what is this repo?\n-------\nASSISTANT Based on the file summaries, this appears to be a repository for an AI coding assistant tool called \"aider\". The key components I can identify are:\nASSISTANT \nASSISTANT 1. A core AI coding assistant framework with:\nASSISTANT - Multiple coder implementations (editblock, udiff, wholefile etc)\nASSISTANT - Prompt management system\nASSISTANT - Repository interaction (git integration, file watching)\nASSISTANT - Voice input support\nASSISTANT - GUI interface\nASSISTANT - Analytics tracking\nASSISTANT \nASSISTANT 2. Benchmarking system for evaluating coding assistant performance:\nASSISTANT - Language-specific test fixtures\nASSISTANT - Performance measurement tools\nASSISTANT - Result visualization\nASSISTANT \nASSISTANT 3. Supporting infrastructure:\nASSISTANT - Command line interface\nASSISTANT - Configuration management\nASSISTANT - Error handling\nASSISTANT - Utility functions\nASSISTANT - Documentation/website\nASSISTANT \nASSISTANT The tool seems focused\n-------\nASSISTANT Based on the file summaries, this appears to be a repository for an AI coding assistant tool called \"aider\". The key components I can identify are:\nASSISTANT \nASSISTANT 1. A core AI coding assistant framework with:\nASSISTANT - Multiple coder implementations (editblock, udiff, wholefile etc)\nASSISTANT - Prompt management system\nASSISTANT - Repository interaction (git integration, file watching)\nASSISTANT - Voice input support\nASSISTANT - GUI interface\nASSISTANT - Analytics tracking\nASSISTANT \nASSISTANT 2. Benchmarking system for evaluating coding assistant performance:\nASSISTANT - Language-specific test fixtures\nASSISTANT - Performance measurement tools\nASSISTANT - Result visualization\nASSISTANT \nASSISTANT 3. Supporting infrastructure:\nASSISTANT - Command line interface\nASSISTANT - Configuration management\nASSISTANT - Error handling\nASSISTANT - Utility functions\nASSISTANT - Documentation/website\nASSISTANT \nASSISTANT The tool seems focused\nASSISTANT ^C KeyboardInterrupt\n-------\nUSER pardon?\n-------\nSYSTEM # *SEARCH/REPLACE block* Rules:\nSYSTEM \nSYSTEM Every *SEARCH/REPLACE block* must use this format:\nSYSTEM 1. The *FULL* file path alone on a line, verbatim. No bold asterisks, no quotes around it, no escaping of characters, etc.\nSYSTEM 2. The opening fence and code language, eg: ```python\nSYSTEM 3. The start of search block: <<<<<<< SEARCH\nSYSTEM 4. A contiguous chunk of lines to search for in the existing source code\nSYSTEM 5. The dividing line: =======\nSYSTEM 6. The lines to replace into the source code\nSYSTEM 7. The end of the replace block: >>>>>>> REPLACE\nSYSTEM 8. The closing fence: ```\nSYSTEM \nSYSTEM Use the *FULL* file path, as shown to you by the user.\nSYSTEM \nSYSTEM Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.\nSYSTEM 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.\nSYSTEM \nSYSTEM *SEARCH/REPLACE* blocks will *only* replace the first match occurrence.\nSYSTEM Including multiple unique *SEARCH/REPLACE* blocks if needed.\nSYSTEM Include enough lines in each SEARCH section to uniquely match each set of lines that need to change.\nSYSTEM \nSYSTEM Keep *SEARCH/REPLACE* blocks concise.\nSYSTEM Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.\nSYSTEM Include just the changing lines, and a few surrounding lines if needed for uniqueness.\nSYSTEM Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.\nSYSTEM \nSYSTEM Only create *SEARCH/REPLACE* blocks for files that the user has added to the chat!\nSYSTEM \nSYSTEM To move code within a file, use 2 *SEARCH/REPLACE* blocks: 1 to delete it from its current location, 1 to insert it in the new location.\nSYSTEM \nSYSTEM Pay attention to which filenames the user wants you to edit, especially if they are asking you to create a new file.\nSYSTEM \nSYSTEM If you want to put code in a new file, use a *SEARCH/REPLACE block* with:\nSYSTEM - A new file path, including dir name if needed\nSYSTEM - An empty `SEARCH` section\nSYSTEM - The new file's contents in the `REPLACE` section\nSYSTEM \nSYSTEM To rename files which have been added to the chat, use shell commands at the end of your response.\nSYSTEM \nSYSTEM If the user just says something like \"ok\" or \"go ahead\" or \"do that\" they probably want you to make SEARCH/REPLACE blocks for the code changes you just proposed.\nSYSTEM The user will say when they've applied your edits. If they haven't explicitly confirmed the edits have been applied, they probably want proper SEARCH/REPLACE blocks.\nSYSTEM \nSYSTEM \nSYSTEM ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!\nSYSTEM \nSYSTEM Examples of when to suggest shell commands:\nSYSTEM \nSYSTEM - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.\nSYSTEM - If you changed a CLI program, suggest the command to run it to see the new behavior.\nSYSTEM - If you added a test, suggest how to run it with the testing tool used by the project.\nSYSTEM - Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.\nSYSTEM - If your code changes add new dependencies, suggest the command to install them.\nSYSTEM - Etc.\nSYSTEM "}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565163}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565178}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565184}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565186}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565186}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565191}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565196}
+{"event": "message_send_exception", "properties": {"exception": "Messages don't properly alternate user/assistant:\n\n-------\nSYSTEM Act as an expert software developer.\nSYSTEM Always use best practices when coding.\nSYSTEM Respect and use existing conventions, libraries, etc that are already present in the code base.\nSYSTEM \nSYSTEM Take requests for changes to the supplied code.\nSYSTEM If the request is ambiguous, ask questions.\nSYSTEM \nSYSTEM Always reply to the user in the same language they are using.\nSYSTEM \nSYSTEM Once you understand the request you MUST:\nSYSTEM \nSYSTEM 1. Decide if you need to propose *SEARCH/REPLACE* edits to any files that haven't been added to the chat. You can create new files without asking!\nSYSTEM \nSYSTEM But if you need to propose edits to existing files not already added to the chat, you *MUST* tell the user their full path names and ask them to *add the files to the chat*.\nSYSTEM End your reply and wait for their approval.\nSYSTEM You can keep asking if you then decide you need to edit more files.\nSYSTEM \nSYSTEM 2. Think step-by-step and explain the needed changes in a few short sentences.\nSYSTEM \nSYSTEM 3. Describe each change with a *SEARCH/REPLACE block* per the examples below.\nSYSTEM \nSYSTEM All changes to files must use this *SEARCH/REPLACE block* format.\nSYSTEM ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!\nSYSTEM \nSYSTEM 4. *Concisely* suggest any shell commands the user might want to run in ```bash blocks.\nSYSTEM \nSYSTEM Just suggest shell commands this way, not example code.\nSYSTEM Only suggest complete shell commands that are ready to execute, without placeholders.\nSYSTEM Only suggest at most a few shell commands at a time, not more than 1-3, one per line.\nSYSTEM Do not suggest multi-line shell commands.\nSYSTEM All shell commands will run from the root directory of the user's project.\nSYSTEM \nSYSTEM Use the appropriate shell based on the user's system info:\nSYSTEM - Platform: macOS-15.2-x86_64-i386-64bit\nSYSTEM - Shell: SHELL=/usr/local/Cellar/bash/5.2.26/bin/bash\nSYSTEM - Language: en_US\nSYSTEM - Current date: 2025-01-22\nSYSTEM - The user's pre-commit runs these lint commands, don't suggest running them:\nSYSTEM - /Users/gauthier/Projects/aider/tmp.lint.sh\nSYSTEM \nSYSTEM Examples of when to suggest shell commands:\nSYSTEM \nSYSTEM - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.\nSYSTEM - If you changed a CLI program, suggest the command to run it to see the new behavior.\nSYSTEM - If you added a test, suggest how to run it with the testing tool used by the project.\nSYSTEM - Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.\nSYSTEM - If your code changes add new dependencies, suggest the command to install them.\nSYSTEM - Etc.\nSYSTEM \nSYSTEM \nSYSTEM # Example conversations:\nSYSTEM \nSYSTEM ## USER: Change get_factorial() to use math.factorial\nSYSTEM \nSYSTEM ## ASSISTANT: To make this change we need to modify `mathweb/flask/app.py` to:\nSYSTEM \nSYSTEM 1. Import the math package.\nSYSTEM 2. Remove the existing factorial() function.\nSYSTEM 3. Update get_factorial() to call math.factorial instead.\nSYSTEM \nSYSTEM Here are the *SEARCH/REPLACE* blocks:\nSYSTEM \nSYSTEM mathweb/flask/app.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM from flask import Flask\nSYSTEM =======\nSYSTEM import math\nSYSTEM from flask import Flask\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM mathweb/flask/app.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM def factorial(n):\nSYSTEM \"compute factorial\"\nSYSTEM \nSYSTEM if n == 0:\nSYSTEM return 1\nSYSTEM else:\nSYSTEM return n * factorial(n-1)\nSYSTEM \nSYSTEM =======\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM mathweb/flask/app.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM return str(factorial(n))\nSYSTEM =======\nSYSTEM return str(math.factorial(n))\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM \nSYSTEM ## USER: Refactor hello() into its own file.\nSYSTEM \nSYSTEM ## ASSISTANT: To make this change we need to modify `main.py` and make a new file `hello.py`:\nSYSTEM \nSYSTEM 1. Make a new hello.py file with hello() in it.\nSYSTEM 2. Remove hello() from main.py and replace it with an import.\nSYSTEM \nSYSTEM Here are the *SEARCH/REPLACE* blocks:\nSYSTEM \nSYSTEM hello.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM =======\nSYSTEM def hello():\nSYSTEM \"print a greeting\"\nSYSTEM \nSYSTEM print(\"hello\")\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM main.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM def hello():\nSYSTEM \"print a greeting\"\nSYSTEM \nSYSTEM print(\"hello\")\nSYSTEM =======\nSYSTEM from hello import hello\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM # *SEARCH/REPLACE block* Rules:\nSYSTEM \nSYSTEM Every *SEARCH/REPLACE block* must use this format:\nSYSTEM 1. The *FULL* file path alone on a line, verbatim. No bold asterisks, no quotes around it, no escaping of characters, etc.\nSYSTEM 2. The opening fence and code language, eg: ```python\nSYSTEM 3. The start of search block: <<<<<<< SEARCH\nSYSTEM 4. A contiguous chunk of lines to search for in the existing source code\nSYSTEM 5. The dividing line: =======\nSYSTEM 6. The lines to replace into the source code\nSYSTEM 7. The end of the replace block: >>>>>>> REPLACE\nSYSTEM 8. The closing fence: ```\nSYSTEM \nSYSTEM Use the *FULL* file path, as shown to you by the user.\nSYSTEM \nSYSTEM Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.\nSYSTEM 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.\nSYSTEM \nSYSTEM *SEARCH/REPLACE* blocks will *only* replace the first match occurrence.\nSYSTEM Including multiple unique *SEARCH/REPLACE* blocks if needed.\nSYSTEM Include enough lines in each SEARCH section to uniquely match each set of lines that need to change.\nSYSTEM \nSYSTEM Keep *SEARCH/REPLACE* blocks concise.\nSYSTEM Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.\nSYSTEM Include just the changing lines, and a few surrounding lines if needed for uniqueness.\nSYSTEM Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.\nSYSTEM \nSYSTEM Only create *SEARCH/REPLACE* blocks for files that the user has added to the chat!\nSYSTEM \nSYSTEM To move code within a file, use 2 *SEARCH/REPLACE* blocks: 1 to delete it from its current location, 1 to insert it in the new location.\nSYSTEM \nSYSTEM Pay attention to which filenames the user wants you to edit, especially if they are asking you to create a new file.\nSYSTEM \nSYSTEM If you want to put code in a new file, use a *SEARCH/REPLACE block* with:\nSYSTEM - A new file path, including dir name if needed\nSYSTEM - An empty `SEARCH` section\nSYSTEM - The new file's contents in the `REPLACE` section\nSYSTEM \nSYSTEM To rename files which have been added to the chat, use shell commands at the end of your response.\nSYSTEM \nSYSTEM If the user just says something like \"ok\" or \"go ahead\" or \"do that\" they probably want you to make SEARCH/REPLACE blocks for the code changes you just proposed.\nSYSTEM The user will say when they've applied your edits. If they haven't explicitly confirmed the edits have been applied, they probably want proper SEARCH/REPLACE blocks.\nSYSTEM \nSYSTEM \nSYSTEM ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!\nSYSTEM \nSYSTEM Examples of when to suggest shell commands:\nSYSTEM \nSYSTEM - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.\nSYSTEM - If you changed a CLI program, suggest the command to run it to see the new behavior.\nSYSTEM - If you added a test, suggest how to run it with the testing tool used by the project.\nSYSTEM - Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.\nSYSTEM - If your code changes add new dependencies, suggest the command to install them.\nSYSTEM - Etc.\nSYSTEM \n-------\nUSER I am not sharing any files that you can edit yet.\n-------\nASSISTANT Ok.\n-------\nUSER tell me a story\n-------\nASSISTANT Once upon a time, in a small village nestled between rolling green hills, there lived a young girl named Elara who had a peculiar gift - she could hear the whispers of the wind. \nASSISTANT \nASSISTANT Each morning, as the first\n-------\nASSISTANT Once upon a time, in a small village nestled between rolling green hills, there lived a young girl named Elara who had a peculiar gift - she could hear the whispers of the wind. \nASSISTANT \nASSISTANT Each morning, as the first\nASSISTANT ^C KeyboardInterrupt\n-------\nUSER ?\n-------\nSYSTEM # *SEARCH/REPLACE block* Rules:\nSYSTEM \nSYSTEM Every *SEARCH/REPLACE block* must use this format:\nSYSTEM 1. The *FULL* file path alone on a line, verbatim. No bold asterisks, no quotes around it, no escaping of characters, etc.\nSYSTEM 2. The opening fence and code language, eg: ```python\nSYSTEM 3. The start of search block: <<<<<<< SEARCH\nSYSTEM 4. A contiguous chunk of lines to search for in the existing source code\nSYSTEM 5. The dividing line: =======\nSYSTEM 6. The lines to replace into the source code\nSYSTEM 7. The end of the replace block: >>>>>>> REPLACE\nSYSTEM 8. The closing fence: ```\nSYSTEM \nSYSTEM Use the *FULL* file path, as shown to you by the user.\nSYSTEM \nSYSTEM Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.\nSYSTEM 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.\nSYSTEM \nSYSTEM *SEARCH/REPLACE* blocks will *only* replace the first match occurrence.\nSYSTEM Including multiple unique *SEARCH/REPLACE* blocks if needed.\nSYSTEM Include enough lines in each SEARCH section to uniquely match each set of lines that need to change.\nSYSTEM \nSYSTEM Keep *SEARCH/REPLACE* blocks concise.\nSYSTEM Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.\nSYSTEM Include just the changing lines, and a few surrounding lines if needed for uniqueness.\nSYSTEM Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.\nSYSTEM \nSYSTEM Only create *SEARCH/REPLACE* blocks for files that the user has added to the chat!\nSYSTEM \nSYSTEM To move code within a file, use 2 *SEARCH/REPLACE* blocks: 1 to delete it from its current location, 1 to insert it in the new location.\nSYSTEM \nSYSTEM Pay attention to which filenames the user wants you to edit, especially if they are asking you to create a new file.\nSYSTEM \nSYSTEM If you want to put code in a new file, use a *SEARCH/REPLACE block* with:\nSYSTEM - A new file path, including dir name if needed\nSYSTEM - An empty `SEARCH` section\nSYSTEM - The new file's contents in the `REPLACE` section\nSYSTEM \nSYSTEM To rename files which have been added to the chat, use shell commands at the end of your response.\nSYSTEM \nSYSTEM If the user just says something like \"ok\" or \"go ahead\" or \"do that\" they probably want you to make SEARCH/REPLACE blocks for the code changes you just proposed.\nSYSTEM The user will say when they've applied your edits. If they haven't explicitly confirmed the edits have been applied, they probably want proper SEARCH/REPLACE blocks.\nSYSTEM \nSYSTEM \nSYSTEM ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!\nSYSTEM \nSYSTEM Examples of when to suggest shell commands:\nSYSTEM \nSYSTEM - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.\nSYSTEM - If you changed a CLI program, suggest the command to run it to see the new behavior.\nSYSTEM - If you added a test, suggest how to run it with the testing tool used by the project.\nSYSTEM - Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.\nSYSTEM - If your code changes add new dependencies, suggest the command to install them.\nSYSTEM - Etc.\nSYSTEM "}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565196}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565320}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565320}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565337}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565339}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565339}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565341}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565345}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565348}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565348}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565351}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565356}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565359}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565365}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565516}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565517}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737565517}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566658}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566660}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566661}
+{"event": "command_tokens", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566662}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566670}
+{"event": "command_tokens", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566673}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566684}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566687}
+{"event": "command_tokens", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566693}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566698}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 105579, "completion_tokens": 0, "total_tokens": 105579, "cost": 0.01478106, "total_cost": 0.01478106}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566700}
+{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566710}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566711}
+{"event": "message_send_exception", "properties": {"exception": "Messages don't properly alternate user/assistant:\n\n-------\nSYSTEM Act as an expert software developer.\nSYSTEM Always use best practices when coding.\nSYSTEM Respect and use existing conventions, libraries, etc that are already present in the code base.\nSYSTEM \nSYSTEM Take requests for changes to the supplied code.\nSYSTEM If the request is ambiguous, ask questions.\nSYSTEM \nSYSTEM Always reply to the user in the same language they are using.\nSYSTEM \nSYSTEM Once you understand the request you MUST:\nSYSTEM \nSYSTEM 1. Decide if you need to propose *SEARCH/REPLACE* edits to any files that haven't been added to the chat. You can create new files without asking!\nSYSTEM \nSYSTEM But if you need to propose edits to existing files not already added to the chat, you *MUST* tell the user their full path names and ask them to *add the files to the chat*.\nSYSTEM End your reply and wait for their approval.\nSYSTEM You can keep asking if you then decide you need to edit more files.\nSYSTEM \nSYSTEM 2. Think step-by-step and explain the needed changes in a few short sentences.\nSYSTEM \nSYSTEM 3. Describe each change with a *SEARCH/REPLACE block* per the examples below.\nSYSTEM \nSYSTEM All changes to files must use this *SEARCH/REPLACE block* format.\nSYSTEM ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!\nSYSTEM \nSYSTEM 4. *Concisely* suggest any shell commands the user might want to run in ```bash blocks.\nSYSTEM \nSYSTEM Just suggest shell commands this way, not example code.\nSYSTEM Only suggest complete shell commands that are ready to execute, without placeholders.\nSYSTEM Only suggest at most a few shell commands at a time, not more than 1-3, one per line.\nSYSTEM Do not suggest multi-line shell commands.\nSYSTEM All shell commands will run from the root directory of the user's project.\nSYSTEM \nSYSTEM Use the appropriate shell based on the user's system info:\nSYSTEM - Platform: macOS-15.2-x86_64-i386-64bit\nSYSTEM - Shell: SHELL=/usr/local/Cellar/bash/5.2.26/bin/bash\nSYSTEM - Language: en_US\nSYSTEM - Current date: 2025-01-22\nSYSTEM - The user is operating inside a git repository\nSYSTEM - The user's pre-commit runs these lint commands, don't suggest running them:\nSYSTEM - /Users/gauthier/Projects/aider/tmp.lint.sh\nSYSTEM \nSYSTEM Examples of when to suggest shell commands:\nSYSTEM \nSYSTEM - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.\nSYSTEM - If you changed a CLI program, suggest the command to run it to see the new behavior.\nSYSTEM - If you added a test, suggest how to run it with the testing tool used by the project.\nSYSTEM - Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.\nSYSTEM - If your code changes add new dependencies, suggest the command to install them.\nSYSTEM - Etc.\nSYSTEM \nSYSTEM \nSYSTEM # Example conversations:\nSYSTEM \nSYSTEM ## USER: Change get_factorial() to use math.factorial\nSYSTEM \nSYSTEM ## ASSISTANT: To make this change we need to modify `mathweb/flask/app.py` to:\nSYSTEM \nSYSTEM 1. Import the math package.\nSYSTEM 2. Remove the existing factorial() function.\nSYSTEM 3. Update get_factorial() to call math.factorial instead.\nSYSTEM \nSYSTEM Here are the *SEARCH/REPLACE* blocks:\nSYSTEM \nSYSTEM mathweb/flask/app.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM from flask import Flask\nSYSTEM =======\nSYSTEM import math\nSYSTEM from flask import Flask\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM mathweb/flask/app.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM def factorial(n):\nSYSTEM \"compute factorial\"\nSYSTEM \nSYSTEM if n == 0:\nSYSTEM return 1\nSYSTEM else:\nSYSTEM return n * factorial(n-1)\nSYSTEM \nSYSTEM =======\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM mathweb/flask/app.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM return str(factorial(n))\nSYSTEM =======\nSYSTEM return str(math.factorial(n))\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM \nSYSTEM ## USER: Refactor hello() into its own file.\nSYSTEM \nSYSTEM ## ASSISTANT: To make this change we need to modify `main.py` and make a new file `hello.py`:\nSYSTEM \nSYSTEM 1. Make a new hello.py file with hello() in it.\nSYSTEM 2. Remove hello() from main.py and replace it with an import.\nSYSTEM \nSYSTEM Here are the *SEARCH/REPLACE* blocks:\nSYSTEM \nSYSTEM hello.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM =======\nSYSTEM def hello():\nSYSTEM \"print a greeting\"\nSYSTEM \nSYSTEM print(\"hello\")\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM main.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM def hello():\nSYSTEM \"print a greeting\"\nSYSTEM \nSYSTEM print(\"hello\")\nSYSTEM =======\nSYSTEM from hello import hello\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM # *SEARCH/REPLACE block* Rules:\nSYSTEM \nSYSTEM Every *SEARCH/REPLACE block* must use this format:\nSYSTEM 1. The *FULL* file path alone on a line, verbatim. No bold asterisks, no quotes around it, no escaping of characters, etc.\nSYSTEM 2. The opening fence and code language, eg: ```python\nSYSTEM 3. The start of search block: <<<<<<< SEARCH\nSYSTEM 4. A contiguous chunk of lines to search for in the existing source code\nSYSTEM 5. The dividing line: =======\nSYSTEM 6. The lines to replace into the source code\nSYSTEM 7. The end of the replace block: >>>>>>> REPLACE\nSYSTEM 8. The closing fence: ```\nSYSTEM \nSYSTEM Use the *FULL* file path, as shown to you by the user.\nSYSTEM \nSYSTEM Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.\nSYSTEM 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.\nSYSTEM \nSYSTEM *SEARCH/REPLACE* blocks will *only* replace the first match occurrence.\nSYSTEM Including multiple unique *SEARCH/REPLACE* blocks if needed.\nSYSTEM Include enough lines in each SEARCH section to uniquely match each set of lines that need to change.\nSYSTEM \nSYSTEM Keep *SEARCH/REPLACE* blocks concise.\nSYSTEM Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.\nSYSTEM Include just the changing lines, and a few surrounding lines if needed for uniqueness.\nSYSTEM Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.\nSYSTEM \nSYSTEM Only create *SEARCH/REPLACE* blocks for files that the user has added to the chat!\nSYSTEM \nSYSTEM To move code within a file, use 2 *SEARCH/REPLACE* blocks: 1 to delete it from its current location, 1 to insert it in the new location.\nSYSTEM \nSYSTEM Pay attention to which filenames the user wants you to edit, especially if they are asking you to create a new file.\nSYSTEM \nSYSTEM If you want to put code in a new file, use a *SEARCH/REPLACE block* with:\nSYSTEM - A new file path, including dir name if needed\nSYSTEM - An empty `SEARCH` section\nSYSTEM - The new file's contents in the `REPLACE` section\nSYSTEM \nSYSTEM To rename files which have been added to the chat, use shell commands at the end of your response.\nSYSTEM \nSYSTEM If the user just says something like \"ok\" or \"go ahead\" or \"do that\" they probably want you to make SEARCH/REPLACE blocks for the code changes you just proposed.\nSYSTEM The user will say when they've applied your edits. If they haven't explicitly confirmed the edits have been applied, they probably want proper SEARCH/REPLACE blocks.\nSYSTEM \nSYSTEM \nSYSTEM ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!\nSYSTEM \nSYSTEM Examples of when to suggest shell commands:\nSYSTEM \nSYSTEM - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.\nSYSTEM - If you changed a CLI program, suggest the command to run it to see the new behavior.\nSYSTEM - If you added a test, suggest how to run it with the testing tool used by the project.\nSYSTEM - Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.\nSYSTEM - If your code changes add new dependencies, suggest the command to install them.\nSYSTEM - Etc.\nSYSTEM \n-------\nUSER Here are summaries of some files present in my git repository.\nUSER Do not propose changes to these files, treat them as *read-only*.\nUSER If you need to edit any of these files, ask me to *add them to the chat* first.\nUSER \nUSER aider/analytics.py:\nUSER \u22ee...\nUSER \u2502def compute_hex_threshold(percent):\nUSER \u22ee...\nUSER \u2502def is_uuid_in_percentage(uuid_str, percent):\nUSER \u22ee...\nUSER \u2502class Analytics:\nUSER \u2502 # providers\nUSER \u2502 mp = None\nUSER \u22ee...\nUSER \u2502 def disable(self, permanently):\nUSER \u22ee...\nUSER \u2502 def get_data_file_path(self):\nUSER \u22ee...\nUSER \u2502 def get_or_create_uuid(self):\nUSER \u22ee...\nUSER \u2502 def load_data(self):\nUSER \u22ee...\nUSER \u2502 def save_data(self):\nUSER \u22ee...\nUSER \u2502 def get_system_info(self):\nUSER \u22ee...\nUSER \u2502 def event(self, event_name, main_model=None, **kwargs):\nUSER \u22ee...\nUSER \nUSER aider/args.py:\nUSER \u22ee...\nUSER \u2502def get_parser(default_config_files, git_root):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/args_formatter.py:\nUSER \u22ee...\nUSER \u2502class DotEnvFormatter(argparse.HelpFormatter):\nUSER \u2502 def start_section(self, heading):\nUSER \u2502 res = \"\\n\\n\"\nUSER \u2502 res += \"#\" * (len(heading) + 3)\nUSER \u2502 res += f\"\\n# {heading}\"\nUSER \u22ee...\nUSER \u2502 def _format_usage(self, usage, actions, groups, prefix):\nUSER \u22ee...\nUSER \u2502class YamlHelpFormatter(argparse.HelpFormatter):\nUSER \u2502 def start_section(self, heading):\nUSER \u2502 res = \"\\n\\n\"\nUSER \u2502 res += \"#\" * (len(heading) + 3)\nUSER \u2502 res += f\"\\n# {heading}\"\nUSER \u22ee...\nUSER \u2502 def _format_usage(self, usage, actions, groups, prefix):\nUSER \u22ee...\nUSER \u2502class MarkdownHelpFormatter(argparse.HelpFormatter):\nUSER \u2502 def start_section(self, heading):\nUSER \u22ee...\nUSER \u2502 def _format_usage(self, usage, actions, groups, prefix):\nUSER \u22ee...\nUSER \nUSER aider/coders/architect_prompts.py:\nUSER \u22ee...\nUSER \u2502class ArchitectPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/ask_prompts.py:\nUSER \u22ee...\nUSER \u2502class AskPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/base_coder.py:\nUSER \u22ee...\nUSER \u2502class Coder:\nUSER \u2502 abs_fnames = None\nUSER \u22ee...\nUSER \u2502 @classmethod\nUSER \u2502 def create(\nUSER \u2502 self,\nUSER \u2502 main_model=None,\nUSER \u2502 edit_format=None,\nUSER \u2502 io=None,\nUSER \u2502 from_coder=None,\nUSER \u2502 summarize_from_coder=True,\nUSER \u2502 **kwargs,\nUSER \u22ee...\nUSER \u2502 def get_announcements(self):\nUSER \u22ee...\nUSER \u2502 def show_announcements(self):\nUSER \u22ee...\nUSER \u2502 def add_rel_fname(self, rel_fname):\nUSER \u22ee...\nUSER \u2502 def drop_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def abs_root_path(self, path):\nUSER \u22ee...\nUSER \u2502 def get_repo_map(self, force_refresh=False):\nUSER \u22ee...\nUSER \u2502 def run_stream(self, user_message):\nUSER \u22ee...\nUSER \u2502 def run(self, with_message=None, preproc=True):\nUSER \u22ee...\nUSER \u2502 def fmt_system_prompt(self, prompt):\nUSER \u22ee...\nUSER \u2502 def format_messages(self):\nUSER \u22ee...\nUSER \u2502 def get_multi_response_content(self, final=False):\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def get_inchat_relative_files(self):\nUSER \u22ee...\nUSER \u2502 def get_all_relative_files(self):\nUSER \u22ee...\nUSER \u2502 def allowed_to_edit(self, path):\nUSER \u22ee...\nUSER \u2502 def check_added_files(self):\nUSER \u22ee...\nUSER \u2502 def apply_updates(self):\nUSER \u22ee...\nUSER \u2502 def parse_partial_args(self):\nUSER \u22ee...\nUSER \nUSER aider/coders/base_prompts.py:\nUSER \u2502class CoderPrompts:\nUSER \u22ee...\nUSER \nUSER aider/coders/chat_chunks.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ChatChunks:\nUSER \u2502 system: List = field(default_factory=list)\nUSER \u22ee...\nUSER \u2502 def all_messages(self):\nUSER \u22ee...\nUSER \u2502 def add_cache_control(self, messages):\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_coder.py:\nUSER \u22ee...\nUSER \u2502def do_replace(fname, content, before_text, after_text, fence=None):\nUSER \u22ee...\nUSER \u2502def find_original_update_blocks(content, fence=DEFAULT_FENCE, valid_fnames=None):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_fenced_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditBlockFencedPrompts(EditBlockPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_func_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditBlockFunctionPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditBlockPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/editor_editblock_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditorEditBlockPrompts(EditBlockPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/editor_whole_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditorWholeFilePrompts(WholeFilePrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/help_prompts.py:\nUSER \u22ee...\nUSER \u2502class HelpPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/search_replace.py:\nUSER \u22ee...\nUSER \u2502def try_strategy(texts, strategy, preproc):\nUSER \u22ee...\nUSER \u2502def read_text(fname):\nUSER \u22ee...\nUSER \u2502def main(dnames):\nUSER \u22ee...\nUSER \nUSER aider/coders/single_wholefile_func_prompts.py:\nUSER \u22ee...\nUSER \u2502class SingleWholeFileFunctionPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/udiff_coder.py:\nUSER \u22ee...\nUSER \u2502def do_replace(fname, content, hunk):\nUSER \u22ee...\nUSER \u2502def directly_apply_hunk(content, hunk):\nUSER \u22ee...\nUSER \u2502def hunk_to_before_after(hunk, lines=False):\nUSER \u22ee...\nUSER \nUSER aider/coders/wholefile_func_prompts.py:\nUSER \u22ee...\nUSER \u2502class WholeFileFunctionPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/wholefile_prompts.py:\nUSER \u22ee...\nUSER \u2502class WholeFilePrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/commands.py:\nUSER \u22ee...\nUSER \u2502class Commands:\nUSER \u2502 voice = None\nUSER \u22ee...\nUSER \u2502 def get_raw_completions(self, cmd):\nUSER \u22ee...\nUSER \u2502 def get_completions(self, cmd):\nUSER \u22ee...\nUSER \u2502 def get_commands(self):\nUSER \u22ee...\nUSER \u2502 def matching_commands(self, inp):\nUSER \u22ee...\nUSER \u2502 def run(self, inp):\nUSER \u22ee...\nUSER \u2502 def cmd_undo(self, args):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/copypaste.py:\nUSER \u22ee...\nUSER \u2502class ClipboardWatcher:\nUSER \u2502 \"\"\"Watches clipboard for changes and updates IO placeholder\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def start(self):\nUSER \u22ee...\nUSER \u2502 def stop(self):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/diffs.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \u2502def diff_partial_update(lines_orig, lines_updated, final=False, fname=None):\nUSER \u22ee...\nUSER \nUSER aider/dump.py:\nUSER \u22ee...\nUSER \u2502def cvt(s):\nUSER \u22ee...\nUSER \u2502def dump(*vals):\nUSER \u22ee...\nUSER \nUSER aider/editor.py:\nUSER \u22ee...\nUSER \u2502def print_status_message(success, message, style=None):\nUSER \u22ee...\nUSER \u2502def write_temp_file(\nUSER \u2502 input_data=\"\",\nUSER \u2502 suffix=None,\nUSER \u2502 prefix=None,\nUSER \u2502 dir=None,\nUSER \u22ee...\nUSER \u2502def get_environment_editor(default=None):\nUSER \u22ee...\nUSER \u2502def discover_editor(editor_override=None):\nUSER \u22ee...\nUSER \u2502def pipe_editor(input_data=\"\", suffix=None, editor=None):\nUSER \u22ee...\nUSER \nUSER aider/exceptions.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ExInfo:\nUSER \u22ee...\nUSER \u2502class LiteLLMExceptions:\nUSER \u2502 exceptions = dict()\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def _load(self, strict=False):\nUSER \u22ee...\nUSER \u2502 def exceptions_tuple(self):\nUSER \u22ee...\nUSER \u2502 def get_ex_info(self, ex):\nUSER \u22ee...\nUSER \nUSER aider/format_settings.py:\nUSER \u2502def scrub_sensitive_info(args, text):\nUSER \u22ee...\nUSER \nUSER aider/gui.py:\nUSER \u22ee...\nUSER \u2502class CaptureIO(InputOutput):\nUSER \u2502 lines = []\nUSER \u2502\nUSER \u2502 def tool_output(self, msg, log_only=False):\nUSER \u22ee...\nUSER \u2502 def tool_error(self, msg):\nUSER \u22ee...\nUSER \u2502 def tool_warning(self, msg):\nUSER \u22ee...\nUSER \u2502 def get_captured_lines(self):\nUSER \u22ee...\nUSER \u2502def search(text=None):\nUSER \u22ee...\nUSER \u2502class State:\nUSER \u2502 keys = set()\nUSER \u2502\nUSER \u2502 def init(self, key, val=None):\nUSER \u22ee...\nUSER \u2502@st.cache_resource\nUSER \u2502def get_state():\nUSER \u22ee...\nUSER \u2502@st.cache_resource\nUSER \u2502def get_coder():\nUSER \u22ee...\nUSER \u2502class GUI:\nUSER \u2502 prompt = None\nUSER \u22ee...\nUSER \u2502 def announce(self):\nUSER \u22ee...\nUSER \u2502 def show_edit_info(self, edit):\nUSER \u22ee...\nUSER \u2502 def add_undo(self, commit_hash):\nUSER \u22ee...\nUSER \u2502 def do_sidebar(self):\nUSER \u22ee...\nUSER \u2502 def do_add_to_chat(self):\nUSER \u22ee...\nUSER \u2502 def do_add_files(self):\nUSER \u22ee...\nUSER \u2502 def do_add_web_page(self):\nUSER \u22ee...\nUSER \u2502 def do_clear_chat_history(self):\nUSER \u22ee...\nUSER \u2502 def do_recent_msgs(self):\nUSER \u22ee...\nUSER \u2502 def do_messages_container(self):\nUSER \u22ee...\nUSER \u2502 def initialize_state(self):\nUSER \u22ee...\nUSER \u2502 def button(self, args, **kwargs):\nUSER \u22ee...\nUSER \u2502 def prompt_pending(self):\nUSER \u22ee...\nUSER \u2502 def process_chat(self):\nUSER \u22ee...\nUSER \u2502 def info(self, message, echo=True):\nUSER \u22ee...\nUSER \u2502 def do_web(self):\nUSER \u22ee...\nUSER \u2502 def do_undo(self, commit_hash):\nUSER \u22ee...\nUSER \u2502def gui_main():\nUSER \u22ee...\nUSER \nUSER aider/help.py:\nUSER \u22ee...\nUSER \u2502def get_package_files():\nUSER \u22ee...\nUSER \u2502def fname_to_url(filepath):\nUSER \u22ee...\nUSER \u2502def get_index():\nUSER \u22ee...\nUSER \nUSER aider/history.py:\nUSER \u22ee...\nUSER \u2502class ChatSummary:\nUSER \u2502 def __init__(self, models=None, max_tokens=1024):\nUSER \u2502 if not models:\nUSER \u2502 raise ValueError(\"At least one model must be provided\")\nUSER \u2502 self.models = models if isinstance(models, list) else [models]\nUSER \u2502 self.max_tokens = max_tokens\nUSER \u22ee...\nUSER \u2502 def too_big(self, messages):\nUSER \u22ee...\nUSER \u2502 def tokenize(self, messages):\nUSER \u22ee...\nUSER \u2502 def summarize(self, messages, depth=0):\nUSER \u22ee...\nUSER \u2502 def summarize_real(self, messages, depth=0):\nUSER \u22ee...\nUSER \u2502 def summarize_all(self, messages):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/io.py:\nUSER \u22ee...\nUSER \u2502class AutoCompleter(Completer):\nUSER \u2502 def __init__(\nUSER \u2502 self, root, rel_fnames, addable_rel_fnames, commands, encoding, abs_read_only_fnames=None\nUSER \u22ee...\nUSER \u2502 def tokenize(self):\nUSER \u22ee...\nUSER \u2502 def get_command_completions(self, document, complete_event, text, words):\nUSER \u22ee...\nUSER \u2502 def get_completions(self, document, complete_event):\nUSER \u22ee...\nUSER \u2502class InputOutput:\nUSER \u2502 num_error_outputs = 0\nUSER \u22ee...\nUSER \u2502 def _get_style(self):\nUSER \u22ee...\nUSER \u2502 def read_image(self, filename):\nUSER \u22ee...\nUSER \u2502 def read_text(self, filename, silent=False):\nUSER \u22ee...\nUSER \u2502 def write_text(self, filename, content, max_retries=5, initial_delay=0.1):\nUSER \u22ee...\nUSER \u2502 def rule(self):\nUSER \u22ee...\nUSER \u2502 def interrupt_input(self):\nUSER \u22ee...\nUSER \u2502 def get_input(\nUSER \u2502 self,\nUSER \u2502 root,\nUSER \u2502 rel_fnames,\nUSER \u2502 addable_rel_fnames,\nUSER \u2502 commands,\nUSER \u2502 abs_read_only_fnames=None,\nUSER \u2502 edit_format=None,\nUSER \u2502 ):\nUSER \u2502 self.rule()\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def suspend_to_bg(event):\nUSER \u22ee...\nUSER \u2502 def add_to_input_history(self, inp):\nUSER \u22ee...\nUSER \u2502 def get_input_history(self):\nUSER \u22ee...\nUSER \u2502 def display_user_input(self, inp):\nUSER \u22ee...\nUSER \u2502 def user_input(self, inp, log_only=True):\nUSER \u22ee...\nUSER \u2502 def confirm_ask(\nUSER \u2502 self,\nUSER \u2502 question,\nUSER \u2502 default=\"y\",\nUSER \u2502 subject=None,\nUSER \u2502 explicit_yes_required=False,\nUSER \u2502 group=None,\nUSER \u2502 allow_never=False,\nUSER \u22ee...\nUSER \u2502 def _tool_message(self, message=\"\", strip=True, color=None):\nUSER \u22ee...\nUSER \u2502 def tool_error(self, message=\"\", strip=True):\nUSER \u22ee...\nUSER \u2502 def tool_warning(self, message=\"\", strip=True):\nUSER \u22ee...\nUSER \u2502 def tool_output(self, *messages, log_only=False, bold=False):\nUSER \u22ee...\nUSER \u2502 def print(self, message=\"\"):\nUSER \u22ee...\nUSER \u2502 def append_chat_history(self, text, linebreak=False, blockquote=False, strip=True):\nUSER \u22ee...\nUSER \u2502 def format_files_for_input(self, rel_fnames, rel_read_only_fnames):\nUSER \u22ee...\nUSER \u2502def get_rel_fname(fname, root):\nUSER \u22ee...\nUSER \nUSER aider/linter.py:\nUSER \u22ee...\nUSER \u2502class Linter:\nUSER \u2502 def __init__(self, encoding=\"utf-8\", root=None):\nUSER \u2502 self.encoding = encoding\nUSER \u2502 self.root = root\nUSER \u2502\nUSER \u2502 self.languages = dict(\nUSER \u2502 python=self.py_lint,\nUSER \u2502 )\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def run_cmd(self, cmd, rel_fname, code):\nUSER \u22ee...\nUSER \u2502 def errors_to_lint_result(self, rel_fname, errors):\nUSER \u22ee...\nUSER \u2502 def lint(self, fname, cmd=None):\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class LintResult:\nUSER \u22ee...\nUSER \u2502def basic_lint(fname, code):\nUSER \u22ee...\nUSER \u2502def traverse_tree(node):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/llm.py:\nUSER \u22ee...\nUSER \u2502class LazyLiteLLM:\nUSER \u22ee...\nUSER \nUSER aider/main.py:\nUSER \u22ee...\nUSER \u2502def sanity_check_repo(repo, io):\nUSER \u22ee...\nUSER \u2502def main(argv=None, input=None, output=None, force_git_root=None, return_coder=False):\nUSER \u22ee...\nUSER \nUSER aider/mdstream.py:\nUSER \u22ee...\nUSER \u2502class MarkdownStream:\nUSER \u2502 \"\"\"Streaming markdown renderer that progressively displays content with a live updating window.\nUSER \u2502\nUSER \u2502 Uses rich.console and rich.live to render markdown content with smooth scrolling\nUSER \u2502 and partial updates. Maintains a sliding window of visible content while streaming\nUSER \u2502 in new markdown text.\nUSER \u22ee...\nUSER \u2502 def update(self, text, final=False):\nUSER \u22ee...\nUSER \nUSER aider/models.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ModelSettings:\nUSER \u22ee...\nUSER \u2502class ModelInfoManager:\nUSER \u2502 MODEL_INFO_URL = (\nUSER \u2502 \"https://raw.githubusercontent.com/BerriAI/litellm/main/\"\nUSER \u2502 \"model_prices_and_context_window.json\"\nUSER \u22ee...\nUSER \u2502 def get_model_from_cached_json_db(self, model):\nUSER \u22ee...\nUSER \u2502 def get_model_info(self, model):\nUSER \u22ee...\nUSER \u2502class Model(ModelSettings):\nUSER \u2502 def __init__(self, model, weak_model=None, editor_model=None, editor_edit_format=None):\nUSER \u2502 # Map any alias to its canonical name\nUSER \u2502 model = MODEL_ALIASES.get(model, model)\nUSER \u2502\nUSER \u2502 self.name = model\nUSER \u2502\nUSER \u2502 self.max_chat_history_tokens = 1024\nUSER \u2502 self.weak_model = None\nUSER \u2502 self.editor_model = None\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def get_model_info(self, model):\nUSER \u22ee...\nUSER \u2502 def token_count(self, messages):\nUSER \u22ee...\nUSER \u2502def validate_variables(vars):\nUSER \u22ee...\nUSER \u2502def sanity_check_model(io, model):\nUSER \u22ee...\nUSER \u2502def fuzzy_match_models(name):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/repo.py:\nUSER \u22ee...\nUSER \u2502class GitRepo:\nUSER \u2502 repo = None\nUSER \u22ee...\nUSER \u2502 def commit(self, fnames=None, context=None, message=None, aider_edits=False):\nUSER \u22ee...\nUSER \u2502 def get_commit_message(self, diffs, context):\nUSER \u22ee...\nUSER \u2502 def get_diffs(self, fnames=None):\nUSER \u22ee...\nUSER \u2502 def diff_commits(self, pretty, from_commit, to_commit):\nUSER \u22ee...\nUSER \u2502 def get_tracked_files(self):\nUSER \u22ee...\nUSER \u2502 def normalize_path(self, path):\nUSER \u22ee...\nUSER \u2502 def refresh_aider_ignore(self):\nUSER \u22ee...\nUSER \u2502 def ignored_file(self, fname):\nUSER \u22ee...\nUSER \u2502 def ignored_file_raw(self, fname):\nUSER \u22ee...\nUSER \u2502 def path_in_repo(self, path):\nUSER \u22ee...\nUSER \u2502 def abs_root_path(self, path):\nUSER \u22ee...\nUSER \u2502 def is_dirty(self, path=None):\nUSER \u22ee...\nUSER \u2502 def get_head_commit(self):\nUSER \u22ee...\nUSER \u2502 def get_head_commit_sha(self, short=False):\nUSER \u22ee...\nUSER \nUSER aider/repomap.py:\nUSER \u22ee...\nUSER \u2502class RepoMap:\nUSER \u2502 CACHE_VERSION = 3\nUSER \u22ee...\nUSER \u2502 def token_count(self, text):\nUSER \u22ee...\nUSER \u2502 def get_repo_map(\nUSER \u2502 self,\nUSER \u2502 chat_files,\nUSER \u2502 other_files,\nUSER \u2502 mentioned_fnames=None,\nUSER \u2502 mentioned_idents=None,\nUSER \u2502 force_refresh=False,\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def tags_cache_error(self, original_error=None):\nUSER \u22ee...\nUSER \u2502def get_scm_fname(lang):\nUSER \u22ee...\nUSER \nUSER aider/report.py:\nUSER \u22ee...\nUSER \u2502def report_github_issue(issue_text, title=None, confirm=True):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/run_cmd.py:\nUSER \u22ee...\nUSER \u2502def run_cmd(command, verbose=False, error_print=None, cwd=None):\nUSER \u22ee...\nUSER \u2502def get_windows_parent_process_name():\nUSER \u22ee...\nUSER \u2502def run_cmd_subprocess(command, verbose=False, cwd=None, encoding=sys.stdout.encoding):\nUSER \u22ee...\nUSER \u2502def run_cmd_pexpect(command, verbose=False, cwd=None):\nUSER \u22ee...\nUSER \nUSER aider/scrape.py:\nUSER \u22ee...\nUSER \u2502class Scraper:\nUSER \u2502 pandoc_available = None\nUSER \u22ee...\nUSER \u2502 def scrape(self, url):\nUSER \u22ee...\nUSER \u2502def main(url):\nUSER \u22ee...\nUSER \nUSER aider/sendchat.py:\nUSER \u22ee...\nUSER \u2502def sanity_check_messages(messages):\nUSER \u22ee...\nUSER \u2502def send_completion(\nUSER \u2502 model_name,\nUSER \u2502 messages,\nUSER \u2502 functions,\nUSER \u2502 stream,\nUSER \u2502 temperature=0,\nUSER \u2502 extra_params=None,\nUSER \u22ee...\nUSER \u2502def simple_send_with_retries(model, messages):\nUSER \u22ee...\nUSER \nUSER aider/special.py:\nUSER \u22ee...\nUSER \u2502def is_important(file_path):\nUSER \u22ee...\nUSER \u2502def filter_important_files(file_paths):\nUSER \u22ee...\nUSER \nUSER aider/utils.py:\nUSER \u22ee...\nUSER \u2502class IgnorantTemporaryDirectory:\nUSER \u2502 def __init__(self):\nUSER \u2502 if sys.version_info >= (3, 10):\nUSER \u2502 self.temp_dir = tempfile.TemporaryDirectory(ignore_cleanup_errors=True)\nUSER \u2502 else:\nUSER \u22ee...\nUSER \u2502 def cleanup(self):\nUSER \u22ee...\nUSER \u2502class GitTemporaryDirectory(ChdirTemporaryDirectory):\nUSER \u22ee...\nUSER \u2502def make_repo(path=None):\nUSER \u22ee...\nUSER \u2502def is_image_file(file_name):\nUSER \u22ee...\nUSER \u2502def safe_abs_path(res):\nUSER \u22ee...\nUSER \u2502def format_content(role, content):\nUSER \u22ee...\nUSER \u2502def format_messages(messages, title=None):\nUSER \u22ee...\nUSER \u2502def split_chat_history_markdown(text, include_tool=False):\nUSER \u2502 messages = []\nUSER \u22ee...\nUSER \u2502 def append_msg(role, lines):\nUSER \u22ee...\nUSER \u2502def get_pip_install(args):\nUSER \u22ee...\nUSER \u2502def run_install(cmd):\nUSER \u22ee...\nUSER \u2502class Spinner:\nUSER \u2502 unicode_spinner = [\"\u280b\", \"\u2819\", \"\u2839\", \"\u2838\", \"\u283c\", \"\u2834\", \"\u2826\", \"\u2827\", \"\u2807\", \"\u280f\"]\nUSER \u22ee...\nUSER \u2502 def step(self):\nUSER \u22ee...\nUSER \u2502 def end(self):\nUSER \u22ee...\nUSER \u2502def check_pip_install_extra(io, module, prompt, pip_install_cmd, self_update=False):\nUSER \u22ee...\nUSER \u2502def printable_shell_command(cmd_list):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/voice.py:\nUSER \u22ee...\nUSER \u2502class SoundDeviceError(Exception):\nUSER \u22ee...\nUSER \u2502class Voice:\nUSER \u2502 max_rms = 0\nUSER \u22ee...\nUSER \u2502 def record_and_transcribe(self, history=None, language=None):\nUSER \u22ee...\nUSER \u2502 def raw_record_and_transcribe(self, history, language):\nUSER \u22ee...\nUSER \nUSER aider/watch.py:\nUSER \u22ee...\nUSER \u2502def load_gitignores(gitignore_paths: list[Path]) -> Optional[PathSpec]:\nUSER \u22ee...\nUSER \u2502class FileWatcher:\nUSER \u2502 \"\"\"Watches source files for changes and AI comments\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def start(self):\nUSER \u22ee...\nUSER \u2502 def stop(self):\nUSER \u22ee...\nUSER \u2502 def process_changes(self):\nUSER \u22ee...\nUSER \u2502 def get_ai_comments(self, filepath):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/code-in-json-benchmark.js:\nUSER \u22ee...\nUSER \u2502 function getAspectRatio() {\nUSER \u2502 var width = chartContainer.offsetWidth;\nUSER \u2502 // Gradually change aspect ratio from 2 (landscape) to 1 (square)\nUSER \u2502 return Math.max(1, Math.min(2, width / 300));\nUSER \u22ee...\nUSER \u2502 function resizeChart() {\nUSER \u2502 chart.options.aspectRatio = getAspectRatio();\nUSER \u2502 chart.resize();\nUSER \u22ee...\nUSER \u2502function createStripedCanvas(isStrict) {\nUSER \u2502 const patternCanvas = document.createElement('canvas');\nUSER \u2502 const patternContext = patternCanvas.getContext('2d');\nUSER \u2502 const size = 10;\nUSER \u2502 patternCanvas.width = size;\nUSER \u2502 patternCanvas.height = size;\nUSER \u2502\nUSER \u2502 patternContext.fillStyle = 'rgba(255, 99, 132, 0.8)';\nUSER \u2502 patternContext.fillRect(0, 0, size, size);\nUSER \u2502\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/code-in-json-syntax.js:\nUSER \u22ee...\nUSER \u2502 function getAspectRatio() {\nUSER \u2502 var width = chartContainer.offsetWidth;\nUSER \u2502 // Gradually change aspect ratio from 2 (landscape) to 1 (square)\nUSER \u2502 return Math.max(1, Math.min(2, width / 300));\nUSER \u22ee...\nUSER \u2502 function resizeChart() {\nUSER \u2502 chart.options.aspectRatio = getAspectRatio();\nUSER \u2502 chart.resize();\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/leaderboard.js:\nUSER \u22ee...\nUSER \u2502 function updateChart() {\nUSER \u2502 var selectedRows = document.querySelectorAll('tr.selected');\nUSER \u2502 var showAll = selectedRows.length === 0;\nUSER \u2502\nUSER \u2502 displayedData = [];\nUSER \u2502 leaderboardData.labels = [];\nUSER \u2502 leaderboardData.datasets[0].data = [];\nUSER \u2502\nUSER \u2502 allData.forEach(function(row, index) {\nUSER \u2502 var rowElement = document.getElementById('edit-row-' + index);\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/quant-chart.js:\nUSER \u22ee...\nUSER \u2502 function updateChart(filterText) {\nUSER \u2502 var filteredData = allData.filter(row => \nUSER \u2502 row.model.toLowerCase().includes(filterText.toLowerCase())\nUSER \u2502 );\nUSER \u2502 \nUSER \u2502 var chartData = {\nUSER \u2502 labels: filteredData.map(row => row.model),\nUSER \u2502 datasets: [{\nUSER \u2502 label: 'Percent completed correctly',\nUSER \u2502 data: filteredData.map(row => row.pass_rate_2),\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/qwq-chart.js:\nUSER \u22ee...\nUSER \u2502 function updateChart(filterText) {\nUSER \u2502 var filteredData = allData.filter(row => \nUSER \u2502 row.model.toLowerCase().includes(filterText.toLowerCase())\nUSER \u2502 );\nUSER \u2502 \nUSER \u2502 var chartData = {\nUSER \u2502 labels: filteredData.map(row => row.model),\nUSER \u2502 datasets: [{\nUSER \u2502 data: filteredData.map(row => row.pass_rate_2),\nUSER \u2502 backgroundColor: filteredData.map(row => \nUSER \u22ee...\nUSER \nUSER benchmark/benchmark.py:\nUSER \u22ee...\nUSER \u2502@app.command()\nUSER \u2502def main(\nUSER \u2502 dirnames: Optional[List[str]] = typer.Argument(None, help=\"Directory names\"),\nUSER \u2502 graphs: bool = typer.Option(False, \"--graphs\", help=\"Generate graphs\"),\nUSER \u2502 model: str = typer.Option(\"gpt-3.5-turbo\", \"--model\", \"-m\", help=\"Model name\"),\nUSER \u2502 sleep: float = typer.Option(\nUSER \u2502 0, \"--sleep\", help=\"Sleep seconds between tests when single threaded\"\nUSER \u2502 ),\nUSER \u2502 languages: str = typer.Option(\nUSER \u2502 None, \"--languages\", \"-l\", help=\"Only run tests for specific languages (comma separated)\"\nUSER \u2502 ),\nUSER \u22ee...\nUSER \u2502def load_results(dirname, stats_languages=None):\nUSER \u22ee...\nUSER \u2502def summarize_results(dirname, stats_languages=None):\nUSER \u2502 all_results = load_results(dirname, stats_languages)\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def show(stat, red=\"red\"):\nUSER \u22ee...\nUSER \u2502def cleanup_test_output(output, testdir):\nUSER \u22ee...\nUSER \nUSER benchmark/over_time.py:\nUSER \u22ee...\nUSER \u2502class BenchmarkPlotter:\nUSER \u2502 LABEL_FONT_SIZE = 16\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def load_data(self, yaml_file: str) -> List[ModelData]:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER benchmark/problem_stats.py:\nUSER \u22ee...\nUSER \u2502def load_results(dirname):\nUSER \u22ee...\nUSER \nUSER benchmark/refactor_tools.py:\nUSER \u22ee...\nUSER \u2502class ParentNodeTransformer(ast.NodeTransformer):\nUSER \u2502 \"\"\"\nUSER \u2502 This transformer sets the 'parent' attribute on each node.\nUSER \u22ee...\nUSER \u2502 def generic_visit(self, node):\nUSER \u22ee...\nUSER \u2502def main(paths):\nUSER \u22ee...\nUSER \nUSER benchmark/rungrid.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \u2502def run(dirname, model, edit_format):\nUSER \u22ee...\nUSER \nUSER benchmark/swe_bench.py:\nUSER \u22ee...\nUSER \u2502def plot_swe_bench(data_file, is_lite):\nUSER \u22ee...\nUSER \nUSER scripts/blame.py:\nUSER \u22ee...\nUSER \u2502def run(cmd):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/issues.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/my_models.py:\nUSER \u22ee...\nUSER \u2502def collect_model_stats(n_lines=1000):\nUSER \u22ee...\nUSER \u2502def format_text_table(model_stats):\nUSER \u22ee...\nUSER \nUSER scripts/update-history.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/versionbump.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/yank-old-versions.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER tests/basic/test_sanity_check_repo.py:\nUSER \u22ee...\nUSER \u2502def mock_repo_wrapper(repo_obj, git_repo_error=None):\nUSER \u22ee...\nUSER \nUSER tests/basic/test_watch.py:\nUSER \u22ee...\nUSER \u2502def test_ai_comment_pattern():\nUSER \u2502 # Create minimal IO and Coder instances for testing\nUSER \u2502 class MinimalCoder:\nUSER \u2502 def __init__(self, io):\nUSER \u2502 self.io = io\nUSER \u2502 self.root = \".\"\nUSER \u2502 self.abs_fnames = set()\nUSER \u2502\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/c/test.c:\nUSER \u22ee...\nUSER \u2502int main() {\nUSER \u2502 printf(\"Hello, World!\\n\");\nUSER \u2502 return 0;\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/cpp/test.cpp:\nUSER \u22ee...\nUSER \u2502int main() {\nUSER \u2502 std::cout << \"Hello, World!\" << std::endl;\nUSER \u2502 return 0;\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/csharp/test.cs:\nUSER \u22ee...\nUSER \u2502namespace Greetings {\nUSER \u2502 public interface IGreeter {\nUSER \u2502 string Greet(string name);\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public class Person {\nUSER \u2502 public string Name { get; set; }\nUSER \u2502 public int Age { get; set; }\nUSER \u2502\nUSER \u2502 public Person(string name, int age) {\nUSER \u2502 Name = name;\nUSER \u2502 Age = age;\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502 public class FormalGreeter : IGreeter {\nUSER \u2502 private const string PREFIX = \"Good day\";\nUSER \u2502 private static readonly int MAX_AGE = 150;\nUSER \u2502\nUSER \u2502 public string Greet(string name) {\nUSER \u2502 return $\"{PREFIX}, {name}!\";\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public string GreetPerson(Person person) {\nUSER \u2502 return $\"{PREFIX}, {person.Name} ({person.Age})!\";\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elisp/test.el:\nUSER \u22ee...\nUSER \u2502(defun create-formal-greeter ()\nUSER \u22ee...\nUSER \u2502(defun main ()\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elixir/test.ex:\nUSER \u2502defmodule Greeter do\nUSER \u2502 def hello(name) do\nUSER \u2502 IO.puts(\"Hello, #{name}!\")\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elm/test.elm:\nUSER \u22ee...\nUSER \u2502type Greeting\nUSER \u2502 = Formal\nUSER \u22ee...\nUSER \u2502greet style person =\nUSER \u2502 let\nUSER \u2502 prefix =\nUSER \u22ee...\nUSER \u2502defaultPerson =\nUSER \u22ee...\nUSER \u2502main =\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/go/test.go:\nUSER \u22ee...\nUSER \u2502type Person struct {\nUSER \u2502 Name string\nUSER \u2502 Age int\nUSER \u22ee...\nUSER \u2502type Greeter interface {\nUSER \u2502 Greet(p Person) string\nUSER \u22ee...\nUSER \u2502type FormalGreeter struct {\nUSER \u2502 Prefix string\nUSER \u22ee...\nUSER \u2502)\nUSER \u2502\nUSER \u2502func (g FormalGreeter) Greet(p Person) string {\nUSER \u2502 return fmt.Sprintf(\"%s, %s! You are %d years old.\",\nUSER \u2502 g.Prefix, p.Name, p.Age)\nUSER \u2502}\nUSER \u2502\nUSER \u2502func NewFormalGreeter() *FormalGreeter {\nUSER \u2502 return &FormalGreeter{Prefix: \"Good day\"}\nUSER \u2502}\nUSER \u2502\nUSER \u2502func main() {\nUSER \u2502 greeter := NewFormalGreeter()\nUSER \u2502 person := Person{Name: DefaultName, Age: 42}\nUSER \u2502 fmt.Println(greeter.Greet(person))\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/java/test.java:\nUSER \u2502public interface Greeting {\nUSER \u2502 String greet(String name);\nUSER \u22ee...\nUSER \u2502public class Test implements Greeting {\nUSER \u2502 private String prefix = \"Hello\";\nUSER \u2502\nUSER \u2502 public String greet(String name) {\nUSER \u2502 return prefix + \", \" + name + \"!\";\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public static void main(String[] args) {\nUSER \u2502 Test greeter = new Test();\nUSER \u2502 System.out.println(greeter.greet(\"World\"));\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/javascript/test.js:\nUSER \u22ee...\nUSER \u2502class Person {\nUSER \u2502 constructor(name) {\nUSER \u2502 this.name = name;\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 sayHello() {\nUSER \u2502 return `Hello, ${this.name}!`;\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502function greet(person) {\nUSER \u2502 return person.sayHello();\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/kotlin/test.kt:\nUSER \u2502interface Greeting {\nUSER \u2502 fun greet(name: String): String\nUSER \u22ee...\nUSER \u2502class Test : Greeting {\nUSER \u2502 private val prefix = \"Hello\"\nUSER \u2502\nUSER \u2502 override fun greet(name: String): String {\nUSER \u2502 return \"$prefix, $name!\"\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502fun main(args: Array) {\nUSER \u2502 val greeter = Test()\nUSER \u2502 println(greeter.greet(\"World\"))\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ocaml/test.ml:\nUSER \u22ee...\nUSER \u2502module Greeter = struct\nUSER \u2502 type person = {\nUSER \u2502 name: string;\nUSER \u2502 age: int\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 let create_person name age =\nUSER \u2502 {name; age}\nUSER \u2502\nUSER \u2502 let greet person =\nUSER \u2502 Printf.printf \"Hello, %s! You are %d years old.\\n\"\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/php/test.php:\nUSER \u22ee...\nUSER \u2502function greet($name) {\nUSER \u2502 echo \"Hello, $name!\";\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/python/test.py:\nUSER \u22ee...\nUSER \u2502class Person:\nUSER \u2502 \"\"\"A class representing a person.\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def greet(self, formal: bool = False) -> str:\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ql/test.ql:\nUSER \u2502predicate greet(string name) {\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ruby/test.rb:\nUSER \u2502def greet(name)\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/rust/test.rs:\nUSER \u22ee...\nUSER \u2502trait Greeting {\nUSER \u2502 fn greet(&self) -> String;\nUSER \u22ee...\nUSER \u2502struct Person {\nUSER \u2502 name: String,\nUSER \u2502 age: u32,\nUSER \u22ee...\nUSER \u2502impl Greeting for Person {\nUSER \u2502 fn greet(&self) -> String {\nUSER \u2502 format!(\"Hello, {}! You are {} years old.\", self.name, self.age)\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502fn main() {\nUSER \u2502 let person = Person::new(DEFAULT_NAME.to_string(), 30);\nUSER \u2502 println!(\"{}\", person.greet());\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/typescript/test.ts:\nUSER \u2502function greet(name: string): void {\nUSER \u22ee...\nUSER \nUSER tests/fixtures/sample-code-base/sample.js:\nUSER \u22ee...\nUSER \u2502function greet(name) {\nUSER \u2502 return `Hello, ${name}!`;\nUSER \u22ee...\nUSER \u2502function calculateCircleArea(radius) {\nUSER \u2502 return Math.PI * radius * radius;\nUSER \u22ee...\nUSER \u2502function isPrime(number) {\nUSER \u2502 if (number <= 1) return false;\nUSER \u2502 for (let i = 2; i <= Math.sqrt(number); i++) {\nUSER \u2502 if (number % i === 0) return false;\nUSER \u2502 }\nUSER \u2502 return true;\nUSER \u22ee...\nUSER \u2502function reverseString(str) {\nUSER \u2502 return str.split('').reverse().join('');\nUSER \u22ee...\nUSER \u2502function getRandomNumber(min, max) {\nUSER \u2502 return Math.floor(Math.random() * (max - min + 1)) + min;\nUSER \u22ee...\nUSER \u2502function filterEvenNumbers(numbers) {\nUSER \u2502 return numbers.filter(num => num % 2 !== 0);\nUSER \u22ee...\nUSER \u2502function factorial(n) {\nUSER \u2502 if (n === 0 || n === 1) return 1;\nUSER \u2502 return n * factorial(n - 1);\nUSER \u22ee...\nUSER \nUSER tests/fixtures/sample-code-base/sample.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\n-------\nASSISTANT Ok, I won't try and edit those files without asking first.\n-------\nUSER Don't try and edit any existing code without asking me to add the files to the chat!\nUSER Tell me which files in my repo are the most likely to **need changes** to solve the requests I make, and then stop so I can add them to the chat.\nUSER Only include the files that are most likely to actually need to be edited.\nUSER Don't include files that might contain relevant context, just files that will need to be changed.\n-------\nASSISTANT Ok, based on your requests I will suggest which files need to be edited and then stop and wait for your approval.\n-------\nUSER hi\n-------\nUSER hi\n-------\nSYSTEM # *SEARCH/REPLACE block* Rules:\nSYSTEM \nSYSTEM Every *SEARCH/REPLACE block* must use this format:\nSYSTEM 1. The *FULL* file path alone on a line, verbatim. No bold asterisks, no quotes around it, no escaping of characters, etc.\nSYSTEM 2. The opening fence and code language, eg: ```python\nSYSTEM 3. The start of search block: <<<<<<< SEARCH\nSYSTEM 4. A contiguous chunk of lines to search for in the existing source code\nSYSTEM 5. The dividing line: =======\nSYSTEM 6. The lines to replace into the source code\nSYSTEM 7. The end of the replace block: >>>>>>> REPLACE\nSYSTEM 8. The closing fence: ```\nSYSTEM \nSYSTEM Use the *FULL* file path, as shown to you by the user.\nSYSTEM \nSYSTEM Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.\nSYSTEM 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.\nSYSTEM \nSYSTEM *SEARCH/REPLACE* blocks will *only* replace the first match occurrence.\nSYSTEM Including multiple unique *SEARCH/REPLACE* blocks if needed.\nSYSTEM Include enough lines in each SEARCH section to uniquely match each set of lines that need to change.\nSYSTEM \nSYSTEM Keep *SEARCH/REPLACE* blocks concise.\nSYSTEM Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.\nSYSTEM Include just the changing lines, and a few surrounding lines if needed for uniqueness.\nSYSTEM Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.\nSYSTEM \nSYSTEM Only create *SEARCH/REPLACE* blocks for files that the user has added to the chat!\nSYSTEM \nSYSTEM To move code within a file, use 2 *SEARCH/REPLACE* blocks: 1 to delete it from its current location, 1 to insert it in the new location.\nSYSTEM \nSYSTEM Pay attention to which filenames the user wants you to edit, especially if they are asking you to create a new file.\nSYSTEM \nSYSTEM If you want to put code in a new file, use a *SEARCH/REPLACE block* with:\nSYSTEM - A new file path, including dir name if needed\nSYSTEM - An empty `SEARCH` section\nSYSTEM - The new file's contents in the `REPLACE` section\nSYSTEM \nSYSTEM To rename files which have been added to the chat, use shell commands at the end of your response.\nSYSTEM \nSYSTEM If the user just says something like \"ok\" or \"go ahead\" or \"do that\" they probably want you to make SEARCH/REPLACE blocks for the code changes you just proposed.\nSYSTEM The user will say when they've applied your edits. If they haven't explicitly confirmed the edits have been applied, they probably want proper SEARCH/REPLACE blocks.\nSYSTEM \nSYSTEM \nSYSTEM ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!\nSYSTEM \nSYSTEM Examples of when to suggest shell commands:\nSYSTEM \nSYSTEM - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.\nSYSTEM - If you changed a CLI program, suggest the command to run it to see the new behavior.\nSYSTEM - If you added a test, suggest how to run it with the testing tool used by the project.\nSYSTEM - Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.\nSYSTEM - If your code changes add new dependencies, suggest the command to install them.\nSYSTEM - Etc.\nSYSTEM "}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566712}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566786}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566786}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566794}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566797}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566797}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566803}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 89277, "completion_tokens": 0, "total_tokens": 89277, "cost": 0.012498780000000001, "total_cost": 0.012498780000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566805}
+{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566812}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566813}
+{"event": "message_send_exception", "properties": {"exception": "Messages don't properly alternate user/assistant:\n\n-------\nSYSTEM Act as an expert software developer.\nSYSTEM Always use best practices when coding.\nSYSTEM Respect and use existing conventions, libraries, etc that are already present in the code base.\nSYSTEM \nSYSTEM Take requests for changes to the supplied code.\nSYSTEM If the request is ambiguous, ask questions.\nSYSTEM \nSYSTEM Always reply to the user in the same language they are using.\nSYSTEM \nSYSTEM Once you understand the request you MUST:\nSYSTEM \nSYSTEM 1. Decide if you need to propose *SEARCH/REPLACE* edits to any files that haven't been added to the chat. You can create new files without asking!\nSYSTEM \nSYSTEM But if you need to propose edits to existing files not already added to the chat, you *MUST* tell the user their full path names and ask them to *add the files to the chat*.\nSYSTEM End your reply and wait for their approval.\nSYSTEM You can keep asking if you then decide you need to edit more files.\nSYSTEM \nSYSTEM 2. Think step-by-step and explain the needed changes in a few short sentences.\nSYSTEM \nSYSTEM 3. Describe each change with a *SEARCH/REPLACE block* per the examples below.\nSYSTEM \nSYSTEM All changes to files must use this *SEARCH/REPLACE block* format.\nSYSTEM ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!\nSYSTEM \nSYSTEM 4. *Concisely* suggest any shell commands the user might want to run in ```bash blocks.\nSYSTEM \nSYSTEM Just suggest shell commands this way, not example code.\nSYSTEM Only suggest complete shell commands that are ready to execute, without placeholders.\nSYSTEM Only suggest at most a few shell commands at a time, not more than 1-3, one per line.\nSYSTEM Do not suggest multi-line shell commands.\nSYSTEM All shell commands will run from the root directory of the user's project.\nSYSTEM \nSYSTEM Use the appropriate shell based on the user's system info:\nSYSTEM - Platform: macOS-15.2-x86_64-i386-64bit\nSYSTEM - Shell: SHELL=/usr/local/Cellar/bash/5.2.26/bin/bash\nSYSTEM - Language: en_US\nSYSTEM - Current date: 2025-01-22\nSYSTEM - The user is operating inside a git repository\nSYSTEM - The user's pre-commit runs these lint commands, don't suggest running them:\nSYSTEM - /Users/gauthier/Projects/aider/tmp.lint.sh\nSYSTEM \nSYSTEM Examples of when to suggest shell commands:\nSYSTEM \nSYSTEM - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.\nSYSTEM - If you changed a CLI program, suggest the command to run it to see the new behavior.\nSYSTEM - If you added a test, suggest how to run it with the testing tool used by the project.\nSYSTEM - Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.\nSYSTEM - If your code changes add new dependencies, suggest the command to install them.\nSYSTEM - Etc.\nSYSTEM \nSYSTEM \nSYSTEM # Example conversations:\nSYSTEM \nSYSTEM ## USER: Change get_factorial() to use math.factorial\nSYSTEM \nSYSTEM ## ASSISTANT: To make this change we need to modify `mathweb/flask/app.py` to:\nSYSTEM \nSYSTEM 1. Import the math package.\nSYSTEM 2. Remove the existing factorial() function.\nSYSTEM 3. Update get_factorial() to call math.factorial instead.\nSYSTEM \nSYSTEM Here are the *SEARCH/REPLACE* blocks:\nSYSTEM \nSYSTEM mathweb/flask/app.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM from flask import Flask\nSYSTEM =======\nSYSTEM import math\nSYSTEM from flask import Flask\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM mathweb/flask/app.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM def factorial(n):\nSYSTEM \"compute factorial\"\nSYSTEM \nSYSTEM if n == 0:\nSYSTEM return 1\nSYSTEM else:\nSYSTEM return n * factorial(n-1)\nSYSTEM \nSYSTEM =======\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM mathweb/flask/app.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM return str(factorial(n))\nSYSTEM =======\nSYSTEM return str(math.factorial(n))\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM \nSYSTEM ## USER: Refactor hello() into its own file.\nSYSTEM \nSYSTEM ## ASSISTANT: To make this change we need to modify `main.py` and make a new file `hello.py`:\nSYSTEM \nSYSTEM 1. Make a new hello.py file with hello() in it.\nSYSTEM 2. Remove hello() from main.py and replace it with an import.\nSYSTEM \nSYSTEM Here are the *SEARCH/REPLACE* blocks:\nSYSTEM \nSYSTEM hello.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM =======\nSYSTEM def hello():\nSYSTEM \"print a greeting\"\nSYSTEM \nSYSTEM print(\"hello\")\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM \nSYSTEM main.py\nSYSTEM ```python\nSYSTEM <<<<<<< SEARCH\nSYSTEM def hello():\nSYSTEM \"print a greeting\"\nSYSTEM \nSYSTEM print(\"hello\")\nSYSTEM =======\nSYSTEM from hello import hello\nSYSTEM >>>>>>> REPLACE\nSYSTEM ```\nSYSTEM # *SEARCH/REPLACE block* Rules:\nSYSTEM \nSYSTEM Every *SEARCH/REPLACE block* must use this format:\nSYSTEM 1. The *FULL* file path alone on a line, verbatim. No bold asterisks, no quotes around it, no escaping of characters, etc.\nSYSTEM 2. The opening fence and code language, eg: ```python\nSYSTEM 3. The start of search block: <<<<<<< SEARCH\nSYSTEM 4. A contiguous chunk of lines to search for in the existing source code\nSYSTEM 5. The dividing line: =======\nSYSTEM 6. The lines to replace into the source code\nSYSTEM 7. The end of the replace block: >>>>>>> REPLACE\nSYSTEM 8. The closing fence: ```\nSYSTEM \nSYSTEM Use the *FULL* file path, as shown to you by the user.\nSYSTEM \nSYSTEM Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.\nSYSTEM 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.\nSYSTEM \nSYSTEM *SEARCH/REPLACE* blocks will *only* replace the first match occurrence.\nSYSTEM Including multiple unique *SEARCH/REPLACE* blocks if needed.\nSYSTEM Include enough lines in each SEARCH section to uniquely match each set of lines that need to change.\nSYSTEM \nSYSTEM Keep *SEARCH/REPLACE* blocks concise.\nSYSTEM Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.\nSYSTEM Include just the changing lines, and a few surrounding lines if needed for uniqueness.\nSYSTEM Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.\nSYSTEM \nSYSTEM Only create *SEARCH/REPLACE* blocks for files that the user has added to the chat!\nSYSTEM \nSYSTEM To move code within a file, use 2 *SEARCH/REPLACE* blocks: 1 to delete it from its current location, 1 to insert it in the new location.\nSYSTEM \nSYSTEM Pay attention to which filenames the user wants you to edit, especially if they are asking you to create a new file.\nSYSTEM \nSYSTEM If you want to put code in a new file, use a *SEARCH/REPLACE block* with:\nSYSTEM - A new file path, including dir name if needed\nSYSTEM - An empty `SEARCH` section\nSYSTEM - The new file's contents in the `REPLACE` section\nSYSTEM \nSYSTEM To rename files which have been added to the chat, use shell commands at the end of your response.\nSYSTEM \nSYSTEM If the user just says something like \"ok\" or \"go ahead\" or \"do that\" they probably want you to make SEARCH/REPLACE blocks for the code changes you just proposed.\nSYSTEM The user will say when they've applied your edits. If they haven't explicitly confirmed the edits have been applied, they probably want proper SEARCH/REPLACE blocks.\nSYSTEM \nSYSTEM \nSYSTEM ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!\nSYSTEM \nSYSTEM Examples of when to suggest shell commands:\nSYSTEM \nSYSTEM - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.\nSYSTEM - If you changed a CLI program, suggest the command to run it to see the new behavior.\nSYSTEM - If you added a test, suggest how to run it with the testing tool used by the project.\nSYSTEM - Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.\nSYSTEM - If your code changes add new dependencies, suggest the command to install them.\nSYSTEM - Etc.\nSYSTEM \n-------\nUSER Here are summaries of some files present in my git repository.\nUSER Do not propose changes to these files, treat them as *read-only*.\nUSER If you need to edit any of these files, ask me to *add them to the chat* first.\nUSER \nUSER aider/analytics.py:\nUSER \u22ee...\nUSER \u2502def compute_hex_threshold(percent):\nUSER \u22ee...\nUSER \u2502def is_uuid_in_percentage(uuid_str, percent):\nUSER \u22ee...\nUSER \u2502class Analytics:\nUSER \u2502 # providers\nUSER \u2502 mp = None\nUSER \u22ee...\nUSER \u2502 def disable(self, permanently):\nUSER \u22ee...\nUSER \u2502 def get_data_file_path(self):\nUSER \u22ee...\nUSER \u2502 def get_or_create_uuid(self):\nUSER \u22ee...\nUSER \u2502 def load_data(self):\nUSER \u22ee...\nUSER \u2502 def save_data(self):\nUSER \u22ee...\nUSER \u2502 def get_system_info(self):\nUSER \u22ee...\nUSER \u2502 def event(self, event_name, main_model=None, **kwargs):\nUSER \u22ee...\nUSER \nUSER aider/args.py:\nUSER \u22ee...\nUSER \u2502def get_parser(default_config_files, git_root):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/args_formatter.py:\nUSER \u22ee...\nUSER \u2502class DotEnvFormatter(argparse.HelpFormatter):\nUSER \u2502 def start_section(self, heading):\nUSER \u2502 res = \"\\n\\n\"\nUSER \u2502 res += \"#\" * (len(heading) + 3)\nUSER \u2502 res += f\"\\n# {heading}\"\nUSER \u22ee...\nUSER \u2502 def _format_usage(self, usage, actions, groups, prefix):\nUSER \u22ee...\nUSER \u2502class YamlHelpFormatter(argparse.HelpFormatter):\nUSER \u2502 def start_section(self, heading):\nUSER \u2502 res = \"\\n\\n\"\nUSER \u2502 res += \"#\" * (len(heading) + 3)\nUSER \u2502 res += f\"\\n# {heading}\"\nUSER \u22ee...\nUSER \u2502 def _format_usage(self, usage, actions, groups, prefix):\nUSER \u22ee...\nUSER \u2502class MarkdownHelpFormatter(argparse.HelpFormatter):\nUSER \u2502 def start_section(self, heading):\nUSER \u22ee...\nUSER \u2502 def _format_usage(self, usage, actions, groups, prefix):\nUSER \u22ee...\nUSER \nUSER aider/coders/architect_prompts.py:\nUSER \u22ee...\nUSER \u2502class ArchitectPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/ask_prompts.py:\nUSER \u22ee...\nUSER \u2502class AskPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/base_coder.py:\nUSER \u22ee...\nUSER \u2502class Coder:\nUSER \u2502 abs_fnames = None\nUSER \u22ee...\nUSER \u2502 @classmethod\nUSER \u2502 def create(\nUSER \u2502 self,\nUSER \u2502 main_model=None,\nUSER \u2502 edit_format=None,\nUSER \u2502 io=None,\nUSER \u2502 from_coder=None,\nUSER \u2502 summarize_from_coder=True,\nUSER \u2502 **kwargs,\nUSER \u22ee...\nUSER \u2502 def get_announcements(self):\nUSER \u22ee...\nUSER \u2502 def show_announcements(self):\nUSER \u22ee...\nUSER \u2502 def add_rel_fname(self, rel_fname):\nUSER \u22ee...\nUSER \u2502 def drop_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def abs_root_path(self, path):\nUSER \u22ee...\nUSER \u2502 def get_repo_map(self, force_refresh=False):\nUSER \u22ee...\nUSER \u2502 def run_stream(self, user_message):\nUSER \u22ee...\nUSER \u2502 def run(self, with_message=None, preproc=True):\nUSER \u22ee...\nUSER \u2502 def fmt_system_prompt(self, prompt):\nUSER \u22ee...\nUSER \u2502 def format_messages(self):\nUSER \u22ee...\nUSER \u2502 def get_multi_response_content(self, final=False):\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def get_inchat_relative_files(self):\nUSER \u22ee...\nUSER \u2502 def get_all_relative_files(self):\nUSER \u22ee...\nUSER \u2502 def allowed_to_edit(self, path):\nUSER \u22ee...\nUSER \u2502 def check_added_files(self):\nUSER \u22ee...\nUSER \u2502 def apply_updates(self):\nUSER \u22ee...\nUSER \u2502 def parse_partial_args(self):\nUSER \u22ee...\nUSER \nUSER aider/coders/base_prompts.py:\nUSER \u2502class CoderPrompts:\nUSER \u22ee...\nUSER \nUSER aider/coders/chat_chunks.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ChatChunks:\nUSER \u2502 system: List = field(default_factory=list)\nUSER \u22ee...\nUSER \u2502 def all_messages(self):\nUSER \u22ee...\nUSER \u2502 def add_cache_control(self, messages):\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_coder.py:\nUSER \u22ee...\nUSER \u2502def do_replace(fname, content, before_text, after_text, fence=None):\nUSER \u22ee...\nUSER \u2502def find_original_update_blocks(content, fence=DEFAULT_FENCE, valid_fnames=None):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_fenced_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditBlockFencedPrompts(EditBlockPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_func_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditBlockFunctionPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditBlockPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/editor_editblock_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditorEditBlockPrompts(EditBlockPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/editor_whole_prompts.py:\nUSER \u22ee...\nUSER \u2502class EditorWholeFilePrompts(WholeFilePrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/help_prompts.py:\nUSER \u22ee...\nUSER \u2502class HelpPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/search_replace.py:\nUSER \u22ee...\nUSER \u2502def try_strategy(texts, strategy, preproc):\nUSER \u22ee...\nUSER \u2502def read_text(fname):\nUSER \u22ee...\nUSER \u2502def main(dnames):\nUSER \u22ee...\nUSER \nUSER aider/coders/single_wholefile_func_prompts.py:\nUSER \u22ee...\nUSER \u2502class SingleWholeFileFunctionPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/udiff_coder.py:\nUSER \u22ee...\nUSER \u2502def do_replace(fname, content, hunk):\nUSER \u22ee...\nUSER \u2502def directly_apply_hunk(content, hunk):\nUSER \u22ee...\nUSER \u2502def hunk_to_before_after(hunk, lines=False):\nUSER \u22ee...\nUSER \nUSER aider/coders/wholefile_func_prompts.py:\nUSER \u22ee...\nUSER \u2502class WholeFileFunctionPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/wholefile_prompts.py:\nUSER \u22ee...\nUSER \u2502class WholeFilePrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/commands.py:\nUSER \u22ee...\nUSER \u2502class Commands:\nUSER \u2502 voice = None\nUSER \u22ee...\nUSER \u2502 def get_raw_completions(self, cmd):\nUSER \u22ee...\nUSER \u2502 def get_completions(self, cmd):\nUSER \u22ee...\nUSER \u2502 def get_commands(self):\nUSER \u22ee...\nUSER \u2502 def matching_commands(self, inp):\nUSER \u22ee...\nUSER \u2502 def run(self, inp):\nUSER \u22ee...\nUSER \u2502 def cmd_undo(self, args):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/copypaste.py:\nUSER \u22ee...\nUSER \u2502class ClipboardWatcher:\nUSER \u2502 \"\"\"Watches clipboard for changes and updates IO placeholder\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def start(self):\nUSER \u22ee...\nUSER \u2502 def stop(self):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/diffs.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \u2502def diff_partial_update(lines_orig, lines_updated, final=False, fname=None):\nUSER \u22ee...\nUSER \nUSER aider/dump.py:\nUSER \u22ee...\nUSER \u2502def cvt(s):\nUSER \u22ee...\nUSER \u2502def dump(*vals):\nUSER \u22ee...\nUSER \nUSER aider/editor.py:\nUSER \u22ee...\nUSER \u2502def print_status_message(success, message, style=None):\nUSER \u22ee...\nUSER \u2502def write_temp_file(\nUSER \u2502 input_data=\"\",\nUSER \u2502 suffix=None,\nUSER \u2502 prefix=None,\nUSER \u2502 dir=None,\nUSER \u22ee...\nUSER \u2502def get_environment_editor(default=None):\nUSER \u22ee...\nUSER \u2502def discover_editor(editor_override=None):\nUSER \u22ee...\nUSER \u2502def pipe_editor(input_data=\"\", suffix=None, editor=None):\nUSER \u22ee...\nUSER \nUSER aider/exceptions.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ExInfo:\nUSER \u22ee...\nUSER \u2502class LiteLLMExceptions:\nUSER \u2502 exceptions = dict()\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def _load(self, strict=False):\nUSER \u22ee...\nUSER \u2502 def exceptions_tuple(self):\nUSER \u22ee...\nUSER \u2502 def get_ex_info(self, ex):\nUSER \u22ee...\nUSER \nUSER aider/format_settings.py:\nUSER \u2502def scrub_sensitive_info(args, text):\nUSER \u22ee...\nUSER \nUSER aider/gui.py:\nUSER \u22ee...\nUSER \u2502class CaptureIO(InputOutput):\nUSER \u2502 lines = []\nUSER \u2502\nUSER \u2502 def tool_output(self, msg, log_only=False):\nUSER \u22ee...\nUSER \u2502 def tool_error(self, msg):\nUSER \u22ee...\nUSER \u2502 def tool_warning(self, msg):\nUSER \u22ee...\nUSER \u2502 def get_captured_lines(self):\nUSER \u22ee...\nUSER \u2502def search(text=None):\nUSER \u22ee...\nUSER \u2502class State:\nUSER \u2502 keys = set()\nUSER \u2502\nUSER \u2502 def init(self, key, val=None):\nUSER \u22ee...\nUSER \u2502@st.cache_resource\nUSER \u2502def get_state():\nUSER \u22ee...\nUSER \u2502@st.cache_resource\nUSER \u2502def get_coder():\nUSER \u22ee...\nUSER \u2502class GUI:\nUSER \u2502 prompt = None\nUSER \u22ee...\nUSER \u2502 def announce(self):\nUSER \u22ee...\nUSER \u2502 def show_edit_info(self, edit):\nUSER \u22ee...\nUSER \u2502 def add_undo(self, commit_hash):\nUSER \u22ee...\nUSER \u2502 def do_sidebar(self):\nUSER \u22ee...\nUSER \u2502 def do_add_to_chat(self):\nUSER \u22ee...\nUSER \u2502 def do_add_files(self):\nUSER \u22ee...\nUSER \u2502 def do_add_web_page(self):\nUSER \u22ee...\nUSER \u2502 def do_clear_chat_history(self):\nUSER \u22ee...\nUSER \u2502 def do_recent_msgs(self):\nUSER \u22ee...\nUSER \u2502 def do_messages_container(self):\nUSER \u22ee...\nUSER \u2502 def initialize_state(self):\nUSER \u22ee...\nUSER \u2502 def button(self, args, **kwargs):\nUSER \u22ee...\nUSER \u2502 def prompt_pending(self):\nUSER \u22ee...\nUSER \u2502 def process_chat(self):\nUSER \u22ee...\nUSER \u2502 def info(self, message, echo=True):\nUSER \u22ee...\nUSER \u2502 def do_web(self):\nUSER \u22ee...\nUSER \u2502 def do_undo(self, commit_hash):\nUSER \u22ee...\nUSER \u2502def gui_main():\nUSER \u22ee...\nUSER \nUSER aider/help.py:\nUSER \u22ee...\nUSER \u2502def get_package_files():\nUSER \u22ee...\nUSER \u2502def fname_to_url(filepath):\nUSER \u22ee...\nUSER \u2502def get_index():\nUSER \u22ee...\nUSER \nUSER aider/history.py:\nUSER \u22ee...\nUSER \u2502class ChatSummary:\nUSER \u2502 def __init__(self, models=None, max_tokens=1024):\nUSER \u2502 if not models:\nUSER \u2502 raise ValueError(\"At least one model must be provided\")\nUSER \u2502 self.models = models if isinstance(models, list) else [models]\nUSER \u2502 self.max_tokens = max_tokens\nUSER \u22ee...\nUSER \u2502 def too_big(self, messages):\nUSER \u22ee...\nUSER \u2502 def tokenize(self, messages):\nUSER \u22ee...\nUSER \u2502 def summarize(self, messages, depth=0):\nUSER \u22ee...\nUSER \u2502 def summarize_real(self, messages, depth=0):\nUSER \u22ee...\nUSER \u2502 def summarize_all(self, messages):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/io.py:\nUSER \u22ee...\nUSER \u2502class AutoCompleter(Completer):\nUSER \u2502 def __init__(\nUSER \u2502 self, root, rel_fnames, addable_rel_fnames, commands, encoding, abs_read_only_fnames=None\nUSER \u22ee...\nUSER \u2502 def tokenize(self):\nUSER \u22ee...\nUSER \u2502 def get_command_completions(self, document, complete_event, text, words):\nUSER \u22ee...\nUSER \u2502 def get_completions(self, document, complete_event):\nUSER \u22ee...\nUSER \u2502class InputOutput:\nUSER \u2502 num_error_outputs = 0\nUSER \u22ee...\nUSER \u2502 def _get_style(self):\nUSER \u22ee...\nUSER \u2502 def read_image(self, filename):\nUSER \u22ee...\nUSER \u2502 def read_text(self, filename, silent=False):\nUSER \u22ee...\nUSER \u2502 def write_text(self, filename, content, max_retries=5, initial_delay=0.1):\nUSER \u22ee...\nUSER \u2502 def rule(self):\nUSER \u22ee...\nUSER \u2502 def interrupt_input(self):\nUSER \u22ee...\nUSER \u2502 def get_input(\nUSER \u2502 self,\nUSER \u2502 root,\nUSER \u2502 rel_fnames,\nUSER \u2502 addable_rel_fnames,\nUSER \u2502 commands,\nUSER \u2502 abs_read_only_fnames=None,\nUSER \u2502 edit_format=None,\nUSER \u2502 ):\nUSER \u2502 self.rule()\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def suspend_to_bg(event):\nUSER \u22ee...\nUSER \u2502 def add_to_input_history(self, inp):\nUSER \u22ee...\nUSER \u2502 def get_input_history(self):\nUSER \u22ee...\nUSER \u2502 def display_user_input(self, inp):\nUSER \u22ee...\nUSER \u2502 def user_input(self, inp, log_only=True):\nUSER \u22ee...\nUSER \u2502 def offer_url(self, url, prompt=\"Open URL for more info?\", allow_never=True):\nUSER \u22ee...\nUSER \u2502 def confirm_ask(\nUSER \u2502 self,\nUSER \u2502 question,\nUSER \u2502 default=\"y\",\nUSER \u2502 subject=None,\nUSER \u2502 explicit_yes_required=False,\nUSER \u2502 group=None,\nUSER \u2502 allow_never=False,\nUSER \u22ee...\nUSER \u2502 def tool_error(self, message=\"\", strip=True):\nUSER \u22ee...\nUSER \u2502 def tool_warning(self, message=\"\", strip=True):\nUSER \u22ee...\nUSER \u2502 def tool_output(self, *messages, log_only=False, bold=False):\nUSER \u22ee...\nUSER \u2502 def print(self, message=\"\"):\nUSER \u22ee...\nUSER \u2502 def append_chat_history(self, text, linebreak=False, blockquote=False, strip=True):\nUSER \u22ee...\nUSER \u2502 def format_files_for_input(self, rel_fnames, rel_read_only_fnames):\nUSER \u22ee...\nUSER \u2502def get_rel_fname(fname, root):\nUSER \u22ee...\nUSER \nUSER aider/linter.py:\nUSER \u22ee...\nUSER \u2502class Linter:\nUSER \u2502 def __init__(self, encoding=\"utf-8\", root=None):\nUSER \u2502 self.encoding = encoding\nUSER \u2502 self.root = root\nUSER \u2502\nUSER \u2502 self.languages = dict(\nUSER \u2502 python=self.py_lint,\nUSER \u2502 )\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def run_cmd(self, cmd, rel_fname, code):\nUSER \u22ee...\nUSER \u2502 def lint(self, fname, cmd=None):\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class LintResult:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/llm.py:\nUSER \u22ee...\nUSER \u2502class LazyLiteLLM:\nUSER \u22ee...\nUSER \nUSER aider/main.py:\nUSER \u22ee...\nUSER \u2502def sanity_check_repo(repo, io):\nUSER \u22ee...\nUSER \u2502def main(argv=None, input=None, output=None, force_git_root=None, return_coder=False):\nUSER \u22ee...\nUSER \nUSER aider/mdstream.py:\nUSER \u22ee...\nUSER \u2502class MarkdownStream:\nUSER \u2502 \"\"\"Streaming markdown renderer that progressively displays content with a live updating window.\nUSER \u2502\nUSER \u2502 Uses rich.console and rich.live to render markdown content with smooth scrolling\nUSER \u2502 and partial updates. Maintains a sliding window of visible content while streaming\nUSER \u2502 in new markdown text.\nUSER \u22ee...\nUSER \u2502 def update(self, text, final=False):\nUSER \u22ee...\nUSER \nUSER aider/models.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ModelSettings:\nUSER \u22ee...\nUSER \u2502class ModelInfoManager:\nUSER \u2502 MODEL_INFO_URL = (\nUSER \u2502 \"https://raw.githubusercontent.com/BerriAI/litellm/main/\"\nUSER \u2502 \"model_prices_and_context_window.json\"\nUSER \u22ee...\nUSER \u2502 def get_model_from_cached_json_db(self, model):\nUSER \u22ee...\nUSER \u2502 def get_model_info(self, model):\nUSER \u22ee...\nUSER \u2502class Model(ModelSettings):\nUSER \u2502 def __init__(self, model, weak_model=None, editor_model=None, editor_edit_format=None):\nUSER \u2502 # Map any alias to its canonical name\nUSER \u2502 model = MODEL_ALIASES.get(model, model)\nUSER \u2502\nUSER \u2502 self.name = model\nUSER \u2502\nUSER \u2502 self.max_chat_history_tokens = 1024\nUSER \u2502 self.weak_model = None\nUSER \u2502 self.editor_model = None\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def get_model_info(self, model):\nUSER \u22ee...\nUSER \u2502 def token_count(self, messages):\nUSER \u22ee...\nUSER \u2502def validate_variables(vars):\nUSER \u22ee...\nUSER \u2502def sanity_check_model(io, model):\nUSER \u22ee...\nUSER \u2502def fuzzy_match_models(name):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/repo.py:\nUSER \u22ee...\nUSER \u2502class GitRepo:\nUSER \u2502 repo = None\nUSER \u22ee...\nUSER \u2502 def commit(self, fnames=None, context=None, message=None, aider_edits=False):\nUSER \u22ee...\nUSER \u2502 def get_commit_message(self, diffs, context):\nUSER \u22ee...\nUSER \u2502 def get_diffs(self, fnames=None):\nUSER \u22ee...\nUSER \u2502 def diff_commits(self, pretty, from_commit, to_commit):\nUSER \u22ee...\nUSER \u2502 def get_tracked_files(self):\nUSER \u22ee...\nUSER \u2502 def normalize_path(self, path):\nUSER \u22ee...\nUSER \u2502 def refresh_aider_ignore(self):\nUSER \u22ee...\nUSER \u2502 def git_ignored_file(self, path):\nUSER \u22ee...\nUSER \u2502 def ignored_file(self, fname):\nUSER \u22ee...\nUSER \u2502 def ignored_file_raw(self, fname):\nUSER \u22ee...\nUSER \u2502 def path_in_repo(self, path):\nUSER \u22ee...\nUSER \u2502 def abs_root_path(self, path):\nUSER \u22ee...\nUSER \u2502 def is_dirty(self, path=None):\nUSER \u22ee...\nUSER \u2502 def get_head_commit(self):\nUSER \u22ee...\nUSER \u2502 def get_head_commit_sha(self, short=False):\nUSER \u22ee...\nUSER \nUSER aider/repomap.py:\nUSER \u22ee...\nUSER \u2502class RepoMap:\nUSER \u2502 CACHE_VERSION = 3\nUSER \u22ee...\nUSER \u2502 def token_count(self, text):\nUSER \u22ee...\nUSER \u2502 def get_repo_map(\nUSER \u2502 self,\nUSER \u2502 chat_files,\nUSER \u2502 other_files,\nUSER \u2502 mentioned_fnames=None,\nUSER \u2502 mentioned_idents=None,\nUSER \u2502 force_refresh=False,\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def tags_cache_error(self, original_error=None):\nUSER \u22ee...\nUSER \u2502 def get_mtime(self, fname):\nUSER \u22ee...\nUSER \u2502 def get_ranked_tags_map(\nUSER \u2502 self,\nUSER \u2502 chat_fnames,\nUSER \u2502 other_fnames=None,\nUSER \u2502 max_map_tokens=None,\nUSER \u2502 mentioned_fnames=None,\nUSER \u2502 mentioned_idents=None,\nUSER \u2502 force_refresh=False,\nUSER \u22ee...\nUSER \u2502def get_scm_fname(lang):\nUSER \u22ee...\nUSER \nUSER aider/report.py:\nUSER \u22ee...\nUSER \u2502def report_github_issue(issue_text, title=None, confirm=True):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/run_cmd.py:\nUSER \u22ee...\nUSER \u2502def run_cmd(command, verbose=False, error_print=None, cwd=None):\nUSER \u22ee...\nUSER \u2502def get_windows_parent_process_name():\nUSER \u22ee...\nUSER \u2502def run_cmd_subprocess(command, verbose=False, cwd=None, encoding=sys.stdout.encoding):\nUSER \u22ee...\nUSER \u2502def run_cmd_pexpect(command, verbose=False, cwd=None):\nUSER \u22ee...\nUSER \nUSER aider/scrape.py:\nUSER \u22ee...\nUSER \u2502class Scraper:\nUSER \u2502 pandoc_available = None\nUSER \u22ee...\nUSER \u2502 def scrape(self, url):\nUSER \u22ee...\nUSER \u2502def main(url):\nUSER \u22ee...\nUSER \nUSER aider/sendchat.py:\nUSER \u22ee...\nUSER \u2502def sanity_check_messages(messages):\nUSER \u22ee...\nUSER \u2502def send_completion(\nUSER \u2502 model_name,\nUSER \u2502 messages,\nUSER \u2502 functions,\nUSER \u2502 stream,\nUSER \u2502 temperature=0,\nUSER \u2502 extra_params=None,\nUSER \u22ee...\nUSER \u2502def simple_send_with_retries(model, messages):\nUSER \u22ee...\nUSER \nUSER aider/special.py:\nUSER \u22ee...\nUSER \u2502def is_important(file_path):\nUSER \u22ee...\nUSER \u2502def filter_important_files(file_paths):\nUSER \u22ee...\nUSER \nUSER aider/utils.py:\nUSER \u22ee...\nUSER \u2502class IgnorantTemporaryDirectory:\nUSER \u2502 def __init__(self):\nUSER \u2502 if sys.version_info >= (3, 10):\nUSER \u2502 self.temp_dir = tempfile.TemporaryDirectory(ignore_cleanup_errors=True)\nUSER \u2502 else:\nUSER \u22ee...\nUSER \u2502 def cleanup(self):\nUSER \u22ee...\nUSER \u2502class GitTemporaryDirectory(ChdirTemporaryDirectory):\nUSER \u22ee...\nUSER \u2502def make_repo(path=None):\nUSER \u22ee...\nUSER \u2502def is_image_file(file_name):\nUSER \u22ee...\nUSER \u2502def safe_abs_path(res):\nUSER \u22ee...\nUSER \u2502def format_content(role, content):\nUSER \u22ee...\nUSER \u2502def format_messages(messages, title=None):\nUSER \u22ee...\nUSER \u2502def split_chat_history_markdown(text, include_tool=False):\nUSER \u2502 messages = []\nUSER \u22ee...\nUSER \u2502 def append_msg(role, lines):\nUSER \u22ee...\nUSER \u2502def get_pip_install(args):\nUSER \u22ee...\nUSER \u2502def run_install(cmd):\nUSER \u22ee...\nUSER \u2502class Spinner:\nUSER \u2502 unicode_spinner = [\"\u280b\", \"\u2819\", \"\u2839\", \"\u2838\", \"\u283c\", \"\u2834\", \"\u2826\", \"\u2827\", \"\u2807\", \"\u280f\"]\nUSER \u22ee...\nUSER \u2502 def step(self):\nUSER \u22ee...\nUSER \u2502 def end(self):\nUSER \u22ee...\nUSER \u2502def check_pip_install_extra(io, module, prompt, pip_install_cmd, self_update=False):\nUSER \u22ee...\nUSER \u2502def printable_shell_command(cmd_list):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/voice.py:\nUSER \u22ee...\nUSER \u2502class SoundDeviceError(Exception):\nUSER \u22ee...\nUSER \u2502class Voice:\nUSER \u2502 max_rms = 0\nUSER \u22ee...\nUSER \u2502 def record_and_transcribe(self, history=None, language=None):\nUSER \u22ee...\nUSER \u2502 def raw_record_and_transcribe(self, history, language):\nUSER \u22ee...\nUSER \nUSER aider/watch.py:\nUSER \u22ee...\nUSER \u2502def load_gitignores(gitignore_paths: list[Path]) -> Optional[PathSpec]:\nUSER \u22ee...\nUSER \u2502class FileWatcher:\nUSER \u2502 \"\"\"Watches source files for changes and AI comments\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def start(self):\nUSER \u22ee...\nUSER \u2502 def stop(self):\nUSER \u22ee...\nUSER \u2502 def process_changes(self):\nUSER \u22ee...\nUSER \u2502 def get_ai_comments(self, filepath):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/code-in-json-benchmark.js:\nUSER \u22ee...\nUSER \u2502 function getAspectRatio() {\nUSER \u2502 var width = chartContainer.offsetWidth;\nUSER \u2502 // Gradually change aspect ratio from 2 (landscape) to 1 (square)\nUSER \u2502 return Math.max(1, Math.min(2, width / 300));\nUSER \u22ee...\nUSER \u2502 function resizeChart() {\nUSER \u2502 chart.options.aspectRatio = getAspectRatio();\nUSER \u2502 chart.resize();\nUSER \u22ee...\nUSER \u2502function createStripedCanvas(isStrict) {\nUSER \u2502 const patternCanvas = document.createElement('canvas');\nUSER \u2502 const patternContext = patternCanvas.getContext('2d');\nUSER \u2502 const size = 10;\nUSER \u2502 patternCanvas.width = size;\nUSER \u2502 patternCanvas.height = size;\nUSER \u2502\nUSER \u2502 patternContext.fillStyle = 'rgba(255, 99, 132, 0.8)';\nUSER \u2502 patternContext.fillRect(0, 0, size, size);\nUSER \u2502\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/code-in-json-syntax.js:\nUSER \u22ee...\nUSER \u2502 function getAspectRatio() {\nUSER \u2502 var width = chartContainer.offsetWidth;\nUSER \u2502 // Gradually change aspect ratio from 2 (landscape) to 1 (square)\nUSER \u2502 return Math.max(1, Math.min(2, width / 300));\nUSER \u22ee...\nUSER \u2502 function resizeChart() {\nUSER \u2502 chart.options.aspectRatio = getAspectRatio();\nUSER \u2502 chart.resize();\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/leaderboard.js:\nUSER \u22ee...\nUSER \u2502 function updateChart() {\nUSER \u2502 var selectedRows = document.querySelectorAll('tr.selected');\nUSER \u2502 var showAll = selectedRows.length === 0;\nUSER \u2502\nUSER \u2502 displayedData = [];\nUSER \u2502 leaderboardData.labels = [];\nUSER \u2502 leaderboardData.datasets[0].data = [];\nUSER \u2502\nUSER \u2502 allData.forEach(function(row, index) {\nUSER \u2502 var rowElement = document.getElementById('edit-row-' + index);\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/quant-chart.js:\nUSER \u22ee...\nUSER \u2502 function updateChart(filterText) {\nUSER \u2502 var filteredData = allData.filter(row => \nUSER \u2502 row.model.toLowerCase().includes(filterText.toLowerCase())\nUSER \u2502 );\nUSER \u2502 \nUSER \u2502 var chartData = {\nUSER \u2502 labels: filteredData.map(row => row.model),\nUSER \u2502 datasets: [{\nUSER \u2502 label: 'Percent completed correctly',\nUSER \u2502 data: filteredData.map(row => row.pass_rate_2),\nUSER \u22ee...\nUSER \nUSER aider/website/_includes/qwq-chart.js:\nUSER \u22ee...\nUSER \u2502 function updateChart(filterText) {\nUSER \u2502 var filteredData = allData.filter(row => \nUSER \u2502 row.model.toLowerCase().includes(filterText.toLowerCase())\nUSER \u2502 );\nUSER \u2502 \nUSER \u2502 var chartData = {\nUSER \u2502 labels: filteredData.map(row => row.model),\nUSER \u2502 datasets: [{\nUSER \u2502 data: filteredData.map(row => row.pass_rate_2),\nUSER \u2502 backgroundColor: filteredData.map(row => \nUSER \u22ee...\nUSER \nUSER benchmark/benchmark.py:\nUSER \u22ee...\nUSER \u2502@app.command()\nUSER \u2502def main(\nUSER \u2502 dirnames: Optional[List[str]] = typer.Argument(None, help=\"Directory names\"),\nUSER \u2502 graphs: bool = typer.Option(False, \"--graphs\", help=\"Generate graphs\"),\nUSER \u2502 model: str = typer.Option(\"gpt-3.5-turbo\", \"--model\", \"-m\", help=\"Model name\"),\nUSER \u2502 sleep: float = typer.Option(\nUSER \u2502 0, \"--sleep\", help=\"Sleep seconds between tests when single threaded\"\nUSER \u2502 ),\nUSER \u2502 languages: str = typer.Option(\nUSER \u2502 None, \"--languages\", \"-l\", help=\"Only run tests for specific languages (comma separated)\"\nUSER \u2502 ),\nUSER \u22ee...\nUSER \u2502def load_results(dirname, stats_languages=None):\nUSER \u22ee...\nUSER \u2502def summarize_results(dirname, stats_languages=None):\nUSER \u2502 all_results = load_results(dirname, stats_languages)\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def show(stat, red=\"red\"):\nUSER \u22ee...\nUSER \u2502def cleanup_test_output(output, testdir):\nUSER \u22ee...\nUSER \nUSER benchmark/over_time.py:\nUSER \u22ee...\nUSER \u2502class BenchmarkPlotter:\nUSER \u2502 LABEL_FONT_SIZE = 16\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def load_data(self, yaml_file: str) -> List[ModelData]:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER benchmark/problem_stats.py:\nUSER \u22ee...\nUSER \u2502def load_results(dirname):\nUSER \u22ee...\nUSER \nUSER benchmark/refactor_tools.py:\nUSER \u22ee...\nUSER \u2502class ParentNodeTransformer(ast.NodeTransformer):\nUSER \u2502 \"\"\"\nUSER \u2502 This transformer sets the 'parent' attribute on each node.\nUSER \u22ee...\nUSER \u2502 def generic_visit(self, node):\nUSER \u22ee...\nUSER \u2502def main(paths):\nUSER \u22ee...\nUSER \nUSER benchmark/rungrid.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \u2502def run(dirname, model, edit_format):\nUSER \u22ee...\nUSER \nUSER benchmark/swe_bench.py:\nUSER \u22ee...\nUSER \u2502def plot_swe_bench(data_file, is_lite):\nUSER \u22ee...\nUSER \nUSER scripts/blame.py:\nUSER \u22ee...\nUSER \u2502def run(cmd):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/issues.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/my_models.py:\nUSER \u22ee...\nUSER \u2502def collect_model_stats(n_lines=1000):\nUSER \u22ee...\nUSER \u2502def format_text_table(model_stats):\nUSER \u22ee...\nUSER \nUSER scripts/update-history.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/versionbump.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/yank-old-versions.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER tests/basic/test_sanity_check_repo.py:\nUSER \u22ee...\nUSER \u2502def mock_repo_wrapper(repo_obj, git_repo_error=None):\nUSER \u22ee...\nUSER \nUSER tests/basic/test_watch.py:\nUSER \u22ee...\nUSER \u2502def test_ai_comment_pattern():\nUSER \u2502 # Create minimal IO and Coder instances for testing\nUSER \u2502 class MinimalCoder:\nUSER \u2502 def __init__(self, io):\nUSER \u2502 self.io = io\nUSER \u2502 self.root = \".\"\nUSER \u2502 self.abs_fnames = set()\nUSER \u2502\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/c/test.c:\nUSER \u22ee...\nUSER \u2502int main() {\nUSER \u2502 printf(\"Hello, World!\\n\");\nUSER \u2502 return 0;\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/cpp/test.cpp:\nUSER \u22ee...\nUSER \u2502int main() {\nUSER \u2502 std::cout << \"Hello, World!\" << std::endl;\nUSER \u2502 return 0;\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/csharp/test.cs:\nUSER \u22ee...\nUSER \u2502namespace Greetings {\nUSER \u2502 public interface IGreeter {\nUSER \u2502 string Greet(string name);\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public class Person {\nUSER \u2502 public string Name { get; set; }\nUSER \u2502 public int Age { get; set; }\nUSER \u2502\nUSER \u2502 public Person(string name, int age) {\nUSER \u2502 Name = name;\nUSER \u2502 Age = age;\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502 public class FormalGreeter : IGreeter {\nUSER \u2502 private const string PREFIX = \"Good day\";\nUSER \u2502 private static readonly int MAX_AGE = 150;\nUSER \u2502\nUSER \u2502 public string Greet(string name) {\nUSER \u2502 return $\"{PREFIX}, {name}!\";\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public string GreetPerson(Person person) {\nUSER \u2502 return $\"{PREFIX}, {person.Name} ({person.Age})!\";\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elisp/test.el:\nUSER \u22ee...\nUSER \u2502(defun create-formal-greeter ()\nUSER \u22ee...\nUSER \u2502(defun main ()\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elixir/test.ex:\nUSER \u2502defmodule Greeter do\nUSER \u2502 def hello(name) do\nUSER \u2502 IO.puts(\"Hello, #{name}!\")\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elm/test.elm:\nUSER \u22ee...\nUSER \u2502type Greeting\nUSER \u2502 = Formal\nUSER \u22ee...\nUSER \u2502greet style person =\nUSER \u2502 let\nUSER \u2502 prefix =\nUSER \u22ee...\nUSER \u2502defaultPerson =\nUSER \u22ee...\nUSER \u2502main =\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/go/test.go:\nUSER \u22ee...\nUSER \u2502type Person struct {\nUSER \u2502 Name string\nUSER \u2502 Age int\nUSER \u22ee...\nUSER \u2502type Greeter interface {\nUSER \u2502 Greet(p Person) string\nUSER \u22ee...\nUSER \u2502type FormalGreeter struct {\nUSER \u2502 Prefix string\nUSER \u22ee...\nUSER \u2502)\nUSER \u2502\nUSER \u2502func (g FormalGreeter) Greet(p Person) string {\nUSER \u2502 return fmt.Sprintf(\"%s, %s! You are %d years old.\",\nUSER \u2502 g.Prefix, p.Name, p.Age)\nUSER \u2502}\nUSER \u2502\nUSER \u2502func NewFormalGreeter() *FormalGreeter {\nUSER \u2502 return &FormalGreeter{Prefix: \"Good day\"}\nUSER \u2502}\nUSER \u2502\nUSER \u2502func main() {\nUSER \u2502 greeter := NewFormalGreeter()\nUSER \u2502 person := Person{Name: DefaultName, Age: 42}\nUSER \u2502 fmt.Println(greeter.Greet(person))\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/java/test.java:\nUSER \u2502public interface Greeting {\nUSER \u2502 String greet(String name);\nUSER \u22ee...\nUSER \u2502public class Test implements Greeting {\nUSER \u2502 private String prefix = \"Hello\";\nUSER \u2502\nUSER \u2502 public String greet(String name) {\nUSER \u2502 return prefix + \", \" + name + \"!\";\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public static void main(String[] args) {\nUSER \u2502 Test greeter = new Test();\nUSER \u2502 System.out.println(greeter.greet(\"World\"));\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/javascript/test.js:\nUSER \u22ee...\nUSER \u2502class Person {\nUSER \u2502 constructor(name) {\nUSER \u2502 this.name = name;\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 sayHello() {\nUSER \u2502 return `Hello, ${this.name}!`;\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502function greet(person) {\nUSER \u2502 return person.sayHello();\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/kotlin/test.kt:\nUSER \u2502interface Greeting {\nUSER \u2502 fun greet(name: String): String\nUSER \u22ee...\nUSER \u2502class Test : Greeting {\nUSER \u2502 private val prefix = \"Hello\"\nUSER \u2502\nUSER \u2502 override fun greet(name: String): String {\nUSER \u2502 return \"$prefix, $name!\"\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502fun main(args: Array) {\nUSER \u2502 val greeter = Test()\nUSER \u2502 println(greeter.greet(\"World\"))\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ocaml/test.ml:\nUSER \u22ee...\nUSER \u2502module Greeter = struct\nUSER \u2502 type person = {\nUSER \u2502 name: string;\nUSER \u2502 age: int\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 let create_person name age =\nUSER \u2502 {name; age}\nUSER \u2502\nUSER \u2502 let greet person =\nUSER \u2502 Printf.printf \"Hello, %s! You are %d years old.\\n\"\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/php/test.php:\nUSER \u22ee...\nUSER \u2502function greet($name) {\nUSER \u2502 echo \"Hello, $name!\";\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/python/test.py:\nUSER \u22ee...\nUSER \u2502class Person:\nUSER \u2502 \"\"\"A class representing a person.\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def greet(self, formal: bool = False) -> str:\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ql/test.ql:\nUSER \u2502predicate greet(string name) {\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ruby/test.rb:\nUSER \u2502def greet(name)\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/rust/test.rs:\nUSER \u22ee...\nUSER \u2502trait Greeting {\nUSER \u2502 fn greet(&self) -> String;\nUSER \u22ee...\nUSER \u2502struct Person {\nUSER \u2502 name: String,\nUSER \u2502 age: u32,\nUSER \u22ee...\nUSER \u2502impl Greeting for Person {\nUSER \u2502 fn greet(&self) -> String {\nUSER \u2502 format!(\"Hello, {}! You are {} years old.\", self.name, self.age)\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502fn main() {\nUSER \u2502 let person = Person::new(DEFAULT_NAME.to_string(), 30);\nUSER \u2502 println!(\"{}\", person.greet());\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/typescript/test.ts:\nUSER \u2502function greet(name: string): void {\nUSER \u22ee...\nUSER \nUSER tests/fixtures/sample-code-base/sample.js:\nUSER \u22ee...\nUSER \u2502function greet(name) {\nUSER \u2502 return `Hello, ${name}!`;\nUSER \u22ee...\nUSER \u2502function calculateCircleArea(radius) {\nUSER \u2502 return Math.PI * radius * radius;\nUSER \u22ee...\nUSER \u2502function isPrime(number) {\nUSER \u2502 if (number <= 1) return false;\nUSER \u2502 for (let i = 2; i <= Math.sqrt(number); i++) {\nUSER \u2502 if (number % i === 0) return false;\nUSER \u2502 }\nUSER \u2502 return true;\nUSER \u22ee...\nUSER \u2502function reverseString(str) {\nUSER \u2502 return str.split('').reverse().join('');\nUSER \u22ee...\nUSER \u2502function getRandomNumber(min, max) {\nUSER \u2502 return Math.floor(Math.random() * (max - min + 1)) + min;\nUSER \u22ee...\nUSER \u2502function filterEvenNumbers(numbers) {\nUSER \u2502 return numbers.filter(num => num % 2 !== 0);\nUSER \u22ee...\nUSER \u2502function factorial(n) {\nUSER \u2502 if (n === 0 || n === 1) return 1;\nUSER \u2502 return n * factorial(n - 1);\nUSER \u22ee...\nUSER \nUSER tests/fixtures/sample-code-base/sample.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\n-------\nASSISTANT Ok, I won't try and edit those files without asking first.\n-------\nUSER Don't try and edit any existing code without asking me to add the files to the chat!\nUSER Tell me which files in my repo are the most likely to **need changes** to solve the requests I make, and then stop so I can add them to the chat.\nUSER Only include the files that are most likely to actually need to be edited.\nUSER Don't include files that might contain relevant context, just files that will need to be changed.\n-------\nASSISTANT Ok, based on your requests I will suggest which files need to be edited and then stop and wait for your approval.\n-------\nUSER hi\n-------\nUSER ok\n-------\nSYSTEM # *SEARCH/REPLACE block* Rules:\nSYSTEM \nSYSTEM Every *SEARCH/REPLACE block* must use this format:\nSYSTEM 1. The *FULL* file path alone on a line, verbatim. No bold asterisks, no quotes around it, no escaping of characters, etc.\nSYSTEM 2. The opening fence and code language, eg: ```python\nSYSTEM 3. The start of search block: <<<<<<< SEARCH\nSYSTEM 4. A contiguous chunk of lines to search for in the existing source code\nSYSTEM 5. The dividing line: =======\nSYSTEM 6. The lines to replace into the source code\nSYSTEM 7. The end of the replace block: >>>>>>> REPLACE\nSYSTEM 8. The closing fence: ```\nSYSTEM \nSYSTEM Use the *FULL* file path, as shown to you by the user.\nSYSTEM \nSYSTEM Every *SEARCH* section must *EXACTLY MATCH* the existing file content, character for character, including all comments, docstrings, etc.\nSYSTEM 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.\nSYSTEM \nSYSTEM *SEARCH/REPLACE* blocks will *only* replace the first match occurrence.\nSYSTEM Including multiple unique *SEARCH/REPLACE* blocks if needed.\nSYSTEM Include enough lines in each SEARCH section to uniquely match each set of lines that need to change.\nSYSTEM \nSYSTEM Keep *SEARCH/REPLACE* blocks concise.\nSYSTEM Break large *SEARCH/REPLACE* blocks into a series of smaller blocks that each change a small portion of the file.\nSYSTEM Include just the changing lines, and a few surrounding lines if needed for uniqueness.\nSYSTEM Do not include long runs of unchanging lines in *SEARCH/REPLACE* blocks.\nSYSTEM \nSYSTEM Only create *SEARCH/REPLACE* blocks for files that the user has added to the chat!\nSYSTEM \nSYSTEM To move code within a file, use 2 *SEARCH/REPLACE* blocks: 1 to delete it from its current location, 1 to insert it in the new location.\nSYSTEM \nSYSTEM Pay attention to which filenames the user wants you to edit, especially if they are asking you to create a new file.\nSYSTEM \nSYSTEM If you want to put code in a new file, use a *SEARCH/REPLACE block* with:\nSYSTEM - A new file path, including dir name if needed\nSYSTEM - An empty `SEARCH` section\nSYSTEM - The new file's contents in the `REPLACE` section\nSYSTEM \nSYSTEM To rename files which have been added to the chat, use shell commands at the end of your response.\nSYSTEM \nSYSTEM If the user just says something like \"ok\" or \"go ahead\" or \"do that\" they probably want you to make SEARCH/REPLACE blocks for the code changes you just proposed.\nSYSTEM The user will say when they've applied your edits. If they haven't explicitly confirmed the edits have been applied, they probably want proper SEARCH/REPLACE blocks.\nSYSTEM \nSYSTEM \nSYSTEM ONLY EVER RETURN CODE IN A *SEARCH/REPLACE BLOCK*!\nSYSTEM \nSYSTEM Examples of when to suggest shell commands:\nSYSTEM \nSYSTEM - If you changed a self-contained html file, suggest an OS-appropriate command to open a browser to view it to see the updated content.\nSYSTEM - If you changed a CLI program, suggest the command to run it to see the new behavior.\nSYSTEM - If you added a test, suggest how to run it with the testing tool used by the project.\nSYSTEM - Suggest OS-appropriate commands to delete or rename files/directories, or other file system operations.\nSYSTEM - If your code changes add new dependencies, suggest the command to install them.\nSYSTEM - Etc.\nSYSTEM "}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566814}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566915}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566915}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566920}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566922}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566922}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566928}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 89281, "completion_tokens": 0, "total_tokens": 89281, "cost": 0.012499340000000001, "total_cost": 0.012499340000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566930}
+{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566937}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566937}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 10011, "completion_tokens": 32, "total_tokens": 10043, "cost": 0.0014105, "total_cost": 0.013909840000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566942}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566995}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737566997}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737567001}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737567001}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737567005}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737567071}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737567071}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737567071}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568228}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568230}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568230}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568233}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568406}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568408}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568412}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568435}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568437}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568437}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 4375, "completion_tokens": 493, "total_tokens": 4868, "cost": 0.0007505400000000001, "total_cost": 0.0007505400000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568450}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568450}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568486}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568486}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568486}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568729}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568729}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568729}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568809}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568811}
+{"event": "cli session", "properties": {"main_model": "deepseek/REDACTED", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568815}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568825}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568833}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568834}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568841}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568841}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568841}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568842}
+{"event": "command_editor", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568857}
+{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568920}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568920}
+{"event": "message_send", "properties": {"main_model": "deepseek/REDACTED", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 27240, "completion_tokens": 737, "total_tokens": 27977, "cost": 0.01659603, "total_cost": 0.01659603}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568955}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568963}
+{"event": "message_send", "properties": {"main_model": "deepseek/REDACTED", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 30223, "completion_tokens": 719, "total_tokens": 30942, "cost": 0.01819726, "total_cost": 0.034793290000000004}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568998}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737568998}
+{"event": "message_send", "properties": {"main_model": "deepseek/REDACTED", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 31787, "completion_tokens": 727, "total_tokens": 32514, "cost": 0.019074980000000002, "total_cost": 0.05386827000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569029}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569031}
+{"event": "message_send", "properties": {"main_model": "deepseek/REDACTED", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 33210, "completion_tokens": 52, "total_tokens": 33262, "cost": 0.01837938, "total_cost": 0.07224765000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569046}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569046}
+{"event": "message_send", "properties": {"main_model": "deepseek/REDACTED", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 33391, "completion_tokens": 77, "total_tokens": 33468, "cost": 0.01853368, "total_cost": 0.09078133000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569061}
+{"event": "command_lint", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569067}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569072}
+{"event": "message_send", "properties": {"main_model": "deepseek/REDACTED", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 31055, "completion_tokens": 158, "total_tokens": 31213, "cost": 0.01742627, "total_cost": 0.10820760000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569095}
+{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569179}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569257}
+{"event": "message_send", "properties": {"main_model": "deepseek/REDACTED", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 37700, "completion_tokens": 543, "total_tokens": 38243, "cost": 0.02192417, "total_cost": 0.11270550000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569287}
+{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569308}
+{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569311}
+{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569314}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569364}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 34544, "completion_tokens": 195, "total_tokens": 34739, "cost": 0.00489076, "total_cost": 0.11759626000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569384}
+{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569394}
+{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569396}
+{"event": "command_run", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569398}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569454}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 34541, "completion_tokens": 293, "total_tokens": 34834, "cost": 0.108018, "total_cost": 0.22561426}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569469}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569470}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 35069, "completion_tokens": 236, "total_tokens": 35305, "cost": 0.10874700000000001, "total_cost": 0.33436126}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569484}
+{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569501}
+{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569503}
+{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569510}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569544}
+{"event": "message_send", "properties": {"main_model": "deepseek/REDACTED", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 30030, "completion_tokens": 361, "total_tokens": 30391, "cost": 0.01730709, "total_cost": 0.35166835}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569568}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569802}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569802}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569836}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569838}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737569842}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737570474}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737570476}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737570477}
+{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737570508}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737570508}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 7649, "completion_tokens": 228, "total_tokens": 7877, "cost": 0.0011347, "total_cost": 0.0011347}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737570518}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737580816}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737580818}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737580818}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737580820}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737580820}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737580823}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737580825}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737580825}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737580838}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737586733}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737586735}
+{"event": "exit", "properties": {"reason": "Showed prompts"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737586736}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737651344}
+{"event": "repo", "properties": {"num_files": 428}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737651347}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737651347}
+{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737651350}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737651356}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737651361}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 5303, "completion_tokens": 232, "total_tokens": 5535, "cost": 0.00080738, "total_cost": 0.00080738}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737651371}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737651891}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737651891}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660558}
+{"event": "model warning", "properties": {"main_model": "sambanova/REDACTED", "weak_model": "sambanova/REDACTED", "editor_model": "sambanova/REDACTED"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660560}
+{"event": "exit", "properties": {"reason": "Keyboard interrupt during model warnings"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660750}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660812}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660814}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660814}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660838}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660838}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660838}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 16771, "completion_tokens": 370, "total_tokens": 17141, "cost": 0.0024515400000000003, "total_cost": 0.0024515400000000003}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660852}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660856}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 17287, "completion_tokens": 82, "total_tokens": 17369, "cost": 0.00244314, "total_cost": 0.00489468}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660870}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660872}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660872}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660876}
+{"event": "model warning", "properties": {"main_model": "sambanova/REDACTED", "weak_model": "sambanova/REDACTED", "editor_model": "sambanova/REDACTED"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660878}
+{"event": "exit", "properties": {"reason": "Keyboard interrupt during model warnings"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660886}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660890}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660891}
+{"event": "cli session", "properties": {"main_model": "sambanova/Meta-Llama-3.2-1B-Instruct", "weak_model": "sambanova/Meta-Llama-3.2-1B-Instruct", "editor_model": "sambanova/Meta-Llama-3.2-1B-Instruct", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660891}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660893}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660893}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660989}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660989}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660989}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660997}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660999}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737660999}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 2468, "completion_tokens": 36, "total_tokens": 2504, "cost": 0.00036097600000000005, "total_cost": 0.00036097600000000005}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737661001}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737661001}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737661006}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737661007}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737661007}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-reasoner", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 2471, "completion_tokens": 279, "total_tokens": 2750, "cost": 0.00199118, "total_cost": 0.00199118}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737661014}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737661014}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737661179}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737661181}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737661181}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-reasoner", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 2471, "completion_tokens": 296, "total_tokens": 2767, "cost": 0.0021410500000000002, "total_cost": 0.0021410500000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737661189}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737661189}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674826}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674828}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674828}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674831}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674831}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674843}
+{"event": "repo", "properties": {"num_files": 427}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674844}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674844}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674858}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674858}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674858}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 7979, "completion_tokens": 619, "total_tokens": 8598, "cost": 0.00129038, "total_cost": 0.00129038}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674876}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674906}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 8681, "completion_tokens": 146, "total_tokens": 8827, "cost": 0.0012562200000000002, "total_cost": 0.0025466000000000004}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674912}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674951}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 8893, "completion_tokens": 193, "total_tokens": 9086, "cost": 0.00129906, "total_cost": 0.0038456600000000007}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737674958}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737675093}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 9144, "completion_tokens": 186, "total_tokens": 9330, "cost": 0.00133224, "total_cost": 0.005177900000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737675100}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737675341}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737675341}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737734509}
+{"event": "repo", "properties": {"num_files": 428}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737734511}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737734511}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737734521}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737734528}
+{"event": "repo", "properties": {"num_files": 428}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737734529}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737734529}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737734534}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735763}
+{"event": "repo", "properties": {"num_files": 429}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735765}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735765}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735770}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735777}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735796}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735796}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735796}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 8967, "completion_tokens": 155, "total_tokens": 9122, "cost": 0.0012987800000000002, "total_cost": 0.0012987800000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735804}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735830}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 9181, "completion_tokens": 268, "total_tokens": 9449, "cost": 0.00136038, "total_cost": 0.0026591600000000003}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735839}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735892}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737735892}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738819}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738821}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738836}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738838}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738842}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 7867, "completion_tokens": 295, "total_tokens": 8162, "cost": 0.00118398, "total_cost": 0.00118398}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738853}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738853}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738868}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738870}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738877}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 7973, "completion_tokens": 301, "total_tokens": 8274, "cost": 0.0012005, "total_cost": 0.0012005}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738888}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738895}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738960}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738960}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737738960}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739083}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739085}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739085}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739093}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739099}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739105}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739121}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 8056, "completion_tokens": 1101, "total_tokens": 9157, "cost": 0.0014361200000000001, "total_cost": 0.0014361200000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739154}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739171}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739226}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739226}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739226}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739495}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739497}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739550}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 7149, "completion_tokens": 250, "total_tokens": 7399, "cost": 0.00107086, "total_cost": 0.00107086}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737739560}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737744858}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737744861}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737744871}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737753076}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737753079}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737753101}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 22094, "completion_tokens": 243, "total_tokens": 22337, "cost": 0.0031612000000000003, "total_cost": 0.0031612000000000003}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737753114}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737753121}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 22610, "completion_tokens": 95, "total_tokens": 22705, "cost": 0.003192, "total_cost": 0.0063532}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737753130}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737753144}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 8768, "completion_tokens": 84, "total_tokens": 8852, "cost": 0.0012510400000000001, "total_cost": 0.00760424}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737753150}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737753153}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737821174}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737821176}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737821176}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 6949, "completion_tokens": 583, "total_tokens": 7532, "cost": 0.0011361000000000001, "total_cost": 0.0011361000000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737821191}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737821191}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737821714}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737821715}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737821715}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737822664}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737822666}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737822670}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823046}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823048}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823048}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823079}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823079}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823079}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 16847, "completion_tokens": 404, "total_tokens": 17251, "cost": 0.0024717000000000003, "total_cost": 0.0024717000000000003}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823097}
+{"event": "command_editor", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823132}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823158}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 17609, "completion_tokens": 482, "total_tokens": 18091, "cost": 0.0026002200000000003, "total_cost": 0.005071920000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823182}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823182}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 18777, "completion_tokens": 468, "total_tokens": 19245, "cost": 0.0027598200000000005, "total_cost": 0.00783174}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823199}
+{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823215}
+{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823220}
+{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823236}
+{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823238}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823241}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 17004, "completion_tokens": 449, "total_tokens": 17453, "cost": 0.057747, "total_cost": 0.06557874}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823257}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823279}
+{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823290}
+{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823293}
+{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823340}
+{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823343}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823375}
+{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823386}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823387}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-reasoner", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 17012, "completion_tokens": 460, "total_tokens": 17472, "cost": 0.010364, "total_cost": 0.07594274}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823418}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823580}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823582}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823588}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823682}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-reasoner", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 17526, "completion_tokens": 82, "total_tokens": 17608, "cost": 0.00981888, "total_cost": 0.08576162}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823695}
+{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823700}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823704}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737823704}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945667}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945670}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945670}
+{"event": "command_architect", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945672}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945675}
+{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945676}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945697}
+{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945712}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945713}
+{"event": "message_send_exception", "properties": {"exception": "Messages don't properly alternate user/assistant:\n\n-------\nSYSTEM Act as an expert code analyst.\nSYSTEM Answer questions about the supplied code.\nSYSTEM Always reply to the user in the same language they are using.\nSYSTEM \nSYSTEM Describe code changes however you like. Don't use SEARCH/REPLACE blocks!\n-------\nUSER I am working with you on code in a git repository.\nUSER Here are summaries of some files present in my git repo.\nUSER If you need to see the full contents of any files to answer my questions, ask me to *add them to the chat*.\nUSER \nUSER aider/analytics.py:\nUSER \u22ee...\nUSER \u2502class Analytics:\nUSER \u2502 # providers\nUSER \u2502 mp = None\nUSER \u22ee...\nUSER \u2502 def event(self, event_name, main_model=None, **kwargs):\nUSER \u22ee...\nUSER \nUSER aider/args.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/coders/base_prompts.py:\nUSER \u2502class CoderPrompts:\nUSER \u22ee...\nUSER \nUSER aider/coders/chat_chunks.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ChatChunks:\nUSER \u2502 system: List = field(default_factory=list)\nUSER \u22ee...\nUSER \u2502 def all_messages(self):\nUSER \u22ee...\nUSER \u2502 def add_cache_control(self, messages):\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_coder.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/coders/help_prompts.py:\nUSER \u22ee...\nUSER \u2502class HelpPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/search_replace.py:\nUSER \u22ee...\nUSER \u2502def read_text(fname):\nUSER \u22ee...\nUSER \u2502def main(dnames):\nUSER \u22ee...\nUSER \nUSER aider/coders/udiff_coder.py:\nUSER \u22ee...\nUSER \u2502class UnifiedDiffCoder(Coder):\nUSER \u2502 \"\"\"A coder that uses unified diff format for code modifications.\"\"\"\nUSER \u22ee...\nUSER \u2502 def get_edits(self):\nUSER \u22ee...\nUSER \nUSER aider/coders/wholefile_coder.py:\nUSER \u22ee...\nUSER \u2502class WholeFileCoder(Coder):\nUSER \u2502 \"\"\"A coder that operates on entire files for code modifications.\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def render_incremental_response(self, final):\nUSER \u22ee...\nUSER \u2502 def get_edits(self, mode=\"update\"):\nUSER \u22ee...\nUSER \nUSER aider/commands.py:\nUSER \u22ee...\nUSER \u2502class Commands:\nUSER \u2502 voice = None\nUSER \u22ee...\nUSER \u2502 def get_raw_completions(self, cmd):\nUSER \u22ee...\nUSER \u2502 def get_completions(self, cmd):\nUSER \u22ee...\nUSER \u2502 def get_commands(self):\nUSER \u22ee...\nUSER \u2502 def matching_commands(self, inp):\nUSER \u22ee...\nUSER \u2502 def run(self, inp):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/copypaste.py:\nUSER \u22ee...\nUSER \u2502class ClipboardWatcher:\nUSER \u2502 \"\"\"Watches clipboard for changes and updates IO placeholder\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def start(self):\nUSER \u22ee...\nUSER \u2502 def stop(self):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/diffs.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/dump.py:\nUSER \u22ee...\nUSER \u2502def cvt(s):\nUSER \u22ee...\nUSER \u2502def dump(*vals):\nUSER \u22ee...\nUSER \nUSER aider/exceptions.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ExInfo:\nUSER \u22ee...\nUSER \u2502class LiteLLMExceptions:\nUSER \u2502 exceptions = dict()\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def exceptions_tuple(self):\nUSER \u22ee...\nUSER \u2502 def get_ex_info(self, ex):\nUSER \u22ee...\nUSER \nUSER aider/gui.py:\nUSER \u22ee...\nUSER \u2502class CaptureIO(InputOutput):\nUSER \u2502 lines = []\nUSER \u2502\nUSER \u2502 def tool_output(self, msg, log_only=False):\nUSER \u22ee...\nUSER \u2502 def tool_error(self, msg):\nUSER \u22ee...\nUSER \u2502 def tool_warning(self, msg):\nUSER \u22ee...\nUSER \u2502 def get_captured_lines(self):\nUSER \u22ee...\nUSER \u2502class State:\nUSER \u2502 keys = set()\nUSER \u2502\nUSER \u2502 def init(self, key, val=None):\nUSER \u22ee...\nUSER \u2502class GUI:\nUSER \u2502 prompt = None\nUSER \u22ee...\nUSER \u2502 def show_edit_info(self, edit):\nUSER \u22ee...\nUSER \u2502 def add_undo(self, commit_hash):\nUSER \u22ee...\nUSER \u2502 def button(self, args, **kwargs):\nUSER \u22ee...\nUSER \u2502 def prompt_pending(self):\nUSER \u22ee...\nUSER \u2502 def info(self, message, echo=True):\nUSER \u22ee...\nUSER \nUSER aider/history.py:\nUSER \u22ee...\nUSER \u2502class ChatSummary:\nUSER \u2502 def __init__(self, models=None, max_tokens=1024):\nUSER \u2502 if not models:\nUSER \u2502 raise ValueError(\"At least one model must be provided\")\nUSER \u2502 self.models = models if isinstance(models, list) else [models]\nUSER \u2502 self.max_tokens = max_tokens\nUSER \u22ee...\nUSER \u2502 def tokenize(self, messages):\nUSER \u22ee...\nUSER \u2502 def summarize_all(self, messages):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/io.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ConfirmGroup:\nUSER \u22ee...\nUSER \u2502class AutoCompleter(Completer):\nUSER \u2502 def __init__(\nUSER \u2502 self, root, rel_fnames, addable_rel_fnames, commands, encoding, abs_read_only_fnames=None\nUSER \u22ee...\nUSER \u2502 def tokenize(self):\nUSER \u22ee...\nUSER \u2502 def get_command_completions(self, document, complete_event, text, words):\nUSER \u22ee...\nUSER \u2502 def get_completions(self, document, complete_event):\nUSER \u22ee...\nUSER \u2502class InputOutput:\nUSER \u2502 num_error_outputs = 0\nUSER \u22ee...\nUSER \u2502 def read_image(self, filename):\nUSER \u22ee...\nUSER \u2502 def read_text(self, filename, silent=False):\nUSER \u22ee...\nUSER \u2502 def write_text(self, filename, content, max_retries=5, initial_delay=0.1):\nUSER \u22ee...\nUSER \u2502 def rule(self):\nUSER \u22ee...\nUSER \u2502 def get_input(\nUSER \u2502 self,\nUSER \u2502 root,\nUSER \u2502 rel_fnames,\nUSER \u2502 addable_rel_fnames,\nUSER \u2502 commands,\nUSER \u2502 abs_read_only_fnames=None,\nUSER \u2502 edit_format=None,\nUSER \u2502 ):\nUSER \u2502 self.rule()\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def suspend_to_bg(event):\nUSER \u22ee...\nUSER \u2502 def add_to_input_history(self, inp):\nUSER \u22ee...\nUSER \u2502 def log_llm_history(self, role, content):\nUSER \u22ee...\nUSER \u2502 def display_user_input(self, inp):\nUSER \u22ee...\nUSER \u2502 def user_input(self, inp, log_only=True):\nUSER \u22ee...\nUSER \u2502 def ai_output(self, content):\nUSER \u22ee...\nUSER \u2502 def offer_url(self, url, prompt=\"Open URL for more info?\", allow_never=True):\nUSER \u22ee...\nUSER \u2502 def confirm_ask(\nUSER \u2502 self,\nUSER \u2502 question,\nUSER \u2502 default=\"y\",\nUSER \u2502 subject=None,\nUSER \u2502 explicit_yes_required=False,\nUSER \u2502 group=None,\nUSER \u2502 allow_never=False,\nUSER \u22ee...\nUSER \u2502 def tool_error(self, message=\"\", strip=True):\nUSER \u22ee...\nUSER \u2502 def tool_warning(self, message=\"\", strip=True):\nUSER \u22ee...\nUSER \u2502 def tool_output(self, *messages, log_only=False, bold=False):\nUSER \u22ee...\nUSER \u2502 def print(self, message=\"\"):\nUSER \u22ee...\nUSER \u2502 def append_chat_history(self, text, linebreak=False, blockquote=False, strip=True):\nUSER \u22ee...\nUSER \u2502 def format_files_for_input(self, rel_fnames, rel_read_only_fnames):\nUSER \u22ee...\nUSER \u2502def get_rel_fname(fname, root):\nUSER \u22ee...\nUSER \nUSER aider/linter.py:\nUSER \u22ee...\nUSER \u2502class Linter:\nUSER \u2502 def __init__(self, encoding=\"utf-8\", root=None):\nUSER \u2502 self.encoding = encoding\nUSER \u2502 self.root = root\nUSER \u2502\nUSER \u2502 self.languages = dict(\nUSER \u2502 python=self.py_lint,\nUSER \u2502 )\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def run_cmd(self, cmd, rel_fname, code):\nUSER \u22ee...\nUSER \u2502 def lint(self, fname, cmd=None):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/main.py:\nUSER \u22ee...\nUSER \u2502def main(argv=None, input=None, output=None, force_git_root=None, return_coder=False):\nUSER \u22ee...\nUSER \nUSER aider/mdstream.py:\nUSER \u22ee...\nUSER \u2502class MarkdownStream:\nUSER \u2502 \"\"\"Streaming markdown renderer that progressively displays content with a live updating window.\nUSER \u2502\nUSER \u2502 Uses rich.console and rich.live to render markdown content with smooth scrolling\nUSER \u2502 and partial updates. Maintains a sliding window of visible content while streaming\nUSER \u2502 in new markdown text.\nUSER \u22ee...\nUSER \u2502 def update(self, text, final=False):\nUSER \u22ee...\nUSER \nUSER aider/models.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ModelSettings:\nUSER \u22ee...\nUSER \u2502class Model(ModelSettings):\nUSER \u2502 def __init__(self, model, weak_model=None, editor_model=None, editor_edit_format=None):\nUSER \u2502 # Map any alias to its canonical name\nUSER \u2502 model = MODEL_ALIASES.get(model, model)\nUSER \u2502\nUSER \u2502 self.name = model\nUSER \u2502\nUSER \u2502 self.max_chat_history_tokens = 1024\nUSER \u2502 self.weak_model = None\nUSER \u2502 self.editor_model = None\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def token_count(self, messages):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/repo.py:\nUSER \u22ee...\nUSER \u2502class GitRepo:\nUSER \u2502 repo = None\nUSER \u22ee...\nUSER \u2502 def commit(self, fnames=None, context=None, message=None, aider_edits=False):\nUSER \u22ee...\nUSER \u2502 def diff_commits(self, pretty, from_commit, to_commit):\nUSER \u22ee...\nUSER \u2502 def get_tracked_files(self):\nUSER \u22ee...\nUSER \u2502 def normalize_path(self, path):\nUSER \u22ee...\nUSER \u2502 def git_ignored_file(self, path):\nUSER \u22ee...\nUSER \u2502 def ignored_file(self, fname):\nUSER \u22ee...\nUSER \u2502 def path_in_repo(self, path):\nUSER \u22ee...\nUSER \u2502 def abs_root_path(self, path):\nUSER \u22ee...\nUSER \u2502 def is_dirty(self, path=None):\nUSER \u22ee...\nUSER \u2502 def get_head_commit_sha(self, short=False):\nUSER \u22ee...\nUSER \nUSER aider/repomap.py:\nUSER \u22ee...\nUSER \u2502class RepoMap:\nUSER \u2502 CACHE_VERSION = 3\nUSER \u22ee...\nUSER \u2502 def token_count(self, text):\nUSER \u22ee...\nUSER \u2502 def get_repo_map(\nUSER \u2502 self,\nUSER \u2502 chat_files,\nUSER \u2502 other_files,\nUSER \u2502 mentioned_fnames=None,\nUSER \u2502 mentioned_idents=None,\nUSER \u2502 force_refresh=False,\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \nUSER aider/report.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/run_cmd.py:\nUSER \u22ee...\nUSER \u2502def run_cmd(command, verbose=False, error_print=None, cwd=None):\nUSER \u22ee...\nUSER \nUSER aider/scrape.py:\nUSER \u22ee...\nUSER \u2502class Scraper:\nUSER \u2502 pandoc_available = None\nUSER \u22ee...\nUSER \u2502 def scrape(self, url):\nUSER \u22ee...\nUSER \u2502def main(url):\nUSER \u22ee...\nUSER \nUSER aider/sendchat.py:\nUSER \u22ee...\nUSER \u2502def send_completion(\nUSER \u2502 model_name,\nUSER \u2502 messages,\nUSER \u2502 functions,\nUSER \u2502 stream,\nUSER \u2502 temperature=0,\nUSER \u2502 extra_params=None,\nUSER \u22ee...\nUSER \nUSER aider/utils.py:\nUSER \u22ee...\nUSER \u2502def is_image_file(file_name):\nUSER \u22ee...\nUSER \u2502def safe_abs_path(res):\nUSER \u22ee...\nUSER \u2502def format_content(role, content):\nUSER \u22ee...\nUSER \u2502def format_messages(messages, title=None):\nUSER \u22ee...\nUSER \u2502def format_tokens(count):\nUSER \u22ee...\nUSER \u2502def touch_file(fname):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/watch.py:\nUSER \u22ee...\nUSER \u2502class FileWatcher:\nUSER \u2502 \"\"\"Watches source files for changes and AI comments\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def start(self):\nUSER \u22ee...\nUSER \u2502 def stop(self):\nUSER \u22ee...\nUSER \u2502 def process_changes(self):\nUSER \u22ee...\nUSER \u2502 def get_ai_comments(self, filepath):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER benchmark/benchmark.py:\nUSER \u22ee...\nUSER \u2502@app.command()\nUSER \u2502def main(\nUSER \u2502 dirnames: Optional[List[str]] = typer.Argument(None, help=\"Directory names\"),\nUSER \u2502 graphs: bool = typer.Option(False, \"--graphs\", help=\"Generate graphs\"),\nUSER \u2502 model: str = typer.Option(\"gpt-3.5-turbo\", \"--model\", \"-m\", help=\"Model name\"),\nUSER \u2502 sleep: float = typer.Option(\nUSER \u2502 0, \"--sleep\", help=\"Sleep seconds between tests when single threaded\"\nUSER \u2502 ),\nUSER \u2502 languages: str = typer.Option(\nUSER \u2502 None, \"--languages\", \"-l\", help=\"Only run tests for specific languages (comma separated)\"\nUSER \u2502 ),\nUSER \u22ee...\nUSER \nUSER benchmark/over_time.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER benchmark/refactor_tools.py:\nUSER \u22ee...\nUSER \u2502def main(paths):\nUSER \u22ee...\nUSER \nUSER benchmark/rungrid.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \u2502def run(dirname, model, edit_format):\nUSER \u22ee...\nUSER \nUSER scripts/blame.py:\nUSER \u22ee...\nUSER \u2502def run(cmd):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/issues.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/update-history.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/versionbump.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/yank-old-versions.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER tests/basic/test_watch.py:\nUSER \u22ee...\nUSER \u2502def test_ai_comment_pattern():\nUSER \u2502 # Create minimal IO and Coder instances for testing\nUSER \u2502 class MinimalCoder:\nUSER \u2502 def __init__(self, io):\nUSER \u2502 self.io = io\nUSER \u2502 self.root = \".\"\nUSER \u2502 self.abs_fnames = set()\nUSER \u2502\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/c/test.c:\nUSER \u22ee...\nUSER \u2502int main() {\nUSER \u2502 printf(\"Hello, World!\\n\");\nUSER \u2502 return 0;\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/cpp/test.cpp:\nUSER \u22ee...\nUSER \u2502int main() {\nUSER \u2502 std::cout << \"Hello, World!\" << std::endl;\nUSER \u2502 return 0;\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/csharp/test.cs:\nUSER \u22ee...\nUSER \u2502namespace Greetings {\nUSER \u2502 public interface IGreeter {\nUSER \u2502 string Greet(string name);\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public class Person {\nUSER \u2502 public string Name { get; set; }\nUSER \u2502 public int Age { get; set; }\nUSER \u2502\nUSER \u2502 public Person(string name, int age) {\nUSER \u2502 Name = name;\nUSER \u2502 Age = age;\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502 public class FormalGreeter : IGreeter {\nUSER \u2502 private const string PREFIX = \"Good day\";\nUSER \u2502 private static readonly int MAX_AGE = 150;\nUSER \u2502\nUSER \u2502 public string Greet(string name) {\nUSER \u2502 return $\"{PREFIX}, {name}!\";\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public string GreetPerson(Person person) {\nUSER \u2502 return $\"{PREFIX}, {person.Name} ({person.Age})!\";\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elisp/test.el:\nUSER \u22ee...\nUSER \u2502(defun main ()\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elixir/test.ex:\nUSER \u2502defmodule Greeter do\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elm/test.elm:\nUSER \u22ee...\nUSER \u2502type Greeting\nUSER \u22ee...\nUSER \u2502greet style person =\nUSER \u22ee...\nUSER \u2502main =\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/go/test.go:\nUSER \u22ee...\nUSER \u2502type Person struct {\nUSER \u2502 Name string\nUSER \u2502 Age int\nUSER \u22ee...\nUSER \u2502type Greeter interface {\nUSER \u2502 Greet(p Person) string\nUSER \u22ee...\nUSER \u2502type FormalGreeter struct {\nUSER \u2502 Prefix string\nUSER \u22ee...\nUSER \u2502}\nUSER \u2502\nUSER \u2502func main() {\nUSER \u2502 greeter := NewFormalGreeter()\nUSER \u2502 person := Person{Name: DefaultName, Age: 42}\nUSER \u2502 fmt.Println(greeter.Greet(person))\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/java/test.java:\nUSER \u2502public interface Greeting {\nUSER \u2502 String greet(String name);\nUSER \u22ee...\nUSER \u2502public class Test implements Greeting {\nUSER \u2502 private String prefix = \"Hello\";\nUSER \u2502\nUSER \u2502 public String greet(String name) {\nUSER \u2502 return prefix + \", \" + name + \"!\";\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public static void main(String[] args) {\nUSER \u2502 Test greeter = new Test();\nUSER \u2502 System.out.println(greeter.greet(\"World\"));\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/javascript/test.js:\nUSER \u22ee...\nUSER \u2502class Person {\nUSER \u2502 constructor(name) {\nUSER \u2502 this.name = name;\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 sayHello() {\nUSER \u2502 return `Hello, ${this.name}!`;\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502function greet(person) {\nUSER \u2502 return person.sayHello();\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/kotlin/test.kt:\nUSER \u2502interface Greeting {\nUSER \u2502 fun greet(name: String): String\nUSER \u22ee...\nUSER \u2502class Test : Greeting {\nUSER \u2502 private val prefix = \"Hello\"\nUSER \u2502\nUSER \u2502 override fun greet(name: String): String {\nUSER \u2502 return \"$prefix, $name!\"\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502fun main(args: Array) {\nUSER \u2502 val greeter = Test()\nUSER \u2502 println(greeter.greet(\"World\"))\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ocaml/test.ml:\nUSER \u22ee...\nUSER \u2502module Greeter = struct\nUSER \u2502 type person = {\nUSER \u2502 name: string;\nUSER \u2502 age: int\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 let create_person name age =\nUSER \u2502 {name; age}\nUSER \u2502\nUSER \u2502 let greet person =\nUSER \u2502 Printf.printf \"Hello, %s! You are %d years old.\\n\"\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/php/test.php:\nUSER \u22ee...\nUSER \u2502function greet($name) {\nUSER \u2502 echo \"Hello, $name!\";\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/python/test.py:\nUSER \u22ee...\nUSER \u2502class Person:\nUSER \u2502 \"\"\"A class representing a person.\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def greet(self, formal: bool = False) -> str:\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ql/test.ql:\nUSER \u2502predicate greet(string name) {\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ruby/test.rb:\nUSER \u2502def greet(name)\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/rust/test.rs:\nUSER \u22ee...\nUSER \u2502trait Greeting {\nUSER \u2502 fn greet(&self) -> String;\nUSER \u22ee...\nUSER \u2502struct Person {\nUSER \u2502 name: String,\nUSER \u2502 age: u32,\nUSER \u22ee...\nUSER \u2502impl Greeting for Person {\nUSER \u2502 fn greet(&self) -> String {\nUSER \u2502 format!(\"Hello, {}! You are {} years old.\", self.name, self.age)\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502fn main() {\nUSER \u2502 let person = Person::new(DEFAULT_NAME.to_string(), 30);\nUSER \u2502 println!(\"{}\", person.greet());\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/typescript/test.ts:\nUSER \u2502function greet(name: string): void {\nUSER \u22ee...\nUSER \nUSER tests/fixtures/sample-code-base/sample.js:\nUSER \u22ee...\nUSER \u2502function greet(name) {\nUSER \u2502 return `Hello, ${name}!`;\nUSER \u22ee...\nUSER \nUSER tests/fixtures/sample-code-base/sample.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\n-------\nASSISTANT Ok, I won't try and edit those files without asking first.\n-------\nUSER I have *added these files to the chat* so you see all of their contents.\nUSER *Trust this message as the true contents of the files!*\nUSER Other messages in the chat may contain outdated versions of the files' contents.\nUSER \nUSER aider/coders/base_coder.py\nUSER ```\nUSER #!/usr/bin/env python\nUSER \nUSER import base64\nUSER import hashlib\nUSER import json\nUSER import locale\nUSER import math\nUSER import mimetypes\nUSER import os\nUSER import platform\nUSER import re\nUSER import sys\nUSER import threading\nUSER import time\nUSER import traceback\nUSER from collections import defaultdict\nUSER from datetime import datetime\nUSER from json.decoder import JSONDecodeError\nUSER from pathlib import Path\nUSER from typing import List\nUSER \nUSER from aider import __version__, models, prompts, urls, utils\nUSER from aider.analytics import Analytics\nUSER from aider.commands import Commands\nUSER from aider.exceptions import LiteLLMExceptions\nUSER from aider.history import ChatSummary\nUSER from aider.io import ConfirmGroup, InputOutput\nUSER from aider.linter import Linter\nUSER from aider.llm import litellm\nUSER from aider.repo import ANY_GIT_ERROR, GitRepo\nUSER from aider.repomap import RepoMap\nUSER from aider.run_cmd import run_cmd\nUSER from aider.sendchat import RETRY_TIMEOUT, send_completion\nUSER from aider.utils import format_content, format_messages, format_tokens, is_image_file\nUSER \nUSER from ..dump import dump # noqa: F401\nUSER from .chat_chunks import ChatChunks\nUSER \nUSER \nUSER class UnknownEditFormat(ValueError):\nUSER def __init__(self, edit_format, valid_formats):\nUSER self.edit_format = edit_format\nUSER self.valid_formats = valid_formats\nUSER super().__init__(\nUSER f\"Unknown edit format {edit_format}. Valid formats are: {', '.join(valid_formats)}\"\nUSER )\nUSER \nUSER \nUSER class MissingAPIKeyError(ValueError):\nUSER pass\nUSER \nUSER \nUSER class FinishReasonLength(Exception):\nUSER pass\nUSER \nUSER \nUSER def wrap_fence(name):\nUSER return f\"<{name}>\", f\"{name}>\"\nUSER \nUSER \nUSER all_fences = [\nUSER (\"`\" * 3, \"`\" * 3),\nUSER (\"`\" * 4, \"`\" * 4),\nUSER wrap_fence(\"source\"),\nUSER wrap_fence(\"code\"),\nUSER wrap_fence(\"pre\"),\nUSER wrap_fence(\"codeblock\"),\nUSER wrap_fence(\"sourcecode\"),\nUSER ]\nUSER \nUSER \nUSER class Coder:\nUSER abs_fnames = None\nUSER abs_read_only_fnames = None\nUSER repo = None\nUSER last_aider_commit_hash = None\nUSER aider_edited_files = None\nUSER last_asked_for_commit_time = 0\nUSER repo_map = None\nUSER functions = None\nUSER num_exhausted_context_windows = 0\nUSER num_malformed_responses = 0\nUSER last_keyboard_interrupt = None\nUSER num_reflections = 0\nUSER max_reflections = 3\nUSER edit_format = None\nUSER yield_stream = False\nUSER temperature = 0\nUSER auto_lint = True\nUSER auto_test = False\nUSER test_cmd = None\nUSER lint_outcome = None\nUSER test_outcome = None\nUSER multi_response_content = \"\"\nUSER partial_response_content = \"\"\nUSER commit_before_message = []\nUSER message_cost = 0.0\nUSER message_tokens_sent = 0\nUSER message_tokens_received = 0\nUSER add_cache_headers = False\nUSER cache_warming_thread = None\nUSER num_cache_warming_pings = 0\nUSER suggest_shell_commands = True\nUSER detect_urls = True\nUSER ignore_mentions = None\nUSER chat_language = None\nUSER file_watcher = None\nUSER \nUSER @classmethod\nUSER def create(\nUSER self,\nUSER main_model=None,\nUSER edit_format=None,\nUSER io=None,\nUSER from_coder=None,\nUSER summarize_from_coder=True,\nUSER **kwargs,\nUSER ):\nUSER import aider.coders as coders\nUSER \nUSER if not main_model:\nUSER if from_coder:\nUSER main_model = from_coder.main_model\nUSER else:\nUSER main_model = models.Model(models.DEFAULT_MODEL_NAME)\nUSER \nUSER if edit_format == \"code\":\nUSER edit_format = None\nUSER if edit_format is None:\nUSER if from_coder:\nUSER edit_format = from_coder.edit_format\nUSER else:\nUSER edit_format = main_model.edit_format\nUSER \nUSER if not io and from_coder:\nUSER io = from_coder.io\nUSER \nUSER if from_coder:\nUSER use_kwargs = dict(from_coder.original_kwargs) # copy orig kwargs\nUSER \nUSER # If the edit format changes, we can't leave old ASSISTANT\nUSER # messages in the chat history. The old edit format will\nUSER # confused the new LLM. It may try and imitate it, disobeying\nUSER # the system prompt.\nUSER done_messages = from_coder.done_messages\nUSER if edit_format != from_coder.edit_format and done_messages and summarize_from_coder:\nUSER done_messages = from_coder.summarizer.summarize_all(done_messages)\nUSER \nUSER # Bring along context from the old Coder\nUSER update = dict(\nUSER fnames=list(from_coder.abs_fnames),\nUSER read_only_fnames=list(from_coder.abs_read_only_fnames), # Copy read-only files\nUSER done_messages=done_messages,\nUSER cur_messages=from_coder.cur_messages,\nUSER aider_commit_hashes=from_coder.aider_commit_hashes,\nUSER commands=from_coder.commands.clone(),\nUSER total_cost=from_coder.total_cost,\nUSER ignore_mentions=from_coder.ignore_mentions,\nUSER file_watcher=from_coder.file_watcher,\nUSER )\nUSER use_kwargs.update(update) # override to complete the switch\nUSER use_kwargs.update(kwargs) # override passed kwargs\nUSER \nUSER kwargs = use_kwargs\nUSER \nUSER for coder in coders.__all__:\nUSER if hasattr(coder, \"edit_format\") and coder.edit_format == edit_format:\nUSER res = coder(main_model, io, **kwargs)\nUSER res.original_kwargs = dict(kwargs)\nUSER return res\nUSER \nUSER valid_formats = [\nUSER str(c.edit_format)\nUSER for c in coders.__all__\nUSER if hasattr(c, \"edit_format\") and c.edit_format is not None\nUSER ]\nUSER raise UnknownEditFormat(edit_format, valid_formats)\nUSER \nUSER def clone(self, **kwargs):\nUSER new_coder = Coder.create(from_coder=self, **kwargs)\nUSER return new_coder\nUSER \nUSER def get_announcements(self):\nUSER lines = []\nUSER lines.append(f\"Aider v{__version__}\")\nUSER \nUSER # Model\nUSER main_model = self.main_model\nUSER weak_model = main_model.weak_model\nUSER \nUSER if weak_model is not main_model:\nUSER prefix = \"Main model\"\nUSER else:\nUSER prefix = \"Model\"\nUSER \nUSER output = f\"{prefix}: {main_model.name} with {self.edit_format} edit format\"\nUSER if self.add_cache_headers or main_model.caches_by_default:\nUSER output += \", prompt cache\"\nUSER if main_model.info.get(\"supports_assistant_prefill\"):\nUSER output += \", infinite output\"\nUSER lines.append(output)\nUSER \nUSER if self.edit_format == \"architect\":\nUSER output = (\nUSER f\"Editor model: {main_model.editor_model.name} with\"\nUSER f\" {main_model.editor_edit_format} edit format\"\nUSER )\nUSER lines.append(output)\nUSER \nUSER if weak_model is not main_model:\nUSER output = f\"Weak model: {weak_model.name}\"\nUSER lines.append(output)\nUSER \nUSER # Repo\nUSER if self.repo:\nUSER rel_repo_dir = self.repo.get_rel_repo_dir()\nUSER num_files = len(self.repo.get_tracked_files())\nUSER \nUSER lines.append(f\"Git repo: {rel_repo_dir} with {num_files:,} files\")\nUSER if num_files > 1000:\nUSER lines.append(\nUSER \"Warning: For large repos, consider using --subtree-only and .aiderignore\"\nUSER )\nUSER lines.append(f\"See: {urls.large_repos}\")\nUSER else:\nUSER lines.append(\"Git repo: none\")\nUSER \nUSER # Repo-map\nUSER if self.repo_map:\nUSER map_tokens = self.repo_map.max_map_tokens\nUSER if map_tokens > 0:\nUSER refresh = self.repo_map.refresh\nUSER lines.append(f\"Repo-map: using {map_tokens} tokens, {refresh} refresh\")\nUSER max_map_tokens = self.main_model.get_repo_map_tokens() * 2\nUSER if map_tokens > max_map_tokens:\nUSER lines.append(\nUSER f\"Warning: map-tokens > {max_map_tokens} is not recommended. Too much\"\nUSER \" irrelevant code can confuse LLMs.\"\nUSER )\nUSER else:\nUSER lines.append(\"Repo-map: disabled because map_tokens == 0\")\nUSER else:\nUSER lines.append(\"Repo-map: disabled\")\nUSER \nUSER # Files\nUSER for fname in self.get_inchat_relative_files():\nUSER lines.append(f\"Added {fname} to the chat.\")\nUSER \nUSER for fname in self.abs_read_only_fnames:\nUSER rel_fname = self.get_rel_fname(fname)\nUSER lines.append(f\"Added {rel_fname} to the chat (read-only).\")\nUSER \nUSER if self.done_messages:\nUSER lines.append(\"Restored previous conversation history.\")\nUSER \nUSER if self.io.multiline_mode:\nUSER lines.append(\"Multiline mode: Enabled. Enter inserts newline, Alt-Enter submits text\")\nUSER \nUSER return lines\nUSER \nUSER def __init__(\nUSER self,\nUSER main_model,\nUSER io,\nUSER repo=None,\nUSER fnames=None,\nUSER read_only_fnames=None,\nUSER show_diffs=False,\nUSER auto_commits=True,\nUSER dirty_commits=True,\nUSER dry_run=False,\nUSER map_tokens=1024,\nUSER verbose=False,\nUSER stream=True,\nUSER use_git=True,\nUSER cur_messages=None,\nUSER done_messages=None,\nUSER restore_chat_history=False,\nUSER auto_lint=True,\nUSER auto_test=False,\nUSER lint_cmds=None,\nUSER test_cmd=None,\nUSER aider_commit_hashes=None,\nUSER map_mul_no_files=8,\nUSER commands=None,\nUSER summarizer=None,\nUSER total_cost=0.0,\nUSER analytics=None,\nUSER map_refresh=\"auto\",\nUSER cache_prompts=False,\nUSER num_cache_warming_pings=0,\nUSER suggest_shell_commands=True,\nUSER chat_language=None,\nUSER detect_urls=True,\nUSER ignore_mentions=None,\nUSER file_watcher=None,\nUSER auto_copy_context=False,\nUSER ):\nUSER # Fill in a dummy Analytics if needed, but it is never .enable()'d\nUSER self.analytics = analytics if analytics is not None else Analytics()\nUSER \nUSER self.event = self.analytics.event\nUSER self.chat_language = chat_language\nUSER self.commit_before_message = []\nUSER self.aider_commit_hashes = set()\nUSER self.rejected_urls = set()\nUSER self.abs_root_path_cache = {}\nUSER \nUSER self.auto_copy_context = auto_copy_context\nUSER \nUSER self.ignore_mentions = ignore_mentions\nUSER if not self.ignore_mentions:\nUSER self.ignore_mentions = set()\nUSER \nUSER self.file_watcher = file_watcher\nUSER if self.file_watcher:\nUSER self.file_watcher.coder = self\nUSER \nUSER self.suggest_shell_commands = suggest_shell_commands\nUSER self.detect_urls = detect_urls\nUSER \nUSER self.num_cache_warming_pings = num_cache_warming_pings\nUSER \nUSER if not fnames:\nUSER fnames = []\nUSER \nUSER if io is None:\nUSER io = InputOutput()\nUSER \nUSER if aider_commit_hashes:\nUSER self.aider_commit_hashes = aider_commit_hashes\nUSER else:\nUSER self.aider_commit_hashes = set()\nUSER \nUSER self.chat_completion_call_hashes = []\nUSER self.chat_completion_response_hashes = []\nUSER self.need_commit_before_edits = set()\nUSER \nUSER self.total_cost = total_cost\nUSER \nUSER self.verbose = verbose\nUSER self.abs_fnames = set()\nUSER self.abs_read_only_fnames = set()\nUSER \nUSER if cur_messages:\nUSER self.cur_messages = cur_messages\nUSER else:\nUSER self.cur_messages = []\nUSER \nUSER if done_messages:\nUSER self.done_messages = done_messages\nUSER else:\nUSER self.done_messages = []\nUSER \nUSER self.io = io\nUSER \nUSER self.shell_commands = []\nUSER \nUSER if not auto_commits:\nUSER dirty_commits = False\nUSER \nUSER self.auto_commits = auto_commits\nUSER self.dirty_commits = dirty_commits\nUSER \nUSER self.dry_run = dry_run\nUSER self.pretty = self.io.pretty\nUSER \nUSER self.main_model = main_model\nUSER \nUSER self.stream = stream and main_model.streaming\nUSER \nUSER if cache_prompts and self.main_model.cache_control:\nUSER self.add_cache_headers = True\nUSER \nUSER self.show_diffs = show_diffs\nUSER \nUSER self.commands = commands or Commands(self.io, self)\nUSER self.commands.coder = self\nUSER \nUSER self.repo = repo\nUSER if use_git and self.repo is None:\nUSER try:\nUSER self.repo = GitRepo(\nUSER self.io,\nUSER fnames,\nUSER None,\nUSER models=main_model.commit_message_models(),\nUSER )\nUSER except FileNotFoundError:\nUSER pass\nUSER \nUSER if self.repo:\nUSER self.root = self.repo.root\nUSER \nUSER for fname in fnames:\nUSER fname = Path(fname)\nUSER if self.repo and self.repo.git_ignored_file(fname):\nUSER self.io.tool_warning(f\"Skipping {fname} that matches gitignore spec.\")\nUSER \nUSER if self.repo and self.repo.ignored_file(fname):\nUSER self.io.tool_warning(f\"Skipping {fname} that matches aiderignore spec.\")\nUSER continue\nUSER \nUSER if not fname.exists():\nUSER if utils.touch_file(fname):\nUSER self.io.tool_output(f\"Creating empty file {fname}\")\nUSER else:\nUSER self.io.tool_warning(f\"Can not create {fname}, skipping.\")\nUSER continue\nUSER \nUSER if not fname.is_file():\nUSER self.io.tool_warning(f\"Skipping {fname} that is not a normal file.\")\nUSER continue\nUSER \nUSER fname = str(fname.resolve())\nUSER \nUSER self.abs_fnames.add(fname)\nUSER self.check_added_files()\nUSER \nUSER if not self.repo:\nUSER self.root = utils.find_common_root(self.abs_fnames)\nUSER \nUSER if read_only_fnames:\nUSER self.abs_read_only_fnames = set()\nUSER for fname in read_only_fnames:\nUSER abs_fname = self.abs_root_path(fname)\nUSER if os.path.exists(abs_fname):\nUSER self.abs_read_only_fnames.add(abs_fname)\nUSER else:\nUSER self.io.tool_warning(f\"Error: Read-only file {fname} does not exist. Skipping.\")\nUSER \nUSER if map_tokens is None:\nUSER use_repo_map = main_model.use_repo_map\nUSER map_tokens = 1024\nUSER else:\nUSER use_repo_map = map_tokens > 0\nUSER \nUSER max_inp_tokens = self.main_model.info.get(\"max_input_tokens\") or 0\nUSER \nUSER has_map_prompt = hasattr(self, \"gpt_prompts\") and self.gpt_prompts.repo_content_prefix\nUSER \nUSER if use_repo_map and self.repo and has_map_prompt:\nUSER self.repo_map = RepoMap(\nUSER map_tokens,\nUSER self.root,\nUSER self.main_model,\nUSER io,\nUSER self.gpt_prompts.repo_content_prefix,\nUSER self.verbose,\nUSER max_inp_tokens,\nUSER map_mul_no_files=map_mul_no_files,\nUSER refresh=map_refresh,\nUSER )\nUSER \nUSER self.summarizer = summarizer or ChatSummary(\nUSER [self.main_model.weak_model, self.main_model],\nUSER self.main_model.max_chat_history_tokens,\nUSER )\nUSER \nUSER self.summarizer_thread = None\nUSER self.summarized_done_messages = []\nUSER self.summarizing_messages = None\nUSER \nUSER if not self.done_messages and restore_chat_history:\nUSER history_md = self.io.read_text(self.io.chat_history_file)\nUSER if history_md:\nUSER self.done_messages = utils.split_chat_history_markdown(history_md)\nUSER self.summarize_start()\nUSER \nUSER # Linting and testing\nUSER self.linter = Linter(root=self.root, encoding=io.encoding)\nUSER self.auto_lint = auto_lint\nUSER self.setup_lint_cmds(lint_cmds)\nUSER self.lint_cmds = lint_cmds\nUSER self.auto_test = auto_test\nUSER self.test_cmd = test_cmd\nUSER \nUSER # validate the functions jsonschema\nUSER if self.functions:\nUSER from jsonschema import Draft7Validator\nUSER \nUSER for function in self.functions:\nUSER Draft7Validator.check_schema(function)\nUSER \nUSER if self.verbose:\nUSER self.io.tool_output(\"JSON Schema:\")\nUSER self.io.tool_output(json.dumps(self.functions, indent=4))\nUSER \nUSER def setup_lint_cmds(self, lint_cmds):\nUSER if not lint_cmds:\nUSER return\nUSER for lang, cmd in lint_cmds.items():\nUSER self.linter.set_linter(lang, cmd)\nUSER \nUSER def show_announcements(self):\nUSER bold = True\nUSER for line in self.get_announcements():\nUSER self.io.tool_output(line, bold=bold)\nUSER bold = False\nUSER \nUSER def add_rel_fname(self, rel_fname):\nUSER self.abs_fnames.add(self.abs_root_path(rel_fname))\nUSER self.check_added_files()\nUSER \nUSER def drop_rel_fname(self, fname):\nUSER abs_fname = self.abs_root_path(fname)\nUSER if abs_fname in self.abs_fnames:\nUSER self.abs_fnames.remove(abs_fname)\nUSER return True\nUSER \nUSER def abs_root_path(self, path):\nUSER key = path\nUSER if key in self.abs_root_path_cache:\nUSER return self.abs_root_path_cache[key]\nUSER \nUSER res = Path(self.root) / path\nUSER res = utils.safe_abs_path(res)\nUSER self.abs_root_path_cache[key] = res\nUSER return res\nUSER \nUSER fences = all_fences\nUSER fence = fences[0]\nUSER \nUSER def show_pretty(self):\nUSER if not self.pretty:\nUSER return False\nUSER \nUSER # only show pretty output if fences are the normal triple-backtick\nUSER if self.fence[0][0] != \"`\":\nUSER return False\nUSER \nUSER return True\nUSER \nUSER def get_abs_fnames_content(self):\nUSER for fname in list(self.abs_fnames):\nUSER content = self.io.read_text(fname)\nUSER \nUSER if content is None:\nUSER relative_fname = self.get_rel_fname(fname)\nUSER self.io.tool_warning(f\"Dropping {relative_fname} from the chat.\")\nUSER self.abs_fnames.remove(fname)\nUSER else:\nUSER yield fname, content\nUSER \nUSER def choose_fence(self):\nUSER all_content = \"\"\nUSER for _fname, content in self.get_abs_fnames_content():\nUSER all_content += content + \"\\n\"\nUSER for _fname in self.abs_read_only_fnames:\nUSER content = self.io.read_text(_fname)\nUSER if content is not None:\nUSER all_content += content + \"\\n\"\nUSER \nUSER lines = all_content.splitlines()\nUSER good = False\nUSER for fence_open, fence_close in self.fences:\nUSER if any(line.startswith(fence_open) or line.startswith(fence_close) for line in lines):\nUSER continue\nUSER good = True\nUSER break\nUSER \nUSER if good:\nUSER self.fence = (fence_open, fence_close)\nUSER else:\nUSER self.fence = self.fences[0]\nUSER self.io.tool_warning(\nUSER \"Unable to find a fencing strategy! Falling back to:\"\nUSER f\" {self.fence[0]}...{self.fence[1]}\"\nUSER )\nUSER \nUSER return\nUSER \nUSER def get_files_content(self, fnames=None):\nUSER if not fnames:\nUSER fnames = self.abs_fnames\nUSER \nUSER prompt = \"\"\nUSER for fname, content in self.get_abs_fnames_content():\nUSER if not is_image_file(fname):\nUSER relative_fname = self.get_rel_fname(fname)\nUSER prompt += \"\\n\"\nUSER prompt += relative_fname\nUSER prompt += f\"\\n{self.fence[0]}\\n\"\nUSER \nUSER prompt += content\nUSER \nUSER # lines = content.splitlines(keepends=True)\nUSER # lines = [f\"{i+1:03}:{line}\" for i, line in enumerate(lines)]\nUSER # prompt += \"\".join(lines)\nUSER \nUSER prompt += f\"{self.fence[1]}\\n\"\nUSER \nUSER return prompt\nUSER \nUSER def get_read_only_files_content(self):\nUSER prompt = \"\"\nUSER for fname in self.abs_read_only_fnames:\nUSER content = self.io.read_text(fname)\nUSER if content is not None and not is_image_file(fname):\nUSER relative_fname = self.get_rel_fname(fname)\nUSER prompt += \"\\n\"\nUSER prompt += relative_fname\nUSER prompt += f\"\\n{self.fence[0]}\\n\"\nUSER prompt += content\nUSER prompt += f\"{self.fence[1]}\\n\"\nUSER return prompt\nUSER \nUSER def get_cur_message_text(self):\nUSER text = \"\"\nUSER for msg in self.cur_messages:\nUSER text += msg[\"content\"] + \"\\n\"\nUSER return text\nUSER \nUSER def get_ident_mentions(self, text):\nUSER # Split the string on any character that is not alphanumeric\nUSER # \\W+ matches one or more non-word characters (equivalent to [^a-zA-Z0-9_]+)\nUSER words = set(re.split(r\"\\W+\", text))\nUSER return words\nUSER \nUSER def get_ident_filename_matches(self, idents):\nUSER all_fnames = defaultdict(set)\nUSER for fname in self.get_all_relative_files():\nUSER # Skip empty paths or just '.'\nUSER if not fname or fname == \".\":\nUSER continue\nUSER \nUSER try:\nUSER # Handle dotfiles properly\nUSER path = Path(fname)\nUSER base = path.stem.lower() # Use stem instead of with_suffix(\"\").name\nUSER if len(base) >= 5:\nUSER all_fnames[base].add(fname)\nUSER except ValueError:\nUSER # Skip paths that can't be processed\nUSER continue\nUSER \nUSER matches = set()\nUSER for ident in idents:\nUSER if len(ident) < 5:\nUSER continue\nUSER matches.update(all_fnames[ident.lower()])\nUSER \nUSER return matches\nUSER \nUSER def get_repo_map(self, force_refresh=False):\nUSER if not self.repo_map:\nUSER return\nUSER \nUSER cur_msg_text = self.get_cur_message_text()\nUSER mentioned_fnames = self.get_file_mentions(cur_msg_text)\nUSER mentioned_idents = self.get_ident_mentions(cur_msg_text)\nUSER \nUSER mentioned_fnames.update(self.get_ident_filename_matches(mentioned_idents))\nUSER \nUSER all_abs_files = set(self.get_all_abs_files())\nUSER repo_abs_read_only_fnames = set(self.abs_read_only_fnames) & all_abs_files\nUSER chat_files = set(self.abs_fnames) | repo_abs_read_only_fnames\nUSER other_files = all_abs_files - chat_files\nUSER \nUSER repo_content = self.repo_map.get_repo_map(\nUSER chat_files,\nUSER other_files,\nUSER mentioned_fnames=mentioned_fnames,\nUSER mentioned_idents=mentioned_idents,\nUSER force_refresh=force_refresh,\nUSER )\nUSER \nUSER # fall back to global repo map if files in chat are disjoint from rest of repo\nUSER if not repo_content:\nUSER repo_content = self.repo_map.get_repo_map(\nUSER set(),\nUSER all_abs_files,\nUSER mentioned_fnames=mentioned_fnames,\nUSER mentioned_idents=mentioned_idents,\nUSER )\nUSER \nUSER # fall back to completely unhinted repo\nUSER if not repo_content:\nUSER repo_content = self.repo_map.get_repo_map(\nUSER set(),\nUSER all_abs_files,\nUSER )\nUSER \nUSER return repo_content\nUSER \nUSER def get_repo_messages(self):\nUSER repo_messages = []\nUSER repo_content = self.get_repo_map()\nUSER if repo_content:\nUSER repo_messages += [\nUSER dict(role=\"user\", content=repo_content),\nUSER dict(\nUSER role=\"assistant\",\nUSER content=\"Ok, I won't try and edit those files without asking first.\",\nUSER ),\nUSER ]\nUSER return repo_messages\nUSER \nUSER def get_readonly_files_messages(self):\nUSER readonly_messages = []\nUSER \nUSER # Handle non-image files\nUSER read_only_content = self.get_read_only_files_content()\nUSER if read_only_content:\nUSER readonly_messages += [\nUSER dict(\nUSER role=\"user\", content=self.gpt_prompts.read_only_files_prefix + read_only_content\nUSER ),\nUSER dict(\nUSER role=\"assistant\",\nUSER content=\"Ok, I will use these files as references.\",\nUSER ),\nUSER ]\nUSER \nUSER # Handle image files\nUSER images_message = self.get_images_message(self.abs_read_only_fnames)\nUSER if images_message is not None:\nUSER readonly_messages += [\nUSER images_message,\nUSER dict(role=\"assistant\", content=\"Ok, I will use these images as references.\"),\nUSER ]\nUSER \nUSER return readonly_messages\nUSER \nUSER def get_chat_files_messages(self):\nUSER chat_files_messages = []\nUSER if self.abs_fnames:\nUSER files_content = self.gpt_prompts.files_content_prefix\nUSER files_content += self.get_files_content()\nUSER files_reply = self.gpt_prompts.files_content_assistant_reply\nUSER elif self.get_repo_map() and self.gpt_prompts.files_no_full_files_with_repo_map:\nUSER files_content = self.gpt_prompts.files_no_full_files_with_repo_map\nUSER files_reply = self.gpt_prompts.files_no_full_files_with_repo_map_reply\nUSER else:\nUSER files_content = self.gpt_prompts.files_no_full_files\nUSER files_reply = \"Ok.\"\nUSER \nUSER if files_content:\nUSER chat_files_messages += [\nUSER dict(role=\"user\", content=files_content),\nUSER dict(role=\"assistant\", content=files_reply),\nUSER ]\nUSER \nUSER images_message = self.get_images_message(self.abs_fnames)\nUSER if images_message is not None:\nUSER chat_files_messages += [\nUSER images_message,\nUSER dict(role=\"assistant\", content=\"Ok.\"),\nUSER ]\nUSER \nUSER return chat_files_messages\nUSER \nUSER def get_images_message(self, fnames):\nUSER supports_images = self.main_model.info.get(\"supports_vision\")\nUSER supports_pdfs = self.main_model.info.get(\"supports_pdf_input\") or self.main_model.info.get(\nUSER \"max_pdf_size_mb\"\nUSER )\nUSER \nUSER # https://github.com/BerriAI/litellm/pull/6928\nUSER supports_pdfs = supports_pdfs or \"claude-3-5-sonnet-20241022\" in self.main_model.name\nUSER \nUSER if not (supports_images or supports_pdfs):\nUSER return None\nUSER \nUSER image_messages = []\nUSER for fname in fnames:\nUSER if not is_image_file(fname):\nUSER continue\nUSER \nUSER mime_type, _ = mimetypes.guess_type(fname)\nUSER if not mime_type:\nUSER continue\nUSER \nUSER with open(fname, \"rb\") as image_file:\nUSER encoded_string = base64.b64encode(image_file.read()).decode(\"utf-8\")\nUSER image_url = f\"data:{mime_type};base64,{encoded_string}\"\nUSER rel_fname = self.get_rel_fname(fname)\nUSER \nUSER if mime_type.startswith(\"image/\") and supports_images:\nUSER image_messages += [\nUSER {\"type\": \"text\", \"text\": f\"Image file: {rel_fname}\"},\nUSER {\"type\": \"image_url\", \"image_url\": {\"url\": image_url, \"detail\": \"high\"}},\nUSER ]\nUSER elif mime_type == \"application/pdf\" and supports_pdfs:\nUSER image_messages += [\nUSER {\"type\": \"text\", \"text\": f\"PDF file: {rel_fname}\"},\nUSER {\"type\": \"image_url\", \"image_url\": image_url},\nUSER ]\nUSER \nUSER if not image_messages:\nUSER return None\nUSER \nUSER return {\"role\": \"user\", \"content\": image_messages}\nUSER \nUSER def run_stream(self, user_message):\nUSER self.io.user_input(user_message)\nUSER self.init_before_message()\nUSER yield from self.send_message(user_message)\nUSER \nUSER def init_before_message(self):\nUSER self.aider_edited_files = set()\nUSER self.reflected_message = None\nUSER self.num_reflections = 0\nUSER self.lint_outcome = None\nUSER self.test_outcome = None\nUSER self.shell_commands = []\nUSER self.message_cost = 0\nUSER \nUSER if self.repo:\nUSER self.commit_before_message.append(self.repo.get_head_commit_sha())\nUSER \nUSER def run(self, with_message=None, preproc=True):\nUSER try:\nUSER if with_message:\nUSER self.io.user_input(with_message)\nUSER self.run_one(with_message, preproc)\nUSER return self.partial_response_content\nUSER while True:\nUSER try:\nUSER if not self.io.placeholder:\nUSER self.copy_context()\nUSER user_message = self.get_input()\nUSER self.run_one(user_message, preproc)\nUSER self.show_undo_hint()\nUSER except KeyboardInterrupt:\nUSER self.keyboard_interrupt()\nUSER except EOFError:\nUSER return\nUSER \nUSER def copy_context(self):\nUSER if self.auto_copy_context:\nUSER self.commands.cmd_copy_context()\nUSER \nUSER def get_input(self):\nUSER inchat_files = self.get_inchat_relative_files()\nUSER read_only_files = [self.get_rel_fname(fname) for fname in self.abs_read_only_fnames]\nUSER all_files = sorted(set(inchat_files + read_only_files))\nUSER edit_format = \"\" if self.edit_format == self.main_model.edit_format else self.edit_format\nUSER return self.io.get_input(\nUSER self.root,\nUSER all_files,\nUSER self.get_addable_relative_files(),\nUSER self.commands,\nUSER self.abs_read_only_fnames,\nUSER edit_format=edit_format,\nUSER )\nUSER \nUSER def preproc_user_input(self, inp):\nUSER if not inp:\nUSER return\nUSER \nUSER if self.commands.is_command(inp):\nUSER return self.commands.run(inp)\nUSER \nUSER self.check_for_file_mentions(inp)\nUSER inp = self.check_for_urls(inp)\nUSER \nUSER return inp\nUSER \nUSER def run_one(self, user_message, preproc):\nUSER self.init_before_message()\nUSER \nUSER if preproc:\nUSER message = self.preproc_user_input(user_message)\nUSER else:\nUSER message = user_message\nUSER \nUSER while message:\nUSER self.reflected_message = None\nUSER list(self.send_message(message))\nUSER \nUSER if not self.reflected_message:\nUSER break\nUSER \nUSER if self.num_reflections >= self.max_reflections:\nUSER self.io.tool_warning(f\"Only {self.max_reflections} reflections allowed, stopping.\")\nUSER return\nUSER \nUSER self.num_reflections += 1\nUSER message = self.reflected_message\nUSER \nUSER def check_and_open_urls(self, exc, friendly_msg=None):\nUSER \"\"\"Check exception for URLs, offer to open in a browser, with user-friendly error msgs.\"\"\"\nUSER text = str(exc)\nUSER \nUSER if friendly_msg:\nUSER self.io.tool_warning(text)\nUSER self.io.tool_error(f\"{friendly_msg}\")\nUSER else:\nUSER self.io.tool_error(text)\nUSER \nUSER url_pattern = re.compile(r\"(https?://[^\\s/$.?#].[^\\s]*)\")\nUSER urls = list(set(url_pattern.findall(text))) # Use set to remove duplicates\nUSER for url in urls:\nUSER url = url.rstrip(\".',\\\"\")\nUSER self.io.offer_url(url)\nUSER return urls\nUSER \nUSER def check_for_urls(self, inp: str) -> List[str]:\nUSER \"\"\"Check input for URLs and offer to add them to the chat.\"\"\"\nUSER if not self.detect_urls:\nUSER return inp\nUSER \nUSER url_pattern = re.compile(r\"(https?://[^\\s/$.?#].[^\\s]*[^\\s,.])\")\nUSER urls = list(set(url_pattern.findall(inp))) # Use set to remove duplicates\nUSER group = ConfirmGroup(urls)\nUSER for url in urls:\nUSER if url not in self.rejected_urls:\nUSER url = url.rstrip(\".',\\\"\")\nUSER if self.io.confirm_ask(\nUSER \"Add URL to the chat?\", subject=url, group=group, allow_never=True\nUSER ):\nUSER inp += \"\\n\\n\"\nUSER inp += self.commands.cmd_web(url, return_content=True)\nUSER else:\nUSER self.rejected_urls.add(url)\nUSER \nUSER return inp\nUSER \nUSER def keyboard_interrupt(self):\nUSER now = time.time()\nUSER \nUSER thresh = 2 # seconds\nUSER if self.last_keyboard_interrupt and now - self.last_keyboard_interrupt < thresh:\nUSER self.io.tool_warning(\"\\n\\n^C KeyboardInterrupt\")\nUSER self.event(\"exit\", reason=\"Control-C\")\nUSER sys.exit()\nUSER \nUSER self.io.tool_warning(\"\\n\\n^C again to exit\")\nUSER \nUSER self.last_keyboard_interrupt = now\nUSER \nUSER def summarize_start(self):\nUSER if not self.summarizer.too_big(self.done_messages):\nUSER return\nUSER \nUSER self.summarize_end()\nUSER \nUSER if self.verbose:\nUSER self.io.tool_output(\"Starting to summarize chat history.\")\nUSER \nUSER self.summarizer_thread = threading.Thread(target=self.summarize_worker)\nUSER self.summarizer_thread.start()\nUSER \nUSER def summarize_worker(self):\nUSER self.summarizing_messages = list(self.done_messages)\nUSER try:\nUSER self.summarized_done_messages = self.summarizer.summarize(self.summarizing_messages)\nUSER except ValueError as err:\nUSER self.io.tool_warning(err.args[0])\nUSER \nUSER if self.verbose:\nUSER self.io.tool_output(\"Finished summarizing chat history.\")\nUSER \nUSER def summarize_end(self):\nUSER if self.summarizer_thread is None:\nUSER return\nUSER \nUSER self.summarizer_thread.join()\nUSER self.summarizer_thread = None\nUSER \nUSER if self.summarizing_messages == self.done_messages:\nUSER self.done_messages = self.summarized_done_messages\nUSER self.summarizing_messages = None\nUSER self.summarized_done_messages = []\nUSER \nUSER def move_back_cur_messages(self, message):\nUSER self.done_messages += self.cur_messages\nUSER self.summarize_start()\nUSER \nUSER # TODO check for impact on image messages\nUSER if message:\nUSER self.done_messages += [\nUSER dict(role=\"user\", content=message),\nUSER dict(role=\"assistant\", content=\"Ok.\"),\nUSER ]\nUSER self.cur_messages = []\nUSER \nUSER def get_user_language(self):\nUSER if self.chat_language:\nUSER return self.chat_language\nUSER \nUSER try:\nUSER lang = locale.getlocale()[0]\nUSER if lang:\nUSER return lang # Return the full language code, including country\nUSER except Exception:\nUSER pass\nUSER \nUSER for env_var in [\"LANG\", \"LANGUAGE\", \"LC_ALL\", \"LC_MESSAGES\"]:\nUSER lang = os.environ.get(env_var)\nUSER if lang:\nUSER return lang.split(\".\")[\nUSER 0\nUSER ] # Return language and country, but remove encoding if present\nUSER \nUSER return None\nUSER \nUSER def get_platform_info(self):\nUSER platform_text = f\"- Platform: {platform.platform()}\\n\"\nUSER shell_var = \"COMSPEC\" if os.name == \"nt\" else \"SHELL\"\nUSER shell_val = os.getenv(shell_var)\nUSER platform_text += f\"- Shell: {shell_var}={shell_val}\\n\"\nUSER \nUSER user_lang = self.get_user_language()\nUSER if user_lang:\nUSER platform_text += f\"- Language: {user_lang}\\n\"\nUSER \nUSER dt = datetime.now().astimezone().strftime(\"%Y-%m-%d\")\nUSER platform_text += f\"- Current date: {dt}\\n\"\nUSER \nUSER if self.repo:\nUSER platform_text += \"- The user is operating inside a git repository\\n\"\nUSER \nUSER if self.lint_cmds:\nUSER if self.auto_lint:\nUSER platform_text += (\nUSER \"- The user's pre-commit runs these lint commands, don't suggest running\"\nUSER \" them:\\n\"\nUSER )\nUSER else:\nUSER platform_text += \"- The user prefers these lint commands:\\n\"\nUSER for lang, cmd in self.lint_cmds.items():\nUSER if lang is None:\nUSER platform_text += f\" - {cmd}\\n\"\nUSER else:\nUSER platform_text += f\" - {lang}: {cmd}\\n\"\nUSER \nUSER if self.test_cmd:\nUSER if self.auto_test:\nUSER platform_text += (\nUSER \"- The user's pre-commit runs this test command, don't suggest running them: \"\nUSER )\nUSER else:\nUSER platform_text += \"- The user prefers this test command: \"\nUSER platform_text += self.test_cmd + \"\\n\"\nUSER \nUSER return platform_text\nUSER \nUSER def fmt_system_prompt(self, prompt):\nUSER lazy_prompt = self.gpt_prompts.lazy_prompt if self.main_model.lazy else \"\"\nUSER platform_text = self.get_platform_info()\nUSER \nUSER if self.suggest_shell_commands:\nUSER shell_cmd_prompt = self.gpt_prompts.shell_cmd_prompt.format(platform=platform_text)\nUSER shell_cmd_reminder = self.gpt_prompts.shell_cmd_reminder.format(platform=platform_text)\nUSER else:\nUSER shell_cmd_prompt = self.gpt_prompts.no_shell_cmd_prompt.format(platform=platform_text)\nUSER shell_cmd_reminder = self.gpt_prompts.no_shell_cmd_reminder.format(\nUSER platform=platform_text\nUSER )\nUSER \nUSER if self.chat_language:\nUSER language = self.chat_language\nUSER else:\nUSER language = \"the same language they are using\"\nUSER \nUSER prompt = prompt.format(\nUSER fence=self.fence,\nUSER lazy_prompt=lazy_prompt,\nUSER platform=platform_text,\nUSER shell_cmd_prompt=shell_cmd_prompt,\nUSER shell_cmd_reminder=shell_cmd_reminder,\nUSER language=language,\nUSER )\nUSER return prompt\nUSER \nUSER def format_chat_chunks(self):\nUSER self.choose_fence()\nUSER main_sys = self.fmt_system_prompt(self.gpt_prompts.main_system)\nUSER \nUSER example_messages = []\nUSER if self.main_model.examples_as_sys_msg:\nUSER if self.gpt_prompts.example_messages:\nUSER main_sys += \"\\n# Example conversations:\\n\\n\"\nUSER for msg in self.gpt_prompts.example_messages:\nUSER role = msg[\"role\"]\nUSER content = self.fmt_system_prompt(msg[\"content\"])\nUSER main_sys += f\"## {role.upper()}: {content}\\n\\n\"\nUSER main_sys = main_sys.strip()\nUSER else:\nUSER for msg in self.gpt_prompts.example_messages:\nUSER example_messages.append(\nUSER dict(\nUSER role=msg[\"role\"],\nUSER content=self.fmt_system_prompt(msg[\"content\"]),\nUSER )\nUSER )\nUSER if self.gpt_prompts.example_messages:\nUSER example_messages += [\nUSER dict(\nUSER role=\"user\",\nUSER content=(\nUSER \"I switched to a new code base. Please don't consider the above files\"\nUSER \" or try to edit them any longer.\"\nUSER ),\nUSER ),\nUSER dict(role=\"assistant\", content=\"Ok.\"),\nUSER ]\nUSER \nUSER if self.gpt_prompts.system_reminder:\nUSER main_sys += \"\\n\" + self.fmt_system_prompt(self.gpt_prompts.system_reminder)\nUSER \nUSER chunks = ChatChunks()\nUSER \nUSER if self.main_model.use_system_prompt:\nUSER chunks.system = [\nUSER dict(role=\"system\", content=main_sys),\nUSER ]\nUSER else:\nUSER chunks.system = [\nUSER dict(role=\"user\", content=main_sys),\nUSER dict(role=\"assistant\", content=\"Ok.\"),\nUSER ]\nUSER \nUSER chunks.examples = example_messages\nUSER \nUSER self.summarize_end()\nUSER chunks.done = self.done_messages\nUSER \nUSER chunks.repo = self.get_repo_messages()\nUSER chunks.readonly_files = self.get_readonly_files_messages()\nUSER chunks.chat_files = self.get_chat_files_messages()\nUSER \nUSER if self.gpt_prompts.system_reminder:\nUSER reminder_message = [\nUSER dict(\nUSER role=\"system\", content=self.fmt_system_prompt(self.gpt_prompts.system_reminder)\nUSER ),\nUSER ]\nUSER else:\nUSER reminder_message = []\nUSER \nUSER chunks.cur = list(self.cur_messages)\nUSER chunks.reminder = []\nUSER \nUSER # TODO review impact of token count on image messages\nUSER messages_tokens = self.main_model.token_count(chunks.all_messages())\nUSER reminder_tokens = self.main_model.token_count(reminder_message)\nUSER cur_tokens = self.main_model.token_count(chunks.cur)\nUSER \nUSER if None not in (messages_tokens, reminder_tokens, cur_tokens):\nUSER total_tokens = messages_tokens + reminder_tokens + cur_tokens\nUSER else:\nUSER # add the reminder anyway\nUSER total_tokens = 0\nUSER \nUSER if chunks.cur:\nUSER final = chunks.cur[-1]\nUSER else:\nUSER final = None\nUSER \nUSER max_input_tokens = self.main_model.info.get(\"max_input_tokens\") or 0\nUSER # Add the reminder prompt if we still have room to include it.\nUSER if (\nUSER not max_input_tokens\nUSER or total_tokens < max_input_tokens\nUSER and self.gpt_prompts.system_reminder\nUSER ):\nUSER if self.main_model.reminder == \"sys\":\nUSER chunks.reminder = reminder_message\nUSER elif self.main_model.reminder == \"user\" and final and final[\"role\"] == \"user\":\nUSER # stuff it into the user message\nUSER new_content = (\nUSER final[\"content\"]\nUSER + \"\\n\\n\"\nUSER + self.fmt_system_prompt(self.gpt_prompts.system_reminder)\nUSER )\nUSER chunks.cur[-1] = dict(role=final[\"role\"], content=new_content)\nUSER \nUSER return chunks\nUSER \nUSER def format_messages(self):\nUSER chunks = self.format_chat_chunks()\nUSER if self.add_cache_headers:\nUSER chunks.add_cache_control_headers()\nUSER \nUSER return chunks\nUSER \nUSER def warm_cache(self, chunks):\nUSER if not self.add_cache_headers:\nUSER return\nUSER if not self.num_cache_warming_pings:\nUSER return\nUSER \nUSER delay = 5 * 60 - 5\nUSER self.next_cache_warm = time.time() + delay\nUSER self.warming_pings_left = self.num_cache_warming_pings\nUSER self.cache_warming_chunks = chunks\nUSER \nUSER if self.cache_warming_thread:\nUSER return\nUSER \nUSER def warm_cache_worker():\nUSER while True:\nUSER time.sleep(1)\nUSER if self.warming_pings_left <= 0:\nUSER continue\nUSER now = time.time()\nUSER if now < self.next_cache_warm:\nUSER continue\nUSER \nUSER self.warming_pings_left -= 1\nUSER self.next_cache_warm = time.time() + delay\nUSER \nUSER kwargs = dict(self.main_model.extra_params) or dict()\nUSER kwargs[\"max_tokens\"] = 1\nUSER \nUSER try:\nUSER completion = litellm.completion(\nUSER model=self.main_model.name,\nUSER messages=self.cache_warming_chunks.cacheable_messages(),\nUSER stream=False,\nUSER **kwargs,\nUSER )\nUSER except Exception as err:\nUSER self.io.tool_warning(f\"Cache warming error: {str(err)}\")\nUSER continue\nUSER \nUSER cache_hit_tokens = getattr(\nUSER completion.usage, \"prompt_cache_hit_tokens\", 0\nUSER ) or getattr(completion.usage, \"cache_read_input_tokens\", 0)\nUSER \nUSER if self.verbose:\nUSER self.io.tool_output(f\"Warmed {format_tokens(cache_hit_tokens)} cached tokens.\")\nUSER \nUSER self.cache_warming_thread = threading.Timer(0, warm_cache_worker)\nUSER self.cache_warming_thread.daemon = True\nUSER self.cache_warming_thread.start()\nUSER \nUSER return chunks\nUSER \nUSER def send_message(self, inp):\nUSER self.event(\"message_send_starting\")\nUSER \nUSER self.cur_messages += [\nUSER dict(role=\"user\", content=inp),\nUSER ]\nUSER \nUSER chunks = self.format_messages()\nUSER messages = chunks.all_messages()\nUSER self.warm_cache(chunks)\nUSER \nUSER if self.verbose:\nUSER utils.show_messages(messages, functions=self.functions)\nUSER \nUSER self.multi_response_content = \"\"\nUSER if self.show_pretty() and self.stream:\nUSER self.mdstream = self.io.get_assistant_mdstream()\nUSER else:\nUSER self.mdstream = None\nUSER \nUSER retry_delay = 0.125\nUSER \nUSER litellm_ex = LiteLLMExceptions()\nUSER \nUSER self.usage_report = None\nUSER exhausted = False\nUSER interrupted = False\nUSER try:\nUSER while True:\nUSER try:\nUSER yield from self.send(messages, functions=self.functions)\nUSER break\nUSER except litellm_ex.exceptions_tuple() as err:\nUSER ex_info = litellm_ex.get_ex_info(err)\nUSER \nUSER if ex_info.name == \"ContextWindowExceededError\":\nUSER exhausted = True\nUSER break\nUSER \nUSER should_retry = ex_info.retry\nUSER if should_retry:\nUSER retry_delay *= 2\nUSER if retry_delay > RETRY_TIMEOUT:\nUSER should_retry = False\nUSER \nUSER if not should_retry:\nUSER self.mdstream = None\nUSER self.check_and_open_urls(err, ex_info.description)\nUSER break\nUSER \nUSER err_msg = str(err)\nUSER if ex_info.description:\nUSER self.io.tool_warning(err_msg)\nUSER self.io.tool_error(ex_info.description)\nUSER else:\nUSER self.io.tool_error(err_msg)\nUSER \nUSER self.io.tool_output(f\"Retrying in {retry_delay:.1f} seconds...\")\nUSER time.sleep(retry_delay)\nUSER continue\nUSER except KeyboardInterrupt:\nUSER interrupted = True\nUSER break\nUSER except FinishReasonLength:\nUSER # We hit the output limit!\nUSER if not self.main_model.info.get(\"supports_assistant_prefill\"):\nUSER exhausted = True\nUSER break\nUSER \nUSER self.multi_response_content = self.get_multi_response_content()\nUSER \nUSER if messages[-1][\"role\"] == \"assistant\":\nUSER messages[-1][\"content\"] = self.multi_response_content\nUSER else:\nUSER messages.append(\nUSER dict(role=\"assistant\", content=self.multi_response_content, prefix=True)\nUSER )\nUSER except Exception as err:\nUSER self.mdstream = None\nUSER lines = traceback.format_exception(type(err), err, err.__traceback__)\nUSER self.io.tool_warning(\"\".join(lines))\nUSER self.io.tool_error(str(err))\nUSER self.event(\"message_send_exception\", exception=str(err))\nUSER return\nUSER finally:\nUSER if self.mdstream:\nUSER self.live_incremental_response(True)\nUSER self.mdstream = None\nUSER \nUSER self.partial_response_content = self.get_multi_response_content(True)\nUSER self.multi_response_content = \"\"\nUSER \nUSER self.io.tool_output()\nUSER \nUSER self.show_usage_report()\nUSER \nUSER self.add_assistant_reply_to_cur_messages()\nUSER \nUSER if exhausted:\nUSER if self.cur_messages and self.cur_messages[-1][\"role\"] == \"user\":\nUSER self.cur_messages += [\nUSER dict(\nUSER role=\"assistant\",\nUSER content=\"FinishReasonLength exception: you sent too many tokens\",\nUSER ),\nUSER ]\nUSER \nUSER self.show_exhausted_error()\nUSER self.num_exhausted_context_windows += 1\nUSER return\nUSER \nUSER if self.partial_response_function_call:\nUSER args = self.parse_partial_args()\nUSER if args:\nUSER content = args.get(\"explanation\") or \"\"\nUSER else:\nUSER content = \"\"\nUSER elif self.partial_response_content:\nUSER content = self.partial_response_content\nUSER else:\nUSER content = \"\"\nUSER \nUSER if not interrupted:\nUSER add_rel_files_message = self.check_for_file_mentions(content)\nUSER if add_rel_files_message:\nUSER if self.reflected_message:\nUSER self.reflected_message += \"\\n\\n\" + add_rel_files_message\nUSER else:\nUSER self.reflected_message = add_rel_files_message\nUSER return\nUSER \nUSER try:\nUSER self.reply_completed()\nUSER except KeyboardInterrupt:\nUSER interrupted = True\nUSER \nUSER if interrupted:\nUSER self.cur_messages += [\nUSER dict(role=\"user\", content=\"^C KeyboardInterrupt\"),\nUSER dict(role=\"assistant\", content=\"I see that you interrupted my previous reply.\"),\nUSER ]\nUSER return\nUSER \nUSER edited = self.apply_updates()\nUSER \nUSER if edited:\nUSER self.aider_edited_files.update(edited)\nUSER saved_message = self.auto_commit(edited)\nUSER \nUSER if not saved_message and hasattr(self.gpt_prompts, \"files_content_gpt_edits_no_repo\"):\nUSER saved_message = self.gpt_prompts.files_content_gpt_edits_no_repo\nUSER \nUSER self.move_back_cur_messages(saved_message)\nUSER \nUSER if self.reflected_message:\nUSER return\nUSER \nUSER if edited and self.auto_lint:\nUSER lint_errors = self.lint_edited(edited)\nUSER self.auto_commit(edited, context=\"Ran the linter\")\nUSER self.lint_outcome = not lint_errors\nUSER if lint_errors:\nUSER ok = self.io.confirm_ask(\"Attempt to fix lint errors?\")\nUSER if ok:\nUSER self.reflected_message = lint_errors\nUSER return\nUSER \nUSER shared_output = self.run_shell_commands()\nUSER if shared_output:\nUSER self.cur_messages += [\nUSER dict(role=\"user\", content=shared_output),\nUSER dict(role=\"assistant\", content=\"Ok\"),\nUSER ]\nUSER \nUSER if edited and self.auto_test:\nUSER test_errors = self.commands.cmd_test(self.test_cmd)\nUSER self.test_outcome = not test_errors\nUSER if test_errors:\nUSER ok = self.io.confirm_ask(\"Attempt to fix test errors?\")\nUSER if ok:\nUSER self.reflected_message = test_errors\nUSER return\nUSER \nUSER def reply_completed(self):\nUSER pass\nUSER \nUSER def show_exhausted_error(self):\nUSER output_tokens = 0\nUSER if self.partial_response_content:\nUSER output_tokens = self.main_model.token_count(self.partial_response_content)\nUSER max_output_tokens = self.main_model.info.get(\"max_output_tokens\") or 0\nUSER \nUSER input_tokens = self.main_model.token_count(self.format_messages().all_messages())\nUSER max_input_tokens = self.main_model.info.get(\"max_input_tokens\") or 0\nUSER \nUSER total_tokens = input_tokens + output_tokens\nUSER \nUSER fudge = 0.7\nUSER \nUSER out_err = \"\"\nUSER if output_tokens >= max_output_tokens * fudge:\nUSER out_err = \" -- possibly exceeded output limit!\"\nUSER \nUSER inp_err = \"\"\nUSER if input_tokens >= max_input_tokens * fudge:\nUSER inp_err = \" -- possibly exhausted context window!\"\nUSER \nUSER tot_err = \"\"\nUSER if total_tokens >= max_input_tokens * fudge:\nUSER tot_err = \" -- possibly exhausted context window!\"\nUSER \nUSER res = [\"\", \"\"]\nUSER res.append(f\"Model {self.main_model.name} has hit a token limit!\")\nUSER res.append(\"Token counts below are approximate.\")\nUSER res.append(\"\")\nUSER res.append(f\"Input tokens: ~{input_tokens:,} of {max_input_tokens:,}{inp_err}\")\nUSER res.append(f\"Output tokens: ~{output_tokens:,} of {max_output_tokens:,}{out_err}\")\nUSER res.append(f\"Total tokens: ~{total_tokens:,} of {max_input_tokens:,}{tot_err}\")\nUSER \nUSER if output_tokens >= max_output_tokens:\nUSER res.append(\"\")\nUSER res.append(\"To reduce output tokens:\")\nUSER res.append(\"- Ask for smaller changes in each request.\")\nUSER res.append(\"- Break your code into smaller source files.\")\nUSER if \"diff\" not in self.main_model.edit_format:\nUSER res.append(\"- Use a stronger model that can return diffs.\")\nUSER \nUSER if input_tokens >= max_input_tokens or total_tokens >= max_input_tokens:\nUSER res.append(\"\")\nUSER res.append(\"To reduce input tokens:\")\nUSER res.append(\"- Use /tokens to see token usage.\")\nUSER res.append(\"- Use /drop to remove unneeded files from the chat session.\")\nUSER res.append(\"- Use /clear to clear the chat history.\")\nUSER res.append(\"- Break your code into smaller source files.\")\nUSER \nUSER res = \"\".join([line + \"\\n\" for line in res])\nUSER self.io.tool_error(res)\nUSER self.io.offer_url(urls.token_limits)\nUSER \nUSER def lint_edited(self, fnames):\nUSER res = \"\"\nUSER for fname in fnames:\nUSER if not fname:\nUSER continue\nUSER errors = self.linter.lint(self.abs_root_path(fname))\nUSER \nUSER if errors:\nUSER res += \"\\n\"\nUSER res += errors\nUSER res += \"\\n\"\nUSER \nUSER if res:\nUSER self.io.tool_warning(res)\nUSER \nUSER return res\nUSER \nUSER def add_assistant_reply_to_cur_messages(self):\nUSER if self.partial_response_content:\nUSER self.cur_messages += [dict(role=\"assistant\", content=self.partial_response_content)]\nUSER if self.partial_response_function_call:\nUSER self.cur_messages += [\nUSER dict(\nUSER role=\"assistant\",\nUSER content=None,\nUSER function_call=self.partial_response_function_call,\nUSER )\nUSER ]\nUSER \nUSER def get_file_mentions(self, content):\nUSER words = set(word for word in content.split())\nUSER \nUSER # drop sentence punctuation from the end\nUSER words = set(word.rstrip(\",.!;:?\") for word in words)\nUSER \nUSER # strip away all kinds of quotes\nUSER quotes = \"\".join(['\"', \"'\", \"`\"])\nUSER words = set(word.strip(quotes) for word in words)\nUSER \nUSER addable_rel_fnames = self.get_addable_relative_files()\nUSER \nUSER # Get basenames of files already in chat or read-only\nUSER existing_basenames = {os.path.basename(f) for f in self.get_inchat_relative_files()} | {\nUSER os.path.basename(self.get_rel_fname(f)) for f in self.abs_read_only_fnames\nUSER }\nUSER \nUSER mentioned_rel_fnames = set()\nUSER fname_to_rel_fnames = {}\nUSER for rel_fname in addable_rel_fnames:\nUSER # Skip files that share a basename with files already in chat\nUSER if os.path.basename(rel_fname) in existing_basenames:\nUSER continue\nUSER \nUSER normalized_rel_fname = rel_fname.replace(\"\\\\\", \"/\")\nUSER normalized_words = set(word.replace(\"\\\\\", \"/\") for word in words)\nUSER if normalized_rel_fname in normalized_words:\nUSER mentioned_rel_fnames.add(rel_fname)\nUSER \nUSER fname = os.path.basename(rel_fname)\nUSER \nUSER # Don't add basenames that could be plain words like \"run\" or \"make\"\nUSER if \"/\" in fname or \"\\\\\" in fname or \".\" in fname or \"_\" in fname or \"-\" in fname:\nUSER if fname not in fname_to_rel_fnames:\nUSER fname_to_rel_fnames[fname] = []\nUSER fname_to_rel_fnames[fname].append(rel_fname)\nUSER \nUSER for fname, rel_fnames in fname_to_rel_fnames.items():\nUSER if len(rel_fnames) == 1 and fname in words:\nUSER mentioned_rel_fnames.add(rel_fnames[0])\nUSER \nUSER return mentioned_rel_fnames\nUSER \nUSER def check_for_file_mentions(self, content):\nUSER mentioned_rel_fnames = self.get_file_mentions(content)\nUSER \nUSER new_mentions = mentioned_rel_fnames - self.ignore_mentions\nUSER \nUSER if not new_mentions:\nUSER return\nUSER \nUSER added_fnames = []\nUSER group = ConfirmGroup(new_mentions)\nUSER for rel_fname in sorted(new_mentions):\nUSER if self.io.confirm_ask(f\"Add {rel_fname} to the chat?\", group=group, allow_never=True):\nUSER self.add_rel_fname(rel_fname)\nUSER added_fnames.append(rel_fname)\nUSER else:\nUSER self.ignore_mentions.add(rel_fname)\nUSER \nUSER if added_fnames:\nUSER return prompts.added_files.format(fnames=\", \".join(added_fnames))\nUSER \nUSER def send(self, messages, model=None, functions=None):\nUSER if not model:\nUSER model = self.main_model\nUSER \nUSER self.partial_response_content = \"\"\nUSER self.partial_response_function_call = dict()\nUSER \nUSER self.io.log_llm_history(\"TO LLM\", format_messages(messages))\nUSER \nUSER if self.main_model.use_temperature:\nUSER temp = self.temperature\nUSER else:\nUSER temp = None\nUSER \nUSER completion = None\nUSER try:\nUSER hash_object, completion = send_completion(\nUSER model.name,\nUSER messages,\nUSER functions,\nUSER self.stream,\nUSER temp,\nUSER extra_params=model.extra_params,\nUSER )\nUSER self.chat_completion_call_hashes.append(hash_object.hexdigest())\nUSER \nUSER if self.stream:\nUSER yield from self.show_send_output_stream(completion)\nUSER else:\nUSER self.show_send_output(completion)\nUSER \nUSER # Calculate costs for successful responses\nUSER self.calculate_and_show_tokens_and_cost(messages, completion)\nUSER \nUSER except LiteLLMExceptions().exceptions_tuple() as err:\nUSER ex_info = LiteLLMExceptions().get_ex_info(err)\nUSER if ex_info.name == \"ContextWindowExceededError\":\nUSER # Still calculate costs for context window errors\nUSER self.calculate_and_show_tokens_and_cost(messages, completion)\nUSER raise\nUSER except KeyboardInterrupt as kbi:\nUSER self.keyboard_interrupt()\nUSER raise kbi\nUSER finally:\nUSER self.io.log_llm_history(\nUSER \"LLM RESPONSE\",\nUSER format_content(\"ASSISTANT\", self.partial_response_content),\nUSER )\nUSER \nUSER if self.partial_response_content:\nUSER self.io.ai_output(self.partial_response_content)\nUSER elif self.partial_response_function_call:\nUSER # TODO: push this into subclasses\nUSER args = self.parse_partial_args()\nUSER if args:\nUSER self.io.ai_output(json.dumps(args, indent=4))\nUSER \nUSER def show_send_output(self, completion):\nUSER if self.verbose:\nUSER print(completion)\nUSER \nUSER if not completion.choices:\nUSER self.io.tool_error(str(completion))\nUSER return\nUSER \nUSER show_func_err = None\nUSER show_content_err = None\nUSER try:\nUSER if completion.choices[0].message.tool_calls:\nUSER self.partial_response_function_call = (\nUSER completion.choices[0].message.tool_calls[0].function\nUSER )\nUSER except AttributeError as func_err:\nUSER show_func_err = func_err\nUSER \nUSER try:\nUSER self.partial_response_content = completion.choices[0].message.content or \"\"\nUSER except AttributeError as content_err:\nUSER show_content_err = content_err\nUSER \nUSER resp_hash = dict(\nUSER function_call=str(self.partial_response_function_call),\nUSER content=self.partial_response_content,\nUSER )\nUSER resp_hash = hashlib.sha1(json.dumps(resp_hash, sort_keys=True).encode())\nUSER self.chat_completion_response_hashes.append(resp_hash.hexdigest())\nUSER \nUSER if show_func_err and show_content_err:\nUSER self.io.tool_error(show_func_err)\nUSER self.io.tool_error(show_content_err)\nUSER raise Exception(\"No data found in LLM response!\")\nUSER \nUSER show_resp = self.render_incremental_response(True)\nUSER self.io.assistant_output(show_resp, pretty=self.show_pretty())\nUSER \nUSER if (\nUSER hasattr(completion.choices[0], \"finish_reason\")\nUSER and completion.choices[0].finish_reason == \"length\"\nUSER ):\nUSER raise FinishReasonLength()\nUSER \nUSER def show_send_output_stream(self, completion):\nUSER for chunk in completion:\nUSER if len(chunk.choices) == 0:\nUSER continue\nUSER \nUSER if (\nUSER hasattr(chunk.choices[0], \"finish_reason\")\nUSER and chunk.choices[0].finish_reason == \"length\"\nUSER ):\nUSER raise FinishReasonLength()\nUSER \nUSER try:\nUSER func = chunk.choices[0].delta.function_call\nUSER # dump(func)\nUSER for k, v in func.items():\nUSER if k in self.partial_response_function_call:\nUSER self.partial_response_function_call[k] += v\nUSER else:\nUSER self.partial_response_function_call[k] = v\nUSER except AttributeError:\nUSER pass\nUSER \nUSER try:\nUSER text = chunk.choices[0].delta.content\nUSER if text:\nUSER self.partial_response_content += text\nUSER except AttributeError:\nUSER text = None\nUSER \nUSER if self.show_pretty():\nUSER self.live_incremental_response(False)\nUSER elif text:\nUSER try:\nUSER sys.stdout.write(text)\nUSER except UnicodeEncodeError:\nUSER # Safely encode and decode the text\nUSER safe_text = text.encode(sys.stdout.encoding, errors=\"backslashreplace\").decode(\nUSER sys.stdout.encoding\nUSER )\nUSER sys.stdout.write(safe_text)\nUSER sys.stdout.flush()\nUSER yield text\nUSER \nUSER def live_incremental_response(self, final):\nUSER show_resp = self.render_incremental_response(final)\nUSER self.mdstream.update(show_resp, final=final)\nUSER \nUSER def render_incremental_response(self, final):\nUSER return self.get_multi_response_content()\nUSER \nUSER def calculate_and_show_tokens_and_cost(self, messages, completion=None):\nUSER prompt_tokens = 0\nUSER completion_tokens = 0\nUSER cache_hit_tokens = 0\nUSER cache_write_tokens = 0\nUSER \nUSER if completion and hasattr(completion, \"usage\") and completion.usage is not None:\nUSER prompt_tokens = completion.usage.prompt_tokens\nUSER completion_tokens = completion.usage.completion_tokens\nUSER cache_hit_tokens = getattr(completion.usage, \"prompt_cache_hit_tokens\", 0) or getattr(\nUSER completion.usage, \"cache_read_input_tokens\", 0\nUSER )\nUSER cache_write_tokens = getattr(completion.usage, \"cache_creation_input_tokens\", 0)\nUSER \nUSER if hasattr(completion.usage, \"cache_read_input_tokens\") or hasattr(\nUSER completion.usage, \"cache_creation_input_tokens\"\nUSER ):\nUSER self.message_tokens_sent += prompt_tokens\nUSER self.message_tokens_sent += cache_write_tokens\nUSER else:\nUSER self.message_tokens_sent += prompt_tokens\nUSER \nUSER else:\nUSER prompt_tokens = self.main_model.token_count(messages)\nUSER completion_tokens = self.main_model.token_count(self.partial_response_content)\nUSER self.message_tokens_sent += prompt_tokens\nUSER \nUSER self.message_tokens_received += completion_tokens\nUSER \nUSER tokens_report = f\"Tokens: {format_tokens(self.message_tokens_sent)} sent\"\nUSER \nUSER if cache_write_tokens:\nUSER tokens_report += f\", {format_tokens(cache_write_tokens)} cache write\"\nUSER if cache_hit_tokens:\nUSER tokens_report += f\", {format_tokens(cache_hit_tokens)} cache hit\"\nUSER tokens_report += f\", {format_tokens(self.message_tokens_received)} received.\"\nUSER \nUSER if not self.main_model.info.get(\"input_cost_per_token\"):\nUSER self.usage_report = tokens_report\nUSER return\nUSER \nUSER cost = 0\nUSER \nUSER input_cost_per_token = self.main_model.info.get(\"input_cost_per_token\") or 0\nUSER output_cost_per_token = self.main_model.info.get(\"output_cost_per_token\") or 0\nUSER input_cost_per_token_cache_hit = (\nUSER self.main_model.info.get(\"input_cost_per_token_cache_hit\") or 0\nUSER )\nUSER \nUSER # deepseek\nUSER # prompt_cache_hit_tokens + prompt_cache_miss_tokens\nUSER # == prompt_tokens == total tokens that were sent\nUSER #\nUSER # Anthropic\nUSER # cache_creation_input_tokens + cache_read_input_tokens + prompt\nUSER # == total tokens that were\nUSER \nUSER if input_cost_per_token_cache_hit:\nUSER # must be deepseek\nUSER cost += input_cost_per_token_cache_hit * cache_hit_tokens\nUSER cost += (prompt_tokens - input_cost_per_token_cache_hit) * input_cost_per_token\nUSER else:\nUSER # hard code the anthropic adjustments, no-ops for other models since cache_x_tokens==0\nUSER cost += cache_write_tokens * input_cost_per_token * 1.25\nUSER cost += cache_hit_tokens * input_cost_per_token * 0.10\nUSER cost += prompt_tokens * input_cost_per_token\nUSER \nUSER cost += completion_tokens * output_cost_per_token\nUSER \nUSER self.total_cost += cost\nUSER self.message_cost += cost\nUSER \nUSER def format_cost(value):\nUSER if value == 0:\nUSER return \"0.00\"\nUSER magnitude = abs(value)\nUSER if magnitude >= 0.01:\nUSER return f\"{value:.2f}\"\nUSER else:\nUSER return f\"{value:.{max(2, 2 - int(math.log10(magnitude)))}f}\"\nUSER \nUSER cost_report = (\nUSER f\"Cost: ${format_cost(self.message_cost)} message,\"\nUSER f\" ${format_cost(self.total_cost)} session.\"\nUSER )\nUSER \nUSER if self.add_cache_headers and self.stream:\nUSER warning = \" Use --no-stream for accurate caching costs.\"\nUSER self.usage_report = tokens_report + \"\\n\" + cost_report + warning\nUSER return\nUSER \nUSER if cache_hit_tokens and cache_write_tokens:\nUSER sep = \"\\n\"\nUSER else:\nUSER sep = \" \"\nUSER \nUSER self.usage_report = tokens_report + sep + cost_report\nUSER \nUSER def show_usage_report(self):\nUSER if not self.usage_report:\nUSER return\nUSER \nUSER self.io.tool_output(self.usage_report)\nUSER \nUSER prompt_tokens = self.message_tokens_sent\nUSER completion_tokens = self.message_tokens_received\nUSER self.event(\nUSER \"message_send\",\nUSER main_model=self.main_model,\nUSER edit_format=self.edit_format,\nUSER prompt_tokens=prompt_tokens,\nUSER completion_tokens=completion_tokens,\nUSER total_tokens=prompt_tokens + completion_tokens,\nUSER cost=self.message_cost,\nUSER total_cost=self.total_cost,\nUSER )\nUSER \nUSER self.message_cost = 0.0\nUSER self.message_tokens_sent = 0\nUSER self.message_tokens_received = 0\nUSER \nUSER def get_multi_response_content(self, final=False):\nUSER cur = self.multi_response_content or \"\"\nUSER new = self.partial_response_content or \"\"\nUSER \nUSER if new.rstrip() != new and not final:\nUSER new = new.rstrip()\nUSER return cur + new\nUSER \nUSER def get_rel_fname(self, fname):\nUSER try:\nUSER return os.path.relpath(fname, self.root)\nUSER except ValueError:\nUSER return fname\nUSER \nUSER def get_inchat_relative_files(self):\nUSER files = [self.get_rel_fname(fname) for fname in self.abs_fnames]\nUSER return sorted(set(files))\nUSER \nUSER def is_file_safe(self, fname):\nUSER try:\nUSER return Path(self.abs_root_path(fname)).is_file()\nUSER except OSError:\nUSER return\nUSER \nUSER def get_all_relative_files(self):\nUSER if self.repo:\nUSER files = self.repo.get_tracked_files()\nUSER else:\nUSER files = self.get_inchat_relative_files()\nUSER \nUSER # This is quite slow in large repos\nUSER # files = [fname for fname in files if self.is_file_safe(fname)]\nUSER \nUSER return sorted(set(files))\nUSER \nUSER def get_all_abs_files(self):\nUSER files = self.get_all_relative_files()\nUSER files = [self.abs_root_path(path) for path in files]\nUSER return files\nUSER \nUSER def get_addable_relative_files(self):\nUSER all_files = set(self.get_all_relative_files())\nUSER inchat_files = set(self.get_inchat_relative_files())\nUSER read_only_files = set(self.get_rel_fname(fname) for fname in self.abs_read_only_fnames)\nUSER return all_files - inchat_files - read_only_files\nUSER \nUSER def check_for_dirty_commit(self, path):\nUSER if not self.repo:\nUSER return\nUSER if not self.dirty_commits:\nUSER return\nUSER if not self.repo.is_dirty(path):\nUSER return\nUSER \nUSER # We need a committed copy of the file in order to /undo, so skip this\nUSER # fullp = Path(self.abs_root_path(path))\nUSER # if not fullp.stat().st_size:\nUSER # return\nUSER \nUSER self.io.tool_output(f\"Committing {path} before applying edits.\")\nUSER self.need_commit_before_edits.add(path)\nUSER \nUSER def allowed_to_edit(self, path):\nUSER full_path = self.abs_root_path(path)\nUSER if self.repo:\nUSER need_to_add = not self.repo.path_in_repo(path)\nUSER else:\nUSER need_to_add = False\nUSER \nUSER if full_path in self.abs_fnames:\nUSER self.check_for_dirty_commit(path)\nUSER return True\nUSER \nUSER if self.repo and self.repo.git_ignored_file(path):\nUSER self.io.tool_warning(f\"Skipping edits to {path} that matches gitignore spec.\")\nUSER return\nUSER \nUSER if not Path(full_path).exists():\nUSER if not self.io.confirm_ask(\"Create new file?\", subject=path):\nUSER self.io.tool_output(f\"Skipping edits to {path}\")\nUSER return\nUSER \nUSER if not self.dry_run:\nUSER if not utils.touch_file(full_path):\nUSER self.io.tool_error(f\"Unable to create {path}, skipping edits.\")\nUSER return\nUSER \nUSER # Seems unlikely that we needed to create the file, but it was\nUSER # actually already part of the repo.\nUSER # But let's only add if we need to, just to be safe.\nUSER if need_to_add:\nUSER self.repo.repo.git.add(full_path)\nUSER \nUSER self.abs_fnames.add(full_path)\nUSER self.check_added_files()\nUSER return True\nUSER \nUSER if not self.io.confirm_ask(\nUSER \"Allow edits to file that has not been added to the chat?\",\nUSER subject=path,\nUSER ):\nUSER self.io.tool_output(f\"Skipping edits to {path}\")\nUSER return\nUSER \nUSER if need_to_add:\nUSER self.repo.repo.git.add(full_path)\nUSER \nUSER self.abs_fnames.add(full_path)\nUSER self.check_added_files()\nUSER self.check_for_dirty_commit(path)\nUSER \nUSER return True\nUSER \nUSER warning_given = False\nUSER \nUSER def check_added_files(self):\nUSER if self.warning_given:\nUSER return\nUSER \nUSER warn_number_of_files = 4\nUSER warn_number_of_tokens = 20 * 1024\nUSER \nUSER num_files = len(self.abs_fnames)\nUSER if num_files < warn_number_of_files:\nUSER return\nUSER \nUSER tokens = 0\nUSER for fname in self.abs_fnames:\nUSER if is_image_file(fname):\nUSER continue\nUSER content = self.io.read_text(fname)\nUSER tokens += self.main_model.token_count(content)\nUSER \nUSER if tokens < warn_number_of_tokens:\nUSER return\nUSER \nUSER self.io.tool_warning(\"Warning: it's best to only add files that need changes to the chat.\")\nUSER self.io.tool_warning(urls.edit_errors)\nUSER self.warning_given = True\nUSER \nUSER def prepare_to_edit(self, edits):\nUSER res = []\nUSER seen = dict()\nUSER \nUSER self.need_commit_before_edits = set()\nUSER \nUSER for edit in edits:\nUSER path = edit[0]\nUSER if path is None:\nUSER res.append(edit)\nUSER continue\nUSER if path == \"python\":\nUSER dump(edits)\nUSER if path in seen:\nUSER allowed = seen[path]\nUSER else:\nUSER allowed = self.allowed_to_edit(path)\nUSER seen[path] = allowed\nUSER \nUSER if allowed:\nUSER res.append(edit)\nUSER \nUSER self.dirty_commit()\nUSER self.need_commit_before_edits = set()\nUSER \nUSER return res\nUSER \nUSER def apply_updates(self):\nUSER edited = set()\nUSER try:\nUSER edits = self.get_edits()\nUSER edits = self.apply_edits_dry_run(edits)\nUSER edits = self.prepare_to_edit(edits)\nUSER edited = set(edit[0] for edit in edits)\nUSER \nUSER self.apply_edits(edits)\nUSER except ValueError as err:\nUSER self.num_malformed_responses += 1\nUSER \nUSER err = err.args[0]\nUSER \nUSER self.io.tool_error(\"The LLM did not conform to the edit format.\")\nUSER self.io.tool_output(urls.edit_errors)\nUSER self.io.tool_output()\nUSER self.io.tool_output(str(err))\nUSER \nUSER self.reflected_message = str(err)\nUSER return edited\nUSER \nUSER except ANY_GIT_ERROR as err:\nUSER self.io.tool_error(str(err))\nUSER return edited\nUSER except Exception as err:\nUSER self.io.tool_error(\"Exception while updating files:\")\nUSER self.io.tool_error(str(err), strip=False)\nUSER \nUSER traceback.print_exc()\nUSER \nUSER self.reflected_message = str(err)\nUSER return edited\nUSER \nUSER for path in edited:\nUSER if self.dry_run:\nUSER self.io.tool_output(f\"Did not apply edit to {path} (--dry-run)\")\nUSER else:\nUSER self.io.tool_output(f\"Applied edit to {path}\")\nUSER \nUSER return edited\nUSER \nUSER def parse_partial_args(self):\nUSER # dump(self.partial_response_function_call)\nUSER \nUSER data = self.partial_response_function_call.get(\"arguments\")\nUSER if not data:\nUSER return\nUSER \nUSER try:\nUSER return json.loads(data)\nUSER except JSONDecodeError:\nUSER pass\nUSER \nUSER try:\nUSER return json.loads(data + \"]}\")\nUSER except JSONDecodeError:\nUSER pass\nUSER \nUSER try:\nUSER return json.loads(data + \"}]}\")\nUSER except JSONDecodeError:\nUSER pass\nUSER \nUSER try:\nUSER return json.loads(data + '\"}]}')\nUSER except JSONDecodeError:\nUSER pass\nUSER \nUSER # commits...\nUSER \nUSER def get_context_from_history(self, history):\nUSER context = \"\"\nUSER if history:\nUSER for msg in history:\nUSER context += \"\\n\" + msg[\"role\"].upper() + \": \" + msg[\"content\"] + \"\\n\"\nUSER \nUSER return context\nUSER \nUSER def auto_commit(self, edited, context=None):\nUSER if not self.repo or not self.auto_commits or self.dry_run:\nUSER return\nUSER \nUSER if not context:\nUSER context = self.get_context_from_history(self.cur_messages)\nUSER \nUSER try:\nUSER res = self.repo.commit(fnames=edited, context=context, aider_edits=True)\nUSER if res:\nUSER self.show_auto_commit_outcome(res)\nUSER commit_hash, commit_message = res\nUSER return self.gpt_prompts.files_content_gpt_edits.format(\nUSER hash=commit_hash,\nUSER message=commit_message,\nUSER )\nUSER \nUSER return self.gpt_prompts.files_content_gpt_no_edits\nUSER except ANY_GIT_ERROR as err:\nUSER self.io.tool_error(f\"Unable to commit: {str(err)}\")\nUSER return\nUSER \nUSER def show_auto_commit_outcome(self, res):\nUSER commit_hash, commit_message = res\nUSER self.last_aider_commit_hash = commit_hash\nUSER self.aider_commit_hashes.add(commit_hash)\nUSER self.last_aider_commit_message = commit_message\nUSER if self.show_diffs:\nUSER self.commands.cmd_diff()\nUSER \nUSER def show_undo_hint(self):\nUSER if not self.commit_before_message:\nUSER return\nUSER if self.commit_before_message[-1] != self.repo.get_head_commit_sha():\nUSER self.io.tool_output(\"You can use /undo to undo and discard each aider commit.\")\nUSER \nUSER def dirty_commit(self):\nUSER if not self.need_commit_before_edits:\nUSER return\nUSER if not self.dirty_commits:\nUSER return\nUSER if not self.repo:\nUSER return\nUSER \nUSER self.repo.commit(fnames=self.need_commit_before_edits)\nUSER \nUSER # files changed, move cur messages back behind the files messages\nUSER # self.move_back_cur_messages(self.gpt_prompts.files_content_local_edits)\nUSER return True\nUSER \nUSER def get_edits(self, mode=\"update\"):\nUSER return []\nUSER \nUSER def apply_edits(self, edits):\nUSER return\nUSER \nUSER def apply_edits_dry_run(self, edits):\nUSER return edits\nUSER \nUSER def run_shell_commands(self):\nUSER if not self.suggest_shell_commands:\nUSER return \"\"\nUSER \nUSER done = set()\nUSER group = ConfirmGroup(set(self.shell_commands))\nUSER accumulated_output = \"\"\nUSER for command in self.shell_commands:\nUSER if command in done:\nUSER continue\nUSER done.add(command)\nUSER output = self.handle_shell_commands(command, group)\nUSER if output:\nUSER accumulated_output += output + \"\\n\\n\"\nUSER return accumulated_output\nUSER \nUSER def handle_shell_commands(self, commands_str, group):\nUSER commands = commands_str.strip().splitlines()\nUSER command_count = sum(\nUSER 1 for cmd in commands if cmd.strip() and not cmd.strip().startswith(\"#\")\nUSER )\nUSER prompt = \"Run shell command?\" if command_count == 1 else \"Run shell commands?\"\nUSER if not self.io.confirm_ask(\nUSER prompt,\nUSER subject=\"\\n\".join(commands),\nUSER explicit_yes_required=True,\nUSER group=group,\nUSER allow_never=True,\nUSER ):\nUSER return\nUSER \nUSER accumulated_output = \"\"\nUSER for command in commands:\nUSER command = command.strip()\nUSER if not command or command.startswith(\"#\"):\nUSER continue\nUSER \nUSER self.io.tool_output()\nUSER self.io.tool_output(f\"Running {command}\")\nUSER # Add the command to input history\nUSER self.io.add_to_input_history(f\"/run {command.strip()}\")\nUSER exit_status, output = run_cmd(command, error_print=self.io.tool_error, cwd=self.root)\nUSER if output:\nUSER accumulated_output += f\"Output from {command}\\n{output}\\n\"\nUSER \nUSER if accumulated_output.strip() and self.io.confirm_ask(\nUSER \"Add command output to the chat?\", allow_never=True\nUSER ):\nUSER num_lines = len(accumulated_output.strip().splitlines())\nUSER line_plural = \"line\" if num_lines == 1 else \"lines\"\nUSER self.io.tool_output(f\"Added {num_lines} {line_plural} of output to the chat.\")\nUSER return accumulated_output\nUSER ```\n-------\nASSISTANT Ok, I will use that as the true, current contents of the files.\n-------\nUSER i'd like to check the tokens that will be sent to the llm before sending a message. is there a logical place to do this?\n-------\nUSER ^C KeyboardInterrupt\n-------\nASSISTANT I see that you interrupted my previous reply.\n-------\nUSER i'd like to check the tokens that will be sent to the llm before sending a message. is there a logical place to do this?"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945714}
+{"event": "command_reset", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945766}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945826}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945826}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945826}
+{"event": "command_model", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945835}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945839}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945839}
+{"event": "message_send_exception", "properties": {"exception": "Messages don't properly alternate user/assistant:\n\n-------\nSYSTEM type: text\nSYSTEM text: Act as an expert code analyst.\nAnswer questions about the supplied code.\nAlways reply to the user in the same language they are using.\n\nDescribe code changes however you like. Don't use SEARCH/REPLACE blocks!\nSYSTEM cache_control: {'type': 'ephemeral'}\n-------\nUSER I am working with you on code in a git repository.\nUSER Here are summaries of some files present in my git repo.\nUSER If you need to see the full contents of any files to answer my questions, ask me to *add them to the chat*.\nUSER \nUSER aider/analytics.py:\nUSER \u22ee...\nUSER \u2502def compute_hex_threshold(percent):\nUSER \u22ee...\nUSER \u2502def is_uuid_in_percentage(uuid_str, percent):\nUSER \u22ee...\nUSER \u2502class Analytics:\nUSER \u2502 # providers\nUSER \u2502 mp = None\nUSER \u22ee...\nUSER \u2502 def disable(self, permanently):\nUSER \u22ee...\nUSER \u2502 def get_data_file_path(self):\nUSER \u22ee...\nUSER \u2502 def get_or_create_uuid(self):\nUSER \u22ee...\nUSER \u2502 def load_data(self):\nUSER \u22ee...\nUSER \u2502 def save_data(self):\nUSER \u22ee...\nUSER \u2502 def get_system_info(self):\nUSER \u22ee...\nUSER \u2502 def event(self, event_name, main_model=None, **kwargs):\nUSER \u22ee...\nUSER \nUSER aider/args.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/coders/base_prompts.py:\nUSER \u2502class CoderPrompts:\nUSER \u22ee...\nUSER \nUSER aider/coders/chat_chunks.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ChatChunks:\nUSER \u2502 system: List = field(default_factory=list)\nUSER \u22ee...\nUSER \u2502 def all_messages(self):\nUSER \u22ee...\nUSER \u2502 def add_cache_control(self, messages):\nUSER \u22ee...\nUSER \nUSER aider/coders/editblock_coder.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/coders/help_prompts.py:\nUSER \u22ee...\nUSER \u2502class HelpPrompts(CoderPrompts):\nUSER \u22ee...\nUSER \nUSER aider/coders/search_replace.py:\nUSER \u22ee...\nUSER \u2502def read_text(fname):\nUSER \u22ee...\nUSER \u2502def main(dnames):\nUSER \u22ee...\nUSER \nUSER aider/coders/wholefile_coder.py:\nUSER \u22ee...\nUSER \u2502class WholeFileCoder(Coder):\nUSER \u2502 \"\"\"A coder that operates on entire files for code modifications.\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def render_incremental_response(self, final):\nUSER \u22ee...\nUSER \nUSER aider/commands.py:\nUSER \u22ee...\nUSER \u2502class Commands:\nUSER \u2502 voice = None\nUSER \u22ee...\nUSER \u2502 def get_raw_completions(self, cmd):\nUSER \u22ee...\nUSER \u2502 def get_completions(self, cmd):\nUSER \u22ee...\nUSER \u2502 def get_commands(self):\nUSER \u22ee...\nUSER \u2502 def matching_commands(self, inp):\nUSER \u22ee...\nUSER \u2502 def run(self, inp):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/copypaste.py:\nUSER \u22ee...\nUSER \u2502class ClipboardWatcher:\nUSER \u2502 \"\"\"Watches clipboard for changes and updates IO placeholder\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def start(self):\nUSER \u22ee...\nUSER \u2502 def stop(self):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/diffs.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/dump.py:\nUSER \u22ee...\nUSER \u2502def cvt(s):\nUSER \u22ee...\nUSER \u2502def dump(*vals):\nUSER \u22ee...\nUSER \nUSER aider/exceptions.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ExInfo:\nUSER \u22ee...\nUSER \u2502class LiteLLMExceptions:\nUSER \u2502 exceptions = dict()\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def exceptions_tuple(self):\nUSER \u22ee...\nUSER \u2502 def get_ex_info(self, ex):\nUSER \u22ee...\nUSER \nUSER aider/gui.py:\nUSER \u22ee...\nUSER \u2502class CaptureIO(InputOutput):\nUSER \u2502 lines = []\nUSER \u2502\nUSER \u2502 def tool_output(self, msg, log_only=False):\nUSER \u22ee...\nUSER \u2502 def tool_error(self, msg):\nUSER \u22ee...\nUSER \u2502 def tool_warning(self, msg):\nUSER \u22ee...\nUSER \u2502 def get_captured_lines(self):\nUSER \u22ee...\nUSER \u2502class State:\nUSER \u2502 keys = set()\nUSER \u2502\nUSER \u2502 def init(self, key, val=None):\nUSER \u22ee...\nUSER \u2502class GUI:\nUSER \u2502 prompt = None\nUSER \u22ee...\nUSER \u2502 def show_edit_info(self, edit):\nUSER \u22ee...\nUSER \u2502 def add_undo(self, commit_hash):\nUSER \u22ee...\nUSER \u2502 def button(self, args, **kwargs):\nUSER \u22ee...\nUSER \u2502 def prompt_pending(self):\nUSER \u22ee...\nUSER \u2502 def info(self, message, echo=True):\nUSER \u22ee...\nUSER \nUSER aider/history.py:\nUSER \u22ee...\nUSER \u2502class ChatSummary:\nUSER \u2502 def __init__(self, models=None, max_tokens=1024):\nUSER \u2502 if not models:\nUSER \u2502 raise ValueError(\"At least one model must be provided\")\nUSER \u2502 self.models = models if isinstance(models, list) else [models]\nUSER \u2502 self.max_tokens = max_tokens\nUSER \u22ee...\nUSER \u2502 def tokenize(self, messages):\nUSER \u22ee...\nUSER \u2502 def summarize_all(self, messages):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/io.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ConfirmGroup:\nUSER \u22ee...\nUSER \u2502class AutoCompleter(Completer):\nUSER \u2502 def __init__(\nUSER \u2502 self, root, rel_fnames, addable_rel_fnames, commands, encoding, abs_read_only_fnames=None\nUSER \u22ee...\nUSER \u2502 def tokenize(self):\nUSER \u22ee...\nUSER \u2502 def get_command_completions(self, document, complete_event, text, words):\nUSER \u22ee...\nUSER \u2502 def get_completions(self, document, complete_event):\nUSER \u22ee...\nUSER \u2502class InputOutput:\nUSER \u2502 num_error_outputs = 0\nUSER \u22ee...\nUSER \u2502 def read_image(self, filename):\nUSER \u22ee...\nUSER \u2502 def read_text(self, filename, silent=False):\nUSER \u22ee...\nUSER \u2502 def write_text(self, filename, content, max_retries=5, initial_delay=0.1):\nUSER \u22ee...\nUSER \u2502 def rule(self):\nUSER \u22ee...\nUSER \u2502 def get_input(\nUSER \u2502 self,\nUSER \u2502 root,\nUSER \u2502 rel_fnames,\nUSER \u2502 addable_rel_fnames,\nUSER \u2502 commands,\nUSER \u2502 abs_read_only_fnames=None,\nUSER \u2502 edit_format=None,\nUSER \u2502 ):\nUSER \u2502 self.rule()\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def suspend_to_bg(event):\nUSER \u22ee...\nUSER \u2502 def add_to_input_history(self, inp):\nUSER \u22ee...\nUSER \u2502 def log_llm_history(self, role, content):\nUSER \u22ee...\nUSER \u2502 def display_user_input(self, inp):\nUSER \u22ee...\nUSER \u2502 def user_input(self, inp, log_only=True):\nUSER \u22ee...\nUSER \u2502 def ai_output(self, content):\nUSER \u22ee...\nUSER \u2502 def offer_url(self, url, prompt=\"Open URL for more info?\", allow_never=True):\nUSER \u22ee...\nUSER \u2502 def confirm_ask(\nUSER \u2502 self,\nUSER \u2502 question,\nUSER \u2502 default=\"y\",\nUSER \u2502 subject=None,\nUSER \u2502 explicit_yes_required=False,\nUSER \u2502 group=None,\nUSER \u2502 allow_never=False,\nUSER \u22ee...\nUSER \u2502 def tool_error(self, message=\"\", strip=True):\nUSER \u22ee...\nUSER \u2502 def tool_warning(self, message=\"\", strip=True):\nUSER \u22ee...\nUSER \u2502 def tool_output(self, *messages, log_only=False, bold=False):\nUSER \u22ee...\nUSER \u2502 def print(self, message=\"\"):\nUSER \u22ee...\nUSER \u2502 def append_chat_history(self, text, linebreak=False, blockquote=False, strip=True):\nUSER \u22ee...\nUSER \u2502 def format_files_for_input(self, rel_fnames, rel_read_only_fnames):\nUSER \u22ee...\nUSER \u2502def get_rel_fname(fname, root):\nUSER \u22ee...\nUSER \nUSER aider/linter.py:\nUSER \u22ee...\nUSER \u2502class Linter:\nUSER \u2502 def __init__(self, encoding=\"utf-8\", root=None):\nUSER \u2502 self.encoding = encoding\nUSER \u2502 self.root = root\nUSER \u2502\nUSER \u2502 self.languages = dict(\nUSER \u2502 python=self.py_lint,\nUSER \u2502 )\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \u2502 def run_cmd(self, cmd, rel_fname, code):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/main.py:\nUSER \u22ee...\nUSER \u2502def main(argv=None, input=None, output=None, force_git_root=None, return_coder=False):\nUSER \u22ee...\nUSER \nUSER aider/mdstream.py:\nUSER \u22ee...\nUSER \u2502class MarkdownStream:\nUSER \u2502 \"\"\"Streaming markdown renderer that progressively displays content with a live updating window.\nUSER \u2502\nUSER \u2502 Uses rich.console and rich.live to render markdown content with smooth scrolling\nUSER \u2502 and partial updates. Maintains a sliding window of visible content while streaming\nUSER \u2502 in new markdown text.\nUSER \u22ee...\nUSER \u2502 def update(self, text, final=False):\nUSER \u22ee...\nUSER \nUSER aider/models.py:\nUSER \u22ee...\nUSER \u2502@dataclass\nUSER \u2502class ModelSettings:\nUSER \u22ee...\nUSER \u2502class ModelInfoManager:\nUSER \u2502 MODEL_INFO_URL = (\nUSER \u2502 \"https://raw.githubusercontent.com/BerriAI/litellm/main/\"\nUSER \u2502 \"model_prices_and_context_window.json\"\nUSER \u22ee...\nUSER \u2502 def get_model_from_cached_json_db(self, model):\nUSER \u22ee...\nUSER \u2502class Model(ModelSettings):\nUSER \u2502 def __init__(self, model, weak_model=None, editor_model=None, editor_edit_format=None):\nUSER \u2502 # Map any alias to its canonical name\nUSER \u2502 model = MODEL_ALIASES.get(model, model)\nUSER \u2502\nUSER \u2502 self.name = model\nUSER \u2502\nUSER \u2502 self.max_chat_history_tokens = 1024\nUSER \u2502 self.weak_model = None\nUSER \u2502 self.editor_model = None\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def token_count(self, messages):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/repo.py:\nUSER \u22ee...\nUSER \u2502class GitRepo:\nUSER \u2502 repo = None\nUSER \u22ee...\nUSER \u2502 def commit(self, fnames=None, context=None, message=None, aider_edits=False):\nUSER \u22ee...\nUSER \u2502 def get_tracked_files(self):\nUSER \u22ee...\nUSER \u2502 def normalize_path(self, path):\nUSER \u22ee...\nUSER \u2502 def git_ignored_file(self, path):\nUSER \u22ee...\nUSER \u2502 def ignored_file(self, fname):\nUSER \u22ee...\nUSER \u2502 def path_in_repo(self, path):\nUSER \u22ee...\nUSER \u2502 def abs_root_path(self, path):\nUSER \u22ee...\nUSER \u2502 def is_dirty(self, path=None):\nUSER \u22ee...\nUSER \u2502 def get_head_commit_sha(self, short=False):\nUSER \u22ee...\nUSER \nUSER aider/repomap.py:\nUSER \u22ee...\nUSER \u2502class RepoMap:\nUSER \u2502 CACHE_VERSION = 3\nUSER \u22ee...\nUSER \u2502 def token_count(self, text):\nUSER \u22ee...\nUSER \u2502 def get_repo_map(\nUSER \u2502 self,\nUSER \u2502 chat_files,\nUSER \u2502 other_files,\nUSER \u2502 mentioned_fnames=None,\nUSER \u2502 mentioned_idents=None,\nUSER \u2502 force_refresh=False,\nUSER \u22ee...\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \nUSER aider/report.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/run_cmd.py:\nUSER \u22ee...\nUSER \u2502def run_cmd(command, verbose=False, error_print=None, cwd=None):\nUSER \u22ee...\nUSER \nUSER aider/scrape.py:\nUSER \u22ee...\nUSER \u2502class Scraper:\nUSER \u2502 pandoc_available = None\nUSER \u22ee...\nUSER \u2502 def scrape(self, url):\nUSER \u22ee...\nUSER \u2502def main(url):\nUSER \u22ee...\nUSER \nUSER aider/utils.py:\nUSER \u22ee...\nUSER \u2502def is_image_file(file_name):\nUSER \u22ee...\nUSER \u2502def safe_abs_path(res):\nUSER \u22ee...\nUSER \u2502def format_messages(messages, title=None):\nUSER \u22ee...\nUSER \u2502def format_tokens(count):\nUSER \u22ee...\nUSER \u2502def touch_file(fname):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER aider/watch.py:\nUSER \u22ee...\nUSER \u2502class FileWatcher:\nUSER \u2502 \"\"\"Watches source files for changes and AI comments\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def start(self):\nUSER \u22ee...\nUSER \u2502 def stop(self):\nUSER \u22ee...\nUSER \u2502 def process_changes(self):\nUSER \u22ee...\nUSER \u2502 def get_ai_comments(self, filepath):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER benchmark/benchmark.py:\nUSER \u22ee...\nUSER \u2502@app.command()\nUSER \u2502def main(\nUSER \u2502 dirnames: Optional[List[str]] = typer.Argument(None, help=\"Directory names\"),\nUSER \u2502 graphs: bool = typer.Option(False, \"--graphs\", help=\"Generate graphs\"),\nUSER \u2502 model: str = typer.Option(\"gpt-3.5-turbo\", \"--model\", \"-m\", help=\"Model name\"),\nUSER \u2502 sleep: float = typer.Option(\nUSER \u2502 0, \"--sleep\", help=\"Sleep seconds between tests when single threaded\"\nUSER \u2502 ),\nUSER \u2502 languages: str = typer.Option(\nUSER \u2502 None, \"--languages\", \"-l\", help=\"Only run tests for specific languages (comma separated)\"\nUSER \u2502 ),\nUSER \u22ee...\nUSER \nUSER benchmark/over_time.py:\nUSER \u22ee...\nUSER \u2502class BenchmarkPlotter:\nUSER \u2502 LABEL_FONT_SIZE = 16\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def load_data(self, yaml_file: str) -> List[ModelData]:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER benchmark/refactor_tools.py:\nUSER \u22ee...\nUSER \u2502def main(paths):\nUSER \u22ee...\nUSER \nUSER benchmark/rungrid.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \u2502def run(dirname, model, edit_format):\nUSER \u22ee...\nUSER \nUSER scripts/blame.py:\nUSER \u22ee...\nUSER \u2502def run(cmd):\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/issues.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/update-history.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/versionbump.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER scripts/yank-old-versions.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\nUSER \nUSER tests/basic/test_watch.py:\nUSER \u22ee...\nUSER \u2502def test_ai_comment_pattern():\nUSER \u2502 # Create minimal IO and Coder instances for testing\nUSER \u2502 class MinimalCoder:\nUSER \u2502 def __init__(self, io):\nUSER \u2502 self.io = io\nUSER \u2502 self.root = \".\"\nUSER \u2502 self.abs_fnames = set()\nUSER \u2502\nUSER \u2502 def get_rel_fname(self, fname):\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/c/test.c:\nUSER \u22ee...\nUSER \u2502int main() {\nUSER \u2502 printf(\"Hello, World!\\n\");\nUSER \u2502 return 0;\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/cpp/test.cpp:\nUSER \u22ee...\nUSER \u2502int main() {\nUSER \u2502 std::cout << \"Hello, World!\" << std::endl;\nUSER \u2502 return 0;\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/csharp/test.cs:\nUSER \u22ee...\nUSER \u2502namespace Greetings {\nUSER \u2502 public interface IGreeter {\nUSER \u2502 string Greet(string name);\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public class Person {\nUSER \u2502 public string Name { get; set; }\nUSER \u2502 public int Age { get; set; }\nUSER \u2502\nUSER \u2502 public Person(string name, int age) {\nUSER \u2502 Name = name;\nUSER \u2502 Age = age;\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502 public class FormalGreeter : IGreeter {\nUSER \u2502 private const string PREFIX = \"Good day\";\nUSER \u2502 private static readonly int MAX_AGE = 150;\nUSER \u2502\nUSER \u2502 public string Greet(string name) {\nUSER \u2502 return $\"{PREFIX}, {name}!\";\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public string GreetPerson(Person person) {\nUSER \u2502 return $\"{PREFIX}, {person.Name} ({person.Age})!\";\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elisp/test.el:\nUSER \u22ee...\nUSER \u2502(defun main ()\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elixir/test.ex:\nUSER \u2502defmodule Greeter do\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/elm/test.elm:\nUSER \u22ee...\nUSER \u2502type Greeting\nUSER \u22ee...\nUSER \u2502greet style person =\nUSER \u22ee...\nUSER \u2502main =\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/go/test.go:\nUSER \u22ee...\nUSER \u2502type Person struct {\nUSER \u2502 Name string\nUSER \u2502 Age int\nUSER \u22ee...\nUSER \u2502type Greeter interface {\nUSER \u2502 Greet(p Person) string\nUSER \u22ee...\nUSER \u2502type FormalGreeter struct {\nUSER \u2502 Prefix string\nUSER \u22ee...\nUSER \u2502}\nUSER \u2502\nUSER \u2502func main() {\nUSER \u2502 greeter := NewFormalGreeter()\nUSER \u2502 person := Person{Name: DefaultName, Age: 42}\nUSER \u2502 fmt.Println(greeter.Greet(person))\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/java/test.java:\nUSER \u2502public interface Greeting {\nUSER \u2502 String greet(String name);\nUSER \u22ee...\nUSER \u2502public class Test implements Greeting {\nUSER \u2502 private String prefix = \"Hello\";\nUSER \u2502\nUSER \u2502 public String greet(String name) {\nUSER \u2502 return prefix + \", \" + name + \"!\";\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 public static void main(String[] args) {\nUSER \u2502 Test greeter = new Test();\nUSER \u2502 System.out.println(greeter.greet(\"World\"));\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/javascript/test.js:\nUSER \u22ee...\nUSER \u2502class Person {\nUSER \u2502 constructor(name) {\nUSER \u2502 this.name = name;\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 sayHello() {\nUSER \u2502 return `Hello, ${this.name}!`;\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502function greet(person) {\nUSER \u2502 return person.sayHello();\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/kotlin/test.kt:\nUSER \u2502interface Greeting {\nUSER \u2502 fun greet(name: String): String\nUSER \u22ee...\nUSER \u2502class Test : Greeting {\nUSER \u2502 private val prefix = \"Hello\"\nUSER \u2502\nUSER \u2502 override fun greet(name: String): String {\nUSER \u2502 return \"$prefix, $name!\"\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502fun main(args: Array) {\nUSER \u2502 val greeter = Test()\nUSER \u2502 println(greeter.greet(\"World\"))\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ocaml/test.ml:\nUSER \u22ee...\nUSER \u2502module Greeter = struct\nUSER \u2502 type person = {\nUSER \u2502 name: string;\nUSER \u2502 age: int\nUSER \u2502 }\nUSER \u2502\nUSER \u2502 let create_person name age =\nUSER \u2502 {name; age}\nUSER \u2502\nUSER \u2502 let greet person =\nUSER \u2502 Printf.printf \"Hello, %s! You are %d years old.\\n\"\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/php/test.php:\nUSER \u22ee...\nUSER \u2502function greet($name) {\nUSER \u2502 echo \"Hello, $name!\";\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/python/test.py:\nUSER \u22ee...\nUSER \u2502class Person:\nUSER \u2502 \"\"\"A class representing a person.\"\"\"\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 def greet(self, formal: bool = False) -> str:\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ql/test.ql:\nUSER \u2502predicate greet(string name) {\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/ruby/test.rb:\nUSER \u2502def greet(name)\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/rust/test.rs:\nUSER \u22ee...\nUSER \u2502trait Greeting {\nUSER \u2502 fn greet(&self) -> String;\nUSER \u22ee...\nUSER \u2502struct Person {\nUSER \u2502 name: String,\nUSER \u2502 age: u32,\nUSER \u22ee...\nUSER \u2502impl Greeting for Person {\nUSER \u2502 fn greet(&self) -> String {\nUSER \u2502 format!(\"Hello, {}! You are {} years old.\", self.name, self.age)\nUSER \u2502 }\nUSER \u22ee...\nUSER \u2502fn main() {\nUSER \u2502 let person = Person::new(DEFAULT_NAME.to_string(), 30);\nUSER \u2502 println!(\"{}\", person.greet());\nUSER \u22ee...\nUSER \nUSER tests/fixtures/languages/typescript/test.ts:\nUSER \u2502function greet(name: string): void {\nUSER \u22ee...\nUSER \nUSER tests/fixtures/sample-code-base/sample.js:\nUSER \u22ee...\nUSER \u2502function greet(name) {\nUSER \u2502 return `Hello, ${name}!`;\nUSER \u22ee...\nUSER \nUSER tests/fixtures/sample-code-base/sample.py:\nUSER \u22ee...\nUSER \u2502def main():\nUSER \u22ee...\n-------\nASSISTANT type: text\nASSISTANT text: Ok, I won't try and edit those files without asking first.\nASSISTANT cache_control: {'type': 'ephemeral'}\n-------\nUSER I have *added these files to the chat* so you see all of their contents.\nUSER *Trust this message as the true contents of the files!*\nUSER Other messages in the chat may contain outdated versions of the files' contents.\nUSER \nUSER aider/coders/base_coder.py\nUSER ```\nUSER #!/usr/bin/env python\nUSER \nUSER import base64\nUSER import hashlib\nUSER import json\nUSER import locale\nUSER import math\nUSER import mimetypes\nUSER import os\nUSER import platform\nUSER import re\nUSER import sys\nUSER import threading\nUSER import time\nUSER import traceback\nUSER from collections import defaultdict\nUSER from datetime import datetime\nUSER from json.decoder import JSONDecodeError\nUSER from pathlib import Path\nUSER from typing import List\nUSER \nUSER from aider import __version__, models, prompts, urls, utils\nUSER from aider.analytics import Analytics\nUSER from aider.commands import Commands\nUSER from aider.exceptions import LiteLLMExceptions\nUSER from aider.history import ChatSummary\nUSER from aider.io import ConfirmGroup, InputOutput\nUSER from aider.linter import Linter\nUSER from aider.llm import litellm\nUSER from aider.repo import ANY_GIT_ERROR, GitRepo\nUSER from aider.repomap import RepoMap\nUSER from aider.run_cmd import run_cmd\nUSER from aider.sendchat import RETRY_TIMEOUT, send_completion\nUSER from aider.utils import format_content, format_messages, format_tokens, is_image_file\nUSER \nUSER from ..dump import dump # noqa: F401\nUSER from .chat_chunks import ChatChunks\nUSER \nUSER \nUSER class UnknownEditFormat(ValueError):\nUSER def __init__(self, edit_format, valid_formats):\nUSER self.edit_format = edit_format\nUSER self.valid_formats = valid_formats\nUSER super().__init__(\nUSER f\"Unknown edit format {edit_format}. Valid formats are: {', '.join(valid_formats)}\"\nUSER )\nUSER \nUSER \nUSER class MissingAPIKeyError(ValueError):\nUSER pass\nUSER \nUSER \nUSER class FinishReasonLength(Exception):\nUSER pass\nUSER \nUSER \nUSER def wrap_fence(name):\nUSER return f\"<{name}>\", f\"{name}>\"\nUSER \nUSER \nUSER all_fences = [\nUSER (\"`\" * 3, \"`\" * 3),\nUSER (\"`\" * 4, \"`\" * 4),\nUSER wrap_fence(\"source\"),\nUSER wrap_fence(\"code\"),\nUSER wrap_fence(\"pre\"),\nUSER wrap_fence(\"codeblock\"),\nUSER wrap_fence(\"sourcecode\"),\nUSER ]\nUSER \nUSER \nUSER class Coder:\nUSER abs_fnames = None\nUSER abs_read_only_fnames = None\nUSER repo = None\nUSER last_aider_commit_hash = None\nUSER aider_edited_files = None\nUSER last_asked_for_commit_time = 0\nUSER repo_map = None\nUSER functions = None\nUSER num_exhausted_context_windows = 0\nUSER num_malformed_responses = 0\nUSER last_keyboard_interrupt = None\nUSER num_reflections = 0\nUSER max_reflections = 3\nUSER edit_format = None\nUSER yield_stream = False\nUSER temperature = 0\nUSER auto_lint = True\nUSER auto_test = False\nUSER test_cmd = None\nUSER lint_outcome = None\nUSER test_outcome = None\nUSER multi_response_content = \"\"\nUSER partial_response_content = \"\"\nUSER commit_before_message = []\nUSER message_cost = 0.0\nUSER message_tokens_sent = 0\nUSER message_tokens_received = 0\nUSER add_cache_headers = False\nUSER cache_warming_thread = None\nUSER num_cache_warming_pings = 0\nUSER suggest_shell_commands = True\nUSER detect_urls = True\nUSER ignore_mentions = None\nUSER chat_language = None\nUSER file_watcher = None\nUSER \nUSER @classmethod\nUSER def create(\nUSER self,\nUSER main_model=None,\nUSER edit_format=None,\nUSER io=None,\nUSER from_coder=None,\nUSER summarize_from_coder=True,\nUSER **kwargs,\nUSER ):\nUSER import aider.coders as coders\nUSER \nUSER if not main_model:\nUSER if from_coder:\nUSER main_model = from_coder.main_model\nUSER else:\nUSER main_model = models.Model(models.DEFAULT_MODEL_NAME)\nUSER \nUSER if edit_format == \"code\":\nUSER edit_format = None\nUSER if edit_format is None:\nUSER if from_coder:\nUSER edit_format = from_coder.edit_format\nUSER else:\nUSER edit_format = main_model.edit_format\nUSER \nUSER if not io and from_coder:\nUSER io = from_coder.io\nUSER \nUSER if from_coder:\nUSER use_kwargs = dict(from_coder.original_kwargs) # copy orig kwargs\nUSER \nUSER # If the edit format changes, we can't leave old ASSISTANT\nUSER # messages in the chat history. The old edit format will\nUSER # confused the new LLM. It may try and imitate it, disobeying\nUSER # the system prompt.\nUSER done_messages = from_coder.done_messages\nUSER if edit_format != from_coder.edit_format and done_messages and summarize_from_coder:\nUSER done_messages = from_coder.summarizer.summarize_all(done_messages)\nUSER \nUSER # Bring along context from the old Coder\nUSER update = dict(\nUSER fnames=list(from_coder.abs_fnames),\nUSER read_only_fnames=list(from_coder.abs_read_only_fnames), # Copy read-only files\nUSER done_messages=done_messages,\nUSER cur_messages=from_coder.cur_messages,\nUSER aider_commit_hashes=from_coder.aider_commit_hashes,\nUSER commands=from_coder.commands.clone(),\nUSER total_cost=from_coder.total_cost,\nUSER ignore_mentions=from_coder.ignore_mentions,\nUSER file_watcher=from_coder.file_watcher,\nUSER )\nUSER use_kwargs.update(update) # override to complete the switch\nUSER use_kwargs.update(kwargs) # override passed kwargs\nUSER \nUSER kwargs = use_kwargs\nUSER \nUSER for coder in coders.__all__:\nUSER if hasattr(coder, \"edit_format\") and coder.edit_format == edit_format:\nUSER res = coder(main_model, io, **kwargs)\nUSER res.original_kwargs = dict(kwargs)\nUSER return res\nUSER \nUSER valid_formats = [\nUSER str(c.edit_format)\nUSER for c in coders.__all__\nUSER if hasattr(c, \"edit_format\") and c.edit_format is not None\nUSER ]\nUSER raise UnknownEditFormat(edit_format, valid_formats)\nUSER \nUSER def clone(self, **kwargs):\nUSER new_coder = Coder.create(from_coder=self, **kwargs)\nUSER return new_coder\nUSER \nUSER def get_announcements(self):\nUSER lines = []\nUSER lines.append(f\"Aider v{__version__}\")\nUSER \nUSER # Model\nUSER main_model = self.main_model\nUSER weak_model = main_model.weak_model\nUSER \nUSER if weak_model is not main_model:\nUSER prefix = \"Main model\"\nUSER else:\nUSER prefix = \"Model\"\nUSER \nUSER output = f\"{prefix}: {main_model.name} with {self.edit_format} edit format\"\nUSER if self.add_cache_headers or main_model.caches_by_default:\nUSER output += \", prompt cache\"\nUSER if main_model.info.get(\"supports_assistant_prefill\"):\nUSER output += \", infinite output\"\nUSER lines.append(output)\nUSER \nUSER if self.edit_format == \"architect\":\nUSER output = (\nUSER f\"Editor model: {main_model.editor_model.name} with\"\nUSER f\" {main_model.editor_edit_format} edit format\"\nUSER )\nUSER lines.append(output)\nUSER \nUSER if weak_model is not main_model:\nUSER output = f\"Weak model: {weak_model.name}\"\nUSER lines.append(output)\nUSER \nUSER # Repo\nUSER if self.repo:\nUSER rel_repo_dir = self.repo.get_rel_repo_dir()\nUSER num_files = len(self.repo.get_tracked_files())\nUSER \nUSER lines.append(f\"Git repo: {rel_repo_dir} with {num_files:,} files\")\nUSER if num_files > 1000:\nUSER lines.append(\nUSER \"Warning: For large repos, consider using --subtree-only and .aiderignore\"\nUSER )\nUSER lines.append(f\"See: {urls.large_repos}\")\nUSER else:\nUSER lines.append(\"Git repo: none\")\nUSER \nUSER # Repo-map\nUSER if self.repo_map:\nUSER map_tokens = self.repo_map.max_map_tokens\nUSER if map_tokens > 0:\nUSER refresh = self.repo_map.refresh\nUSER lines.append(f\"Repo-map: using {map_tokens} tokens, {refresh} refresh\")\nUSER max_map_tokens = self.main_model.get_repo_map_tokens() * 2\nUSER if map_tokens > max_map_tokens:\nUSER lines.append(\nUSER f\"Warning: map-tokens > {max_map_tokens} is not recommended. Too much\"\nUSER \" irrelevant code can confuse LLMs.\"\nUSER )\nUSER else:\nUSER lines.append(\"Repo-map: disabled because map_tokens == 0\")\nUSER else:\nUSER lines.append(\"Repo-map: disabled\")\nUSER \nUSER # Files\nUSER for fname in self.get_inchat_relative_files():\nUSER lines.append(f\"Added {fname} to the chat.\")\nUSER \nUSER for fname in self.abs_read_only_fnames:\nUSER rel_fname = self.get_rel_fname(fname)\nUSER lines.append(f\"Added {rel_fname} to the chat (read-only).\")\nUSER \nUSER if self.done_messages:\nUSER lines.append(\"Restored previous conversation history.\")\nUSER \nUSER if self.io.multiline_mode:\nUSER lines.append(\"Multiline mode: Enabled. Enter inserts newline, Alt-Enter submits text\")\nUSER \nUSER return lines\nUSER \nUSER def __init__(\nUSER self,\nUSER main_model,\nUSER io,\nUSER repo=None,\nUSER fnames=None,\nUSER read_only_fnames=None,\nUSER show_diffs=False,\nUSER auto_commits=True,\nUSER dirty_commits=True,\nUSER dry_run=False,\nUSER map_tokens=1024,\nUSER verbose=False,\nUSER stream=True,\nUSER use_git=True,\nUSER cur_messages=None,\nUSER done_messages=None,\nUSER restore_chat_history=False,\nUSER auto_lint=True,\nUSER auto_test=False,\nUSER lint_cmds=None,\nUSER test_cmd=None,\nUSER aider_commit_hashes=None,\nUSER map_mul_no_files=8,\nUSER commands=None,\nUSER summarizer=None,\nUSER total_cost=0.0,\nUSER analytics=None,\nUSER map_refresh=\"auto\",\nUSER cache_prompts=False,\nUSER num_cache_warming_pings=0,\nUSER suggest_shell_commands=True,\nUSER chat_language=None,\nUSER detect_urls=True,\nUSER ignore_mentions=None,\nUSER file_watcher=None,\nUSER auto_copy_context=False,\nUSER ):\nUSER # Fill in a dummy Analytics if needed, but it is never .enable()'d\nUSER self.analytics = analytics if analytics is not None else Analytics()\nUSER \nUSER self.event = self.analytics.event\nUSER self.chat_language = chat_language\nUSER self.commit_before_message = []\nUSER self.aider_commit_hashes = set()\nUSER self.rejected_urls = set()\nUSER self.abs_root_path_cache = {}\nUSER \nUSER self.auto_copy_context = auto_copy_context\nUSER \nUSER self.ignore_mentions = ignore_mentions\nUSER if not self.ignore_mentions:\nUSER self.ignore_mentions = set()\nUSER \nUSER self.file_watcher = file_watcher\nUSER if self.file_watcher:\nUSER self.file_watcher.coder = self\nUSER \nUSER self.suggest_shell_commands = suggest_shell_commands\nUSER self.detect_urls = detect_urls\nUSER \nUSER self.num_cache_warming_pings = num_cache_warming_pings\nUSER \nUSER if not fnames:\nUSER fnames = []\nUSER \nUSER if io is None:\nUSER io = InputOutput()\nUSER \nUSER if aider_commit_hashes:\nUSER self.aider_commit_hashes = aider_commit_hashes\nUSER else:\nUSER self.aider_commit_hashes = set()\nUSER \nUSER self.chat_completion_call_hashes = []\nUSER self.chat_completion_response_hashes = []\nUSER self.need_commit_before_edits = set()\nUSER \nUSER self.total_cost = total_cost\nUSER \nUSER self.verbose = verbose\nUSER self.abs_fnames = set()\nUSER self.abs_read_only_fnames = set()\nUSER \nUSER if cur_messages:\nUSER self.cur_messages = cur_messages\nUSER else:\nUSER self.cur_messages = []\nUSER \nUSER if done_messages:\nUSER self.done_messages = done_messages\nUSER else:\nUSER self.done_messages = []\nUSER \nUSER self.io = io\nUSER \nUSER self.shell_commands = []\nUSER \nUSER if not auto_commits:\nUSER dirty_commits = False\nUSER \nUSER self.auto_commits = auto_commits\nUSER self.dirty_commits = dirty_commits\nUSER \nUSER self.dry_run = dry_run\nUSER self.pretty = self.io.pretty\nUSER \nUSER self.main_model = main_model\nUSER \nUSER self.stream = stream and main_model.streaming\nUSER \nUSER if cache_prompts and self.main_model.cache_control:\nUSER self.add_cache_headers = True\nUSER \nUSER self.show_diffs = show_diffs\nUSER \nUSER self.commands = commands or Commands(self.io, self)\nUSER self.commands.coder = self\nUSER \nUSER self.repo = repo\nUSER if use_git and self.repo is None:\nUSER try:\nUSER self.repo = GitRepo(\nUSER self.io,\nUSER fnames,\nUSER None,\nUSER models=main_model.commit_message_models(),\nUSER )\nUSER except FileNotFoundError:\nUSER pass\nUSER \nUSER if self.repo:\nUSER self.root = self.repo.root\nUSER \nUSER for fname in fnames:\nUSER fname = Path(fname)\nUSER if self.repo and self.repo.git_ignored_file(fname):\nUSER self.io.tool_warning(f\"Skipping {fname} that matches gitignore spec.\")\nUSER \nUSER if self.repo and self.repo.ignored_file(fname):\nUSER self.io.tool_warning(f\"Skipping {fname} that matches aiderignore spec.\")\nUSER continue\nUSER \nUSER if not fname.exists():\nUSER if utils.touch_file(fname):\nUSER self.io.tool_output(f\"Creating empty file {fname}\")\nUSER else:\nUSER self.io.tool_warning(f\"Can not create {fname}, skipping.\")\nUSER continue\nUSER \nUSER if not fname.is_file():\nUSER self.io.tool_warning(f\"Skipping {fname} that is not a normal file.\")\nUSER continue\nUSER \nUSER fname = str(fname.resolve())\nUSER \nUSER self.abs_fnames.add(fname)\nUSER self.check_added_files()\nUSER \nUSER if not self.repo:\nUSER self.root = utils.find_common_root(self.abs_fnames)\nUSER \nUSER if read_only_fnames:\nUSER self.abs_read_only_fnames = set()\nUSER for fname in read_only_fnames:\nUSER abs_fname = self.abs_root_path(fname)\nUSER if os.path.exists(abs_fname):\nUSER self.abs_read_only_fnames.add(abs_fname)\nUSER else:\nUSER self.io.tool_warning(f\"Error: Read-only file {fname} does not exist. Skipping.\")\nUSER \nUSER if map_tokens is None:\nUSER use_repo_map = main_model.use_repo_map\nUSER map_tokens = 1024\nUSER else:\nUSER use_repo_map = map_tokens > 0\nUSER \nUSER max_inp_tokens = self.main_model.info.get(\"max_input_tokens\") or 0\nUSER \nUSER has_map_prompt = hasattr(self, \"gpt_prompts\") and self.gpt_prompts.repo_content_prefix\nUSER \nUSER if use_repo_map and self.repo and has_map_prompt:\nUSER self.repo_map = RepoMap(\nUSER map_tokens,\nUSER self.root,\nUSER self.main_model,\nUSER io,\nUSER self.gpt_prompts.repo_content_prefix,\nUSER self.verbose,\nUSER max_inp_tokens,\nUSER map_mul_no_files=map_mul_no_files,\nUSER refresh=map_refresh,\nUSER )\nUSER \nUSER self.summarizer = summarizer or ChatSummary(\nUSER [self.main_model.weak_model, self.main_model],\nUSER self.main_model.max_chat_history_tokens,\nUSER )\nUSER \nUSER self.summarizer_thread = None\nUSER self.summarized_done_messages = []\nUSER self.summarizing_messages = None\nUSER \nUSER if not self.done_messages and restore_chat_history:\nUSER history_md = self.io.read_text(self.io.chat_history_file)\nUSER if history_md:\nUSER self.done_messages = utils.split_chat_history_markdown(history_md)\nUSER self.summarize_start()\nUSER \nUSER # Linting and testing\nUSER self.linter = Linter(root=self.root, encoding=io.encoding)\nUSER self.auto_lint = auto_lint\nUSER self.setup_lint_cmds(lint_cmds)\nUSER self.lint_cmds = lint_cmds\nUSER self.auto_test = auto_test\nUSER self.test_cmd = test_cmd\nUSER \nUSER # validate the functions jsonschema\nUSER if self.functions:\nUSER from jsonschema import Draft7Validator\nUSER \nUSER for function in self.functions:\nUSER Draft7Validator.check_schema(function)\nUSER \nUSER if self.verbose:\nUSER self.io.tool_output(\"JSON Schema:\")\nUSER self.io.tool_output(json.dumps(self.functions, indent=4))\nUSER \nUSER def setup_lint_cmds(self, lint_cmds):\nUSER if not lint_cmds:\nUSER return\nUSER for lang, cmd in lint_cmds.items():\nUSER self.linter.set_linter(lang, cmd)\nUSER \nUSER def show_announcements(self):\nUSER bold = True\nUSER for line in self.get_announcements():\nUSER self.io.tool_output(line, bold=bold)\nUSER bold = False\nUSER \nUSER def add_rel_fname(self, rel_fname):\nUSER self.abs_fnames.add(self.abs_root_path(rel_fname))\nUSER self.check_added_files()\nUSER \nUSER def drop_rel_fname(self, fname):\nUSER abs_fname = self.abs_root_path(fname)\nUSER if abs_fname in self.abs_fnames:\nUSER self.abs_fnames.remove(abs_fname)\nUSER return True\nUSER \nUSER def abs_root_path(self, path):\nUSER key = path\nUSER if key in self.abs_root_path_cache:\nUSER return self.abs_root_path_cache[key]\nUSER \nUSER res = Path(self.root) / path\nUSER res = utils.safe_abs_path(res)\nUSER self.abs_root_path_cache[key] = res\nUSER return res\nUSER \nUSER fences = all_fences\nUSER fence = fences[0]\nUSER \nUSER def show_pretty(self):\nUSER if not self.pretty:\nUSER return False\nUSER \nUSER # only show pretty output if fences are the normal triple-backtick\nUSER if self.fence[0][0] != \"`\":\nUSER return False\nUSER \nUSER return True\nUSER \nUSER def get_abs_fnames_content(self):\nUSER for fname in list(self.abs_fnames):\nUSER content = self.io.read_text(fname)\nUSER \nUSER if content is None:\nUSER relative_fname = self.get_rel_fname(fname)\nUSER self.io.tool_warning(f\"Dropping {relative_fname} from the chat.\")\nUSER self.abs_fnames.remove(fname)\nUSER else:\nUSER yield fname, content\nUSER \nUSER def choose_fence(self):\nUSER all_content = \"\"\nUSER for _fname, content in self.get_abs_fnames_content():\nUSER all_content += content + \"\\n\"\nUSER for _fname in self.abs_read_only_fnames:\nUSER content = self.io.read_text(_fname)\nUSER if content is not None:\nUSER all_content += content + \"\\n\"\nUSER \nUSER lines = all_content.splitlines()\nUSER good = False\nUSER for fence_open, fence_close in self.fences:\nUSER if any(line.startswith(fence_open) or line.startswith(fence_close) for line in lines):\nUSER continue\nUSER good = True\nUSER break\nUSER \nUSER if good:\nUSER self.fence = (fence_open, fence_close)\nUSER else:\nUSER self.fence = self.fences[0]\nUSER self.io.tool_warning(\nUSER \"Unable to find a fencing strategy! Falling back to:\"\nUSER f\" {self.fence[0]}...{self.fence[1]}\"\nUSER )\nUSER \nUSER return\nUSER \nUSER def get_files_content(self, fnames=None):\nUSER if not fnames:\nUSER fnames = self.abs_fnames\nUSER \nUSER prompt = \"\"\nUSER for fname, content in self.get_abs_fnames_content():\nUSER if not is_image_file(fname):\nUSER relative_fname = self.get_rel_fname(fname)\nUSER prompt += \"\\n\"\nUSER prompt += relative_fname\nUSER prompt += f\"\\n{self.fence[0]}\\n\"\nUSER \nUSER prompt += content\nUSER \nUSER # lines = content.splitlines(keepends=True)\nUSER # lines = [f\"{i+1:03}:{line}\" for i, line in enumerate(lines)]\nUSER # prompt += \"\".join(lines)\nUSER \nUSER prompt += f\"{self.fence[1]}\\n\"\nUSER \nUSER return prompt\nUSER \nUSER def get_read_only_files_content(self):\nUSER prompt = \"\"\nUSER for fname in self.abs_read_only_fnames:\nUSER content = self.io.read_text(fname)\nUSER if content is not None and not is_image_file(fname):\nUSER relative_fname = self.get_rel_fname(fname)\nUSER prompt += \"\\n\"\nUSER prompt += relative_fname\nUSER prompt += f\"\\n{self.fence[0]}\\n\"\nUSER prompt += content\nUSER prompt += f\"{self.fence[1]}\\n\"\nUSER return prompt\nUSER \nUSER def get_cur_message_text(self):\nUSER text = \"\"\nUSER for msg in self.cur_messages:\nUSER text += msg[\"content\"] + \"\\n\"\nUSER return text\nUSER \nUSER def get_ident_mentions(self, text):\nUSER # Split the string on any character that is not alphanumeric\nUSER # \\W+ matches one or more non-word characters (equivalent to [^a-zA-Z0-9_]+)\nUSER words = set(re.split(r\"\\W+\", text))\nUSER return words\nUSER \nUSER def get_ident_filename_matches(self, idents):\nUSER all_fnames = defaultdict(set)\nUSER for fname in self.get_all_relative_files():\nUSER # Skip empty paths or just '.'\nUSER if not fname or fname == \".\":\nUSER continue\nUSER \nUSER try:\nUSER # Handle dotfiles properly\nUSER path = Path(fname)\nUSER base = path.stem.lower() # Use stem instead of with_suffix(\"\").name\nUSER if len(base) >= 5:\nUSER all_fnames[base].add(fname)\nUSER except ValueError:\nUSER # Skip paths that can't be processed\nUSER continue\nUSER \nUSER matches = set()\nUSER for ident in idents:\nUSER if len(ident) < 5:\nUSER continue\nUSER matches.update(all_fnames[ident.lower()])\nUSER \nUSER return matches\nUSER \nUSER def get_repo_map(self, force_refresh=False):\nUSER if not self.repo_map:\nUSER return\nUSER \nUSER cur_msg_text = self.get_cur_message_text()\nUSER mentioned_fnames = self.get_file_mentions(cur_msg_text)\nUSER mentioned_idents = self.get_ident_mentions(cur_msg_text)\nUSER \nUSER mentioned_fnames.update(self.get_ident_filename_matches(mentioned_idents))\nUSER \nUSER all_abs_files = set(self.get_all_abs_files())\nUSER repo_abs_read_only_fnames = set(self.abs_read_only_fnames) & all_abs_files\nUSER chat_files = set(self.abs_fnames) | repo_abs_read_only_fnames\nUSER other_files = all_abs_files - chat_files\nUSER \nUSER repo_content = self.repo_map.get_repo_map(\nUSER chat_files,\nUSER other_files,\nUSER mentioned_fnames=mentioned_fnames,\nUSER mentioned_idents=mentioned_idents,\nUSER force_refresh=force_refresh,\nUSER )\nUSER \nUSER # fall back to global repo map if files in chat are disjoint from rest of repo\nUSER if not repo_content:\nUSER repo_content = self.repo_map.get_repo_map(\nUSER set(),\nUSER all_abs_files,\nUSER mentioned_fnames=mentioned_fnames,\nUSER mentioned_idents=mentioned_idents,\nUSER )\nUSER \nUSER # fall back to completely unhinted repo\nUSER if not repo_content:\nUSER repo_content = self.repo_map.get_repo_map(\nUSER set(),\nUSER all_abs_files,\nUSER )\nUSER \nUSER return repo_content\nUSER \nUSER def get_repo_messages(self):\nUSER repo_messages = []\nUSER repo_content = self.get_repo_map()\nUSER if repo_content:\nUSER repo_messages += [\nUSER dict(role=\"user\", content=repo_content),\nUSER dict(\nUSER role=\"assistant\",\nUSER content=\"Ok, I won't try and edit those files without asking first.\",\nUSER ),\nUSER ]\nUSER return repo_messages\nUSER \nUSER def get_readonly_files_messages(self):\nUSER readonly_messages = []\nUSER \nUSER # Handle non-image files\nUSER read_only_content = self.get_read_only_files_content()\nUSER if read_only_content:\nUSER readonly_messages += [\nUSER dict(\nUSER role=\"user\", content=self.gpt_prompts.read_only_files_prefix + read_only_content\nUSER ),\nUSER dict(\nUSER role=\"assistant\",\nUSER content=\"Ok, I will use these files as references.\",\nUSER ),\nUSER ]\nUSER \nUSER # Handle image files\nUSER images_message = self.get_images_message(self.abs_read_only_fnames)\nUSER if images_message is not None:\nUSER readonly_messages += [\nUSER images_message,\nUSER dict(role=\"assistant\", content=\"Ok, I will use these images as references.\"),\nUSER ]\nUSER \nUSER return readonly_messages\nUSER \nUSER def get_chat_files_messages(self):\nUSER chat_files_messages = []\nUSER if self.abs_fnames:\nUSER files_content = self.gpt_prompts.files_content_prefix\nUSER files_content += self.get_files_content()\nUSER files_reply = self.gpt_prompts.files_content_assistant_reply\nUSER elif self.get_repo_map() and self.gpt_prompts.files_no_full_files_with_repo_map:\nUSER files_content = self.gpt_prompts.files_no_full_files_with_repo_map\nUSER files_reply = self.gpt_prompts.files_no_full_files_with_repo_map_reply\nUSER else:\nUSER files_content = self.gpt_prompts.files_no_full_files\nUSER files_reply = \"Ok.\"\nUSER \nUSER if files_content:\nUSER chat_files_messages += [\nUSER dict(role=\"user\", content=files_content),\nUSER dict(role=\"assistant\", content=files_reply),\nUSER ]\nUSER \nUSER images_message = self.get_images_message(self.abs_fnames)\nUSER if images_message is not None:\nUSER chat_files_messages += [\nUSER images_message,\nUSER dict(role=\"assistant\", content=\"Ok.\"),\nUSER ]\nUSER \nUSER return chat_files_messages\nUSER \nUSER def get_images_message(self, fnames):\nUSER supports_images = self.main_model.info.get(\"supports_vision\")\nUSER supports_pdfs = self.main_model.info.get(\"supports_pdf_input\") or self.main_model.info.get(\nUSER \"max_pdf_size_mb\"\nUSER )\nUSER \nUSER # https://github.com/BerriAI/litellm/pull/6928\nUSER supports_pdfs = supports_pdfs or \"claude-3-5-sonnet-20241022\" in self.main_model.name\nUSER \nUSER if not (supports_images or supports_pdfs):\nUSER return None\nUSER \nUSER image_messages = []\nUSER for fname in fnames:\nUSER if not is_image_file(fname):\nUSER continue\nUSER \nUSER mime_type, _ = mimetypes.guess_type(fname)\nUSER if not mime_type:\nUSER continue\nUSER \nUSER with open(fname, \"rb\") as image_file:\nUSER encoded_string = base64.b64encode(image_file.read()).decode(\"utf-8\")\nUSER image_url = f\"data:{mime_type};base64,{encoded_string}\"\nUSER rel_fname = self.get_rel_fname(fname)\nUSER \nUSER if mime_type.startswith(\"image/\") and supports_images:\nUSER image_messages += [\nUSER {\"type\": \"text\", \"text\": f\"Image file: {rel_fname}\"},\nUSER {\"type\": \"image_url\", \"image_url\": {\"url\": image_url, \"detail\": \"high\"}},\nUSER ]\nUSER elif mime_type == \"application/pdf\" and supports_pdfs:\nUSER image_messages += [\nUSER {\"type\": \"text\", \"text\": f\"PDF file: {rel_fname}\"},\nUSER {\"type\": \"image_url\", \"image_url\": image_url},\nUSER ]\nUSER \nUSER if not image_messages:\nUSER return None\nUSER \nUSER return {\"role\": \"user\", \"content\": image_messages}\nUSER \nUSER def run_stream(self, user_message):\nUSER self.io.user_input(user_message)\nUSER self.init_before_message()\nUSER yield from self.send_message(user_message)\nUSER \nUSER def init_before_message(self):\nUSER self.aider_edited_files = set()\nUSER self.reflected_message = None\nUSER self.num_reflections = 0\nUSER self.lint_outcome = None\nUSER self.test_outcome = None\nUSER self.shell_commands = []\nUSER self.message_cost = 0\nUSER \nUSER if self.repo:\nUSER self.commit_before_message.append(self.repo.get_head_commit_sha())\nUSER \nUSER def run(self, with_message=None, preproc=True):\nUSER try:\nUSER if with_message:\nUSER self.io.user_input(with_message)\nUSER self.run_one(with_message, preproc)\nUSER return self.partial_response_content\nUSER while True:\nUSER try:\nUSER if not self.io.placeholder:\nUSER self.copy_context()\nUSER user_message = self.get_input()\nUSER self.run_one(user_message, preproc)\nUSER self.show_undo_hint()\nUSER except KeyboardInterrupt:\nUSER self.keyboard_interrupt()\nUSER except EOFError:\nUSER return\nUSER \nUSER def copy_context(self):\nUSER if self.auto_copy_context:\nUSER self.commands.cmd_copy_context()\nUSER \nUSER def get_input(self):\nUSER inchat_files = self.get_inchat_relative_files()\nUSER read_only_files = [self.get_rel_fname(fname) for fname in self.abs_read_only_fnames]\nUSER all_files = sorted(set(inchat_files + read_only_files))\nUSER edit_format = \"\" if self.edit_format == self.main_model.edit_format else self.edit_format\nUSER return self.io.get_input(\nUSER self.root,\nUSER all_files,\nUSER self.get_addable_relative_files(),\nUSER self.commands,\nUSER self.abs_read_only_fnames,\nUSER edit_format=edit_format,\nUSER )\nUSER \nUSER def preproc_user_input(self, inp):\nUSER if not inp:\nUSER return\nUSER \nUSER if self.commands.is_command(inp):\nUSER return self.commands.run(inp)\nUSER \nUSER self.check_for_file_mentions(inp)\nUSER inp = self.check_for_urls(inp)\nUSER \nUSER return inp\nUSER \nUSER def run_one(self, user_message, preproc):\nUSER self.init_before_message()\nUSER \nUSER if preproc:\nUSER message = self.preproc_user_input(user_message)\nUSER else:\nUSER message = user_message\nUSER \nUSER while message:\nUSER self.reflected_message = None\nUSER list(self.send_message(message))\nUSER \nUSER if not self.reflected_message:\nUSER break\nUSER \nUSER if self.num_reflections >= self.max_reflections:\nUSER self.io.tool_warning(f\"Only {self.max_reflections} reflections allowed, stopping.\")\nUSER return\nUSER \nUSER self.num_reflections += 1\nUSER message = self.reflected_message\nUSER \nUSER def check_and_open_urls(self, exc, friendly_msg=None):\nUSER \"\"\"Check exception for URLs, offer to open in a browser, with user-friendly error msgs.\"\"\"\nUSER text = str(exc)\nUSER \nUSER if friendly_msg:\nUSER self.io.tool_warning(text)\nUSER self.io.tool_error(f\"{friendly_msg}\")\nUSER else:\nUSER self.io.tool_error(text)\nUSER \nUSER url_pattern = re.compile(r\"(https?://[^\\s/$.?#].[^\\s]*)\")\nUSER urls = list(set(url_pattern.findall(text))) # Use set to remove duplicates\nUSER for url in urls:\nUSER url = url.rstrip(\".',\\\"\")\nUSER self.io.offer_url(url)\nUSER return urls\nUSER \nUSER def check_for_urls(self, inp: str) -> List[str]:\nUSER \"\"\"Check input for URLs and offer to add them to the chat.\"\"\"\nUSER if not self.detect_urls:\nUSER return inp\nUSER \nUSER url_pattern = re.compile(r\"(https?://[^\\s/$.?#].[^\\s]*[^\\s,.])\")\nUSER urls = list(set(url_pattern.findall(inp))) # Use set to remove duplicates\nUSER group = ConfirmGroup(urls)\nUSER for url in urls:\nUSER if url not in self.rejected_urls:\nUSER url = url.rstrip(\".',\\\"\")\nUSER if self.io.confirm_ask(\nUSER \"Add URL to the chat?\", subject=url, group=group, allow_never=True\nUSER ):\nUSER inp += \"\\n\\n\"\nUSER inp += self.commands.cmd_web(url, return_content=True)\nUSER else:\nUSER self.rejected_urls.add(url)\nUSER \nUSER return inp\nUSER \nUSER def keyboard_interrupt(self):\nUSER now = time.time()\nUSER \nUSER thresh = 2 # seconds\nUSER if self.last_keyboard_interrupt and now - self.last_keyboard_interrupt < thresh:\nUSER self.io.tool_warning(\"\\n\\n^C KeyboardInterrupt\")\nUSER self.event(\"exit\", reason=\"Control-C\")\nUSER sys.exit()\nUSER \nUSER self.io.tool_warning(\"\\n\\n^C again to exit\")\nUSER \nUSER self.last_keyboard_interrupt = now\nUSER \nUSER def summarize_start(self):\nUSER if not self.summarizer.too_big(self.done_messages):\nUSER return\nUSER \nUSER self.summarize_end()\nUSER \nUSER if self.verbose:\nUSER self.io.tool_output(\"Starting to summarize chat history.\")\nUSER \nUSER self.summarizer_thread = threading.Thread(target=self.summarize_worker)\nUSER self.summarizer_thread.start()\nUSER \nUSER def summarize_worker(self):\nUSER self.summarizing_messages = list(self.done_messages)\nUSER try:\nUSER self.summarized_done_messages = self.summarizer.summarize(self.summarizing_messages)\nUSER except ValueError as err:\nUSER self.io.tool_warning(err.args[0])\nUSER \nUSER if self.verbose:\nUSER self.io.tool_output(\"Finished summarizing chat history.\")\nUSER \nUSER def summarize_end(self):\nUSER if self.summarizer_thread is None:\nUSER return\nUSER \nUSER self.summarizer_thread.join()\nUSER self.summarizer_thread = None\nUSER \nUSER if self.summarizing_messages == self.done_messages:\nUSER self.done_messages = self.summarized_done_messages\nUSER self.summarizing_messages = None\nUSER self.summarized_done_messages = []\nUSER \nUSER def move_back_cur_messages(self, message):\nUSER self.done_messages += self.cur_messages\nUSER self.summarize_start()\nUSER \nUSER # TODO check for impact on image messages\nUSER if message:\nUSER self.done_messages += [\nUSER dict(role=\"user\", content=message),\nUSER dict(role=\"assistant\", content=\"Ok.\"),\nUSER ]\nUSER self.cur_messages = []\nUSER \nUSER def get_user_language(self):\nUSER if self.chat_language:\nUSER return self.chat_language\nUSER \nUSER try:\nUSER lang = locale.getlocale()[0]\nUSER if lang:\nUSER return lang # Return the full language code, including country\nUSER except Exception:\nUSER pass\nUSER \nUSER for env_var in [\"LANG\", \"LANGUAGE\", \"LC_ALL\", \"LC_MESSAGES\"]:\nUSER lang = os.environ.get(env_var)\nUSER if lang:\nUSER return lang.split(\".\")[\nUSER 0\nUSER ] # Return language and country, but remove encoding if present\nUSER \nUSER return None\nUSER \nUSER def get_platform_info(self):\nUSER platform_text = f\"- Platform: {platform.platform()}\\n\"\nUSER shell_var = \"COMSPEC\" if os.name == \"nt\" else \"SHELL\"\nUSER shell_val = os.getenv(shell_var)\nUSER platform_text += f\"- Shell: {shell_var}={shell_val}\\n\"\nUSER \nUSER user_lang = self.get_user_language()\nUSER if user_lang:\nUSER platform_text += f\"- Language: {user_lang}\\n\"\nUSER \nUSER dt = datetime.now().astimezone().strftime(\"%Y-%m-%d\")\nUSER platform_text += f\"- Current date: {dt}\\n\"\nUSER \nUSER if self.repo:\nUSER platform_text += \"- The user is operating inside a git repository\\n\"\nUSER \nUSER if self.lint_cmds:\nUSER if self.auto_lint:\nUSER platform_text += (\nUSER \"- The user's pre-commit runs these lint commands, don't suggest running\"\nUSER \" them:\\n\"\nUSER )\nUSER else:\nUSER platform_text += \"- The user prefers these lint commands:\\n\"\nUSER for lang, cmd in self.lint_cmds.items():\nUSER if lang is None:\nUSER platform_text += f\" - {cmd}\\n\"\nUSER else:\nUSER platform_text += f\" - {lang}: {cmd}\\n\"\nUSER \nUSER if self.test_cmd:\nUSER if self.auto_test:\nUSER platform_text += (\nUSER \"- The user's pre-commit runs this test command, don't suggest running them: \"\nUSER )\nUSER else:\nUSER platform_text += \"- The user prefers this test command: \"\nUSER platform_text += self.test_cmd + \"\\n\"\nUSER \nUSER return platform_text\nUSER \nUSER def fmt_system_prompt(self, prompt):\nUSER lazy_prompt = self.gpt_prompts.lazy_prompt if self.main_model.lazy else \"\"\nUSER platform_text = self.get_platform_info()\nUSER \nUSER if self.suggest_shell_commands:\nUSER shell_cmd_prompt = self.gpt_prompts.shell_cmd_prompt.format(platform=platform_text)\nUSER shell_cmd_reminder = self.gpt_prompts.shell_cmd_reminder.format(platform=platform_text)\nUSER else:\nUSER shell_cmd_prompt = self.gpt_prompts.no_shell_cmd_prompt.format(platform=platform_text)\nUSER shell_cmd_reminder = self.gpt_prompts.no_shell_cmd_reminder.format(\nUSER platform=platform_text\nUSER )\nUSER \nUSER if self.chat_language:\nUSER language = self.chat_language\nUSER else:\nUSER language = \"the same language they are using\"\nUSER \nUSER prompt = prompt.format(\nUSER fence=self.fence,\nUSER lazy_prompt=lazy_prompt,\nUSER platform=platform_text,\nUSER shell_cmd_prompt=shell_cmd_prompt,\nUSER shell_cmd_reminder=shell_cmd_reminder,\nUSER language=language,\nUSER )\nUSER return prompt\nUSER \nUSER def format_chat_chunks(self):\nUSER self.choose_fence()\nUSER main_sys = self.fmt_system_prompt(self.gpt_prompts.main_system)\nUSER \nUSER example_messages = []\nUSER if self.main_model.examples_as_sys_msg:\nUSER if self.gpt_prompts.example_messages:\nUSER main_sys += \"\\n# Example conversations:\\n\\n\"\nUSER for msg in self.gpt_prompts.example_messages:\nUSER role = msg[\"role\"]\nUSER content = self.fmt_system_prompt(msg[\"content\"])\nUSER main_sys += f\"## {role.upper()}: {content}\\n\\n\"\nUSER main_sys = main_sys.strip()\nUSER else:\nUSER for msg in self.gpt_prompts.example_messages:\nUSER example_messages.append(\nUSER dict(\nUSER role=msg[\"role\"],\nUSER content=self.fmt_system_prompt(msg[\"content\"]),\nUSER )\nUSER )\nUSER if self.gpt_prompts.example_messages:\nUSER example_messages += [\nUSER dict(\nUSER role=\"user\",\nUSER content=(\nUSER \"I switched to a new code base. Please don't consider the above files\"\nUSER \" or try to edit them any longer.\"\nUSER ),\nUSER ),\nUSER dict(role=\"assistant\", content=\"Ok.\"),\nUSER ]\nUSER \nUSER if self.gpt_prompts.system_reminder:\nUSER main_sys += \"\\n\" + self.fmt_system_prompt(self.gpt_prompts.system_reminder)\nUSER \nUSER chunks = ChatChunks()\nUSER \nUSER if self.main_model.use_system_prompt:\nUSER chunks.system = [\nUSER dict(role=\"system\", content=main_sys),\nUSER ]\nUSER else:\nUSER chunks.system = [\nUSER dict(role=\"user\", content=main_sys),\nUSER dict(role=\"assistant\", content=\"Ok.\"),\nUSER ]\nUSER \nUSER chunks.examples = example_messages\nUSER \nUSER self.summarize_end()\nUSER chunks.done = self.done_messages\nUSER \nUSER chunks.repo = self.get_repo_messages()\nUSER chunks.readonly_files = self.get_readonly_files_messages()\nUSER chunks.chat_files = self.get_chat_files_messages()\nUSER \nUSER if self.gpt_prompts.system_reminder:\nUSER reminder_message = [\nUSER dict(\nUSER role=\"system\", content=self.fmt_system_prompt(self.gpt_prompts.system_reminder)\nUSER ),\nUSER ]\nUSER else:\nUSER reminder_message = []\nUSER \nUSER chunks.cur = list(self.cur_messages)\nUSER chunks.reminder = []\nUSER \nUSER # TODO review impact of token count on image messages\nUSER messages_tokens = self.main_model.token_count(chunks.all_messages())\nUSER reminder_tokens = self.main_model.token_count(reminder_message)\nUSER cur_tokens = self.main_model.token_count(chunks.cur)\nUSER \nUSER if None not in (messages_tokens, reminder_tokens, cur_tokens):\nUSER total_tokens = messages_tokens + reminder_tokens + cur_tokens\nUSER else:\nUSER # add the reminder anyway\nUSER total_tokens = 0\nUSER \nUSER if chunks.cur:\nUSER final = chunks.cur[-1]\nUSER else:\nUSER final = None\nUSER \nUSER max_input_tokens = self.main_model.info.get(\"max_input_tokens\") or 0\nUSER # Add the reminder prompt if we still have room to include it.\nUSER if (\nUSER not max_input_tokens\nUSER or total_tokens < max_input_tokens\nUSER and self.gpt_prompts.system_reminder\nUSER ):\nUSER if self.main_model.reminder == \"sys\":\nUSER chunks.reminder = reminder_message\nUSER elif self.main_model.reminder == \"user\" and final and final[\"role\"] == \"user\":\nUSER # stuff it into the user message\nUSER new_content = (\nUSER final[\"content\"]\nUSER + \"\\n\\n\"\nUSER + self.fmt_system_prompt(self.gpt_prompts.system_reminder)\nUSER )\nUSER chunks.cur[-1] = dict(role=final[\"role\"], content=new_content)\nUSER \nUSER return chunks\nUSER \nUSER def format_messages(self):\nUSER chunks = self.format_chat_chunks()\nUSER if self.add_cache_headers:\nUSER chunks.add_cache_control_headers()\nUSER \nUSER return chunks\nUSER \nUSER def warm_cache(self, chunks):\nUSER if not self.add_cache_headers:\nUSER return\nUSER if not self.num_cache_warming_pings:\nUSER return\nUSER \nUSER delay = 5 * 60 - 5\nUSER self.next_cache_warm = time.time() + delay\nUSER self.warming_pings_left = self.num_cache_warming_pings\nUSER self.cache_warming_chunks = chunks\nUSER \nUSER if self.cache_warming_thread:\nUSER return\nUSER \nUSER def warm_cache_worker():\nUSER while True:\nUSER time.sleep(1)\nUSER if self.warming_pings_left <= 0:\nUSER continue\nUSER now = time.time()\nUSER if now < self.next_cache_warm:\nUSER continue\nUSER \nUSER self.warming_pings_left -= 1\nUSER self.next_cache_warm = time.time() + delay\nUSER \nUSER kwargs = dict(self.main_model.extra_params) or dict()\nUSER kwargs[\"max_tokens\"] = 1\nUSER \nUSER try:\nUSER completion = litellm.completion(\nUSER model=self.main_model.name,\nUSER messages=self.cache_warming_chunks.cacheable_messages(),\nUSER stream=False,\nUSER **kwargs,\nUSER )\nUSER except Exception as err:\nUSER self.io.tool_warning(f\"Cache warming error: {str(err)}\")\nUSER continue\nUSER \nUSER cache_hit_tokens = getattr(\nUSER completion.usage, \"prompt_cache_hit_tokens\", 0\nUSER ) or getattr(completion.usage, \"cache_read_input_tokens\", 0)\nUSER \nUSER if self.verbose:\nUSER self.io.tool_output(f\"Warmed {format_tokens(cache_hit_tokens)} cached tokens.\")\nUSER \nUSER self.cache_warming_thread = threading.Timer(0, warm_cache_worker)\nUSER self.cache_warming_thread.daemon = True\nUSER self.cache_warming_thread.start()\nUSER \nUSER return chunks\nUSER \nUSER def send_message(self, inp):\nUSER self.event(\"message_send_starting\")\nUSER \nUSER self.cur_messages += [\nUSER dict(role=\"user\", content=inp),\nUSER ]\nUSER \nUSER chunks = self.format_messages()\nUSER messages = chunks.all_messages()\nUSER self.warm_cache(chunks)\nUSER \nUSER if self.verbose:\nUSER utils.show_messages(messages, functions=self.functions)\nUSER \nUSER self.multi_response_content = \"\"\nUSER if self.show_pretty() and self.stream:\nUSER self.mdstream = self.io.get_assistant_mdstream()\nUSER else:\nUSER self.mdstream = None\nUSER \nUSER retry_delay = 0.125\nUSER \nUSER litellm_ex = LiteLLMExceptions()\nUSER \nUSER self.usage_report = None\nUSER exhausted = False\nUSER interrupted = False\nUSER try:\nUSER while True:\nUSER try:\nUSER yield from self.send(messages, functions=self.functions)\nUSER break\nUSER except litellm_ex.exceptions_tuple() as err:\nUSER ex_info = litellm_ex.get_ex_info(err)\nUSER \nUSER if ex_info.name == \"ContextWindowExceededError\":\nUSER exhausted = True\nUSER break\nUSER \nUSER should_retry = ex_info.retry\nUSER if should_retry:\nUSER retry_delay *= 2\nUSER if retry_delay > RETRY_TIMEOUT:\nUSER should_retry = False\nUSER \nUSER if not should_retry:\nUSER self.mdstream = None\nUSER self.check_and_open_urls(err, ex_info.description)\nUSER break\nUSER \nUSER err_msg = str(err)\nUSER if ex_info.description:\nUSER self.io.tool_warning(err_msg)\nUSER self.io.tool_error(ex_info.description)\nUSER else:\nUSER self.io.tool_error(err_msg)\nUSER \nUSER self.io.tool_output(f\"Retrying in {retry_delay:.1f} seconds...\")\nUSER time.sleep(retry_delay)\nUSER continue\nUSER except KeyboardInterrupt:\nUSER interrupted = True\nUSER break\nUSER except FinishReasonLength:\nUSER # We hit the output limit!\nUSER if not self.main_model.info.get(\"supports_assistant_prefill\"):\nUSER exhausted = True\nUSER break\nUSER \nUSER self.multi_response_content = self.get_multi_response_content()\nUSER \nUSER if messages[-1][\"role\"] == \"assistant\":\nUSER messages[-1][\"content\"] = self.multi_response_content\nUSER else:\nUSER messages.append(\nUSER dict(role=\"assistant\", content=self.multi_response_content, prefix=True)\nUSER )\nUSER except Exception as err:\nUSER self.mdstream = None\nUSER lines = traceback.format_exception(type(err), err, err.__traceback__)\nUSER self.io.tool_warning(\"\".join(lines))\nUSER self.io.tool_error(str(err))\nUSER self.event(\"message_send_exception\", exception=str(err))\nUSER return\nUSER finally:\nUSER if self.mdstream:\nUSER self.live_incremental_response(True)\nUSER self.mdstream = None\nUSER \nUSER self.partial_response_content = self.get_multi_response_content(True)\nUSER self.multi_response_content = \"\"\nUSER \nUSER self.io.tool_output()\nUSER \nUSER self.show_usage_report()\nUSER \nUSER self.add_assistant_reply_to_cur_messages()\nUSER \nUSER if exhausted:\nUSER if self.cur_messages and self.cur_messages[-1][\"role\"] == \"user\":\nUSER self.cur_messages += [\nUSER dict(\nUSER role=\"assistant\",\nUSER content=\"FinishReasonLength exception: you sent too many tokens\",\nUSER ),\nUSER ]\nUSER \nUSER self.show_exhausted_error()\nUSER self.num_exhausted_context_windows += 1\nUSER return\nUSER \nUSER if self.partial_response_function_call:\nUSER args = self.parse_partial_args()\nUSER if args:\nUSER content = args.get(\"explanation\") or \"\"\nUSER else:\nUSER content = \"\"\nUSER elif self.partial_response_content:\nUSER content = self.partial_response_content\nUSER else:\nUSER content = \"\"\nUSER \nUSER if not interrupted:\nUSER add_rel_files_message = self.check_for_file_mentions(content)\nUSER if add_rel_files_message:\nUSER if self.reflected_message:\nUSER self.reflected_message += \"\\n\\n\" + add_rel_files_message\nUSER else:\nUSER self.reflected_message = add_rel_files_message\nUSER return\nUSER \nUSER try:\nUSER self.reply_completed()\nUSER except KeyboardInterrupt:\nUSER interrupted = True\nUSER \nUSER if interrupted:\nUSER # check if the last messages was role==user, append the ^C Key.. to it if so. ai!\nUSER self.cur_messages += [\nUSER dict(role=\"user\", content=\"^C KeyboardInterrupt\"),\nUSER dict(role=\"assistant\", content=\"I see that you interrupted my previous reply.\"),\nUSER ]\nUSER return\nUSER \nUSER edited = self.apply_updates()\nUSER \nUSER if edited:\nUSER self.aider_edited_files.update(edited)\nUSER saved_message = self.auto_commit(edited)\nUSER \nUSER if not saved_message and hasattr(self.gpt_prompts, \"files_content_gpt_edits_no_repo\"):\nUSER saved_message = self.gpt_prompts.files_content_gpt_edits_no_repo\nUSER \nUSER self.move_back_cur_messages(saved_message)\nUSER \nUSER if self.reflected_message:\nUSER return\nUSER \nUSER if edited and self.auto_lint:\nUSER lint_errors = self.lint_edited(edited)\nUSER self.auto_commit(edited, context=\"Ran the linter\")\nUSER self.lint_outcome = not lint_errors\nUSER if lint_errors:\nUSER ok = self.io.confirm_ask(\"Attempt to fix lint errors?\")\nUSER if ok:\nUSER self.reflected_message = lint_errors\nUSER return\nUSER \nUSER shared_output = self.run_shell_commands()\nUSER if shared_output:\nUSER self.cur_messages += [\nUSER dict(role=\"user\", content=shared_output),\nUSER dict(role=\"assistant\", content=\"Ok\"),\nUSER ]\nUSER \nUSER if edited and self.auto_test:\nUSER test_errors = self.commands.cmd_test(self.test_cmd)\nUSER self.test_outcome = not test_errors\nUSER if test_errors:\nUSER ok = self.io.confirm_ask(\"Attempt to fix test errors?\")\nUSER if ok:\nUSER self.reflected_message = test_errors\nUSER return\nUSER \nUSER def reply_completed(self):\nUSER pass\nUSER \nUSER def show_exhausted_error(self):\nUSER output_tokens = 0\nUSER if self.partial_response_content:\nUSER output_tokens = self.main_model.token_count(self.partial_response_content)\nUSER max_output_tokens = self.main_model.info.get(\"max_output_tokens\") or 0\nUSER \nUSER input_tokens = self.main_model.token_count(self.format_messages().all_messages())\nUSER max_input_tokens = self.main_model.info.get(\"max_input_tokens\") or 0\nUSER \nUSER total_tokens = input_tokens + output_tokens\nUSER \nUSER fudge = 0.7\nUSER \nUSER out_err = \"\"\nUSER if output_tokens >= max_output_tokens * fudge:\nUSER out_err = \" -- possibly exceeded output limit!\"\nUSER \nUSER inp_err = \"\"\nUSER if input_tokens >= max_input_tokens * fudge:\nUSER inp_err = \" -- possibly exhausted context window!\"\nUSER \nUSER tot_err = \"\"\nUSER if total_tokens >= max_input_tokens * fudge:\nUSER tot_err = \" -- possibly exhausted context window!\"\nUSER \nUSER res = [\"\", \"\"]\nUSER res.append(f\"Model {self.main_model.name} has hit a token limit!\")\nUSER res.append(\"Token counts below are approximate.\")\nUSER res.append(\"\")\nUSER res.append(f\"Input tokens: ~{input_tokens:,} of {max_input_tokens:,}{inp_err}\")\nUSER res.append(f\"Output tokens: ~{output_tokens:,} of {max_output_tokens:,}{out_err}\")\nUSER res.append(f\"Total tokens: ~{total_tokens:,} of {max_input_tokens:,}{tot_err}\")\nUSER \nUSER if output_tokens >= max_output_tokens:\nUSER res.append(\"\")\nUSER res.append(\"To reduce output tokens:\")\nUSER res.append(\"- Ask for smaller changes in each request.\")\nUSER res.append(\"- Break your code into smaller source files.\")\nUSER if \"diff\" not in self.main_model.edit_format:\nUSER res.append(\"- Use a stronger model that can return diffs.\")\nUSER \nUSER if input_tokens >= max_input_tokens or total_tokens >= max_input_tokens:\nUSER res.append(\"\")\nUSER res.append(\"To reduce input tokens:\")\nUSER res.append(\"- Use /tokens to see token usage.\")\nUSER res.append(\"- Use /drop to remove unneeded files from the chat session.\")\nUSER res.append(\"- Use /clear to clear the chat history.\")\nUSER res.append(\"- Break your code into smaller source files.\")\nUSER \nUSER res = \"\".join([line + \"\\n\" for line in res])\nUSER self.io.tool_error(res)\nUSER self.io.offer_url(urls.token_limits)\nUSER \nUSER def lint_edited(self, fnames):\nUSER res = \"\"\nUSER for fname in fnames:\nUSER if not fname:\nUSER continue\nUSER errors = self.linter.lint(self.abs_root_path(fname))\nUSER \nUSER if errors:\nUSER res += \"\\n\"\nUSER res += errors\nUSER res += \"\\n\"\nUSER \nUSER if res:\nUSER self.io.tool_warning(res)\nUSER \nUSER return res\nUSER \nUSER def add_assistant_reply_to_cur_messages(self):\nUSER if self.partial_response_content:\nUSER self.cur_messages += [dict(role=\"assistant\", content=self.partial_response_content)]\nUSER if self.partial_response_function_call:\nUSER self.cur_messages += [\nUSER dict(\nUSER role=\"assistant\",\nUSER content=None,\nUSER function_call=self.partial_response_function_call,\nUSER )\nUSER ]\nUSER \nUSER def get_file_mentions(self, content):\nUSER words = set(word for word in content.split())\nUSER \nUSER # drop sentence punctuation from the end\nUSER words = set(word.rstrip(\",.!;:?\") for word in words)\nUSER \nUSER # strip away all kinds of quotes\nUSER quotes = \"\".join(['\"', \"'\", \"`\"])\nUSER words = set(word.strip(quotes) for word in words)\nUSER \nUSER addable_rel_fnames = self.get_addable_relative_files()\nUSER \nUSER # Get basenames of files already in chat or read-only\nUSER existing_basenames = {os.path.basename(f) for f in self.get_inchat_relative_files()} | {\nUSER os.path.basename(self.get_rel_fname(f)) for f in self.abs_read_only_fnames\nUSER }\nUSER \nUSER mentioned_rel_fnames = set()\nUSER fname_to_rel_fnames = {}\nUSER for rel_fname in addable_rel_fnames:\nUSER # Skip files that share a basename with files already in chat\nUSER if os.path.basename(rel_fname) in existing_basenames:\nUSER continue\nUSER \nUSER normalized_rel_fname = rel_fname.replace(\"\\\\\", \"/\")\nUSER normalized_words = set(word.replace(\"\\\\\", \"/\") for word in words)\nUSER if normalized_rel_fname in normalized_words:\nUSER mentioned_rel_fnames.add(rel_fname)\nUSER \nUSER fname = os.path.basename(rel_fname)\nUSER \nUSER # Don't add basenames that could be plain words like \"run\" or \"make\"\nUSER if \"/\" in fname or \"\\\\\" in fname or \".\" in fname or \"_\" in fname or \"-\" in fname:\nUSER if fname not in fname_to_rel_fnames:\nUSER fname_to_rel_fnames[fname] = []\nUSER fname_to_rel_fnames[fname].append(rel_fname)\nUSER \nUSER for fname, rel_fnames in fname_to_rel_fnames.items():\nUSER if len(rel_fnames) == 1 and fname in words:\nUSER mentioned_rel_fnames.add(rel_fnames[0])\nUSER \nUSER return mentioned_rel_fnames\nUSER \nUSER def check_for_file_mentions(self, content):\nUSER mentioned_rel_fnames = self.get_file_mentions(content)\nUSER \nUSER new_mentions = mentioned_rel_fnames - self.ignore_mentions\nUSER \nUSER if not new_mentions:\nUSER return\nUSER \nUSER added_fnames = []\nUSER group = ConfirmGroup(new_mentions)\nUSER for rel_fname in sorted(new_mentions):\nUSER if self.io.confirm_ask(f\"Add {rel_fname} to the chat?\", group=group, allow_never=True):\nUSER self.add_rel_fname(rel_fname)\nUSER added_fnames.append(rel_fname)\nUSER else:\nUSER self.ignore_mentions.add(rel_fname)\nUSER \nUSER if added_fnames:\nUSER return prompts.added_files.format(fnames=\", \".join(added_fnames))\nUSER \nUSER def send(self, messages, model=None, functions=None):\nUSER if not model:\nUSER model = self.main_model\nUSER \nUSER self.partial_response_content = \"\"\nUSER self.partial_response_function_call = dict()\nUSER \nUSER self.io.log_llm_history(\"TO LLM\", format_messages(messages))\nUSER \nUSER if self.main_model.use_temperature:\nUSER temp = self.temperature\nUSER else:\nUSER temp = None\nUSER \nUSER completion = None\nUSER try:\nUSER hash_object, completion = send_completion(\nUSER model.name,\nUSER messages,\nUSER functions,\nUSER self.stream,\nUSER temp,\nUSER extra_params=model.extra_params,\nUSER )\nUSER self.chat_completion_call_hashes.append(hash_object.hexdigest())\nUSER \nUSER if self.stream:\nUSER yield from self.show_send_output_stream(completion)\nUSER else:\nUSER self.show_send_output(completion)\nUSER \nUSER # Calculate costs for successful responses\nUSER self.calculate_and_show_tokens_and_cost(messages, completion)\nUSER \nUSER except LiteLLMExceptions().exceptions_tuple() as err:\nUSER ex_info = LiteLLMExceptions().get_ex_info(err)\nUSER if ex_info.name == \"ContextWindowExceededError\":\nUSER # Still calculate costs for context window errors\nUSER self.calculate_and_show_tokens_and_cost(messages, completion)\nUSER raise\nUSER except KeyboardInterrupt as kbi:\nUSER self.keyboard_interrupt()\nUSER raise kbi\nUSER finally:\nUSER self.io.log_llm_history(\nUSER \"LLM RESPONSE\",\nUSER format_content(\"ASSISTANT\", self.partial_response_content),\nUSER )\nUSER \nUSER if self.partial_response_content:\nUSER self.io.ai_output(self.partial_response_content)\nUSER elif self.partial_response_function_call:\nUSER # TODO: push this into subclasses\nUSER args = self.parse_partial_args()\nUSER if args:\nUSER self.io.ai_output(json.dumps(args, indent=4))\nUSER \nUSER def show_send_output(self, completion):\nUSER if self.verbose:\nUSER print(completion)\nUSER \nUSER if not completion.choices:\nUSER self.io.tool_error(str(completion))\nUSER return\nUSER \nUSER show_func_err = None\nUSER show_content_err = None\nUSER try:\nUSER if completion.choices[0].message.tool_calls:\nUSER self.partial_response_function_call = (\nUSER completion.choices[0].message.tool_calls[0].function\nUSER )\nUSER except AttributeError as func_err:\nUSER show_func_err = func_err\nUSER \nUSER try:\nUSER self.partial_response_content = completion.choices[0].message.content or \"\"\nUSER except AttributeError as content_err:\nUSER show_content_err = content_err\nUSER \nUSER resp_hash = dict(\nUSER function_call=str(self.partial_response_function_call),\nUSER content=self.partial_response_content,\nUSER )\nUSER resp_hash = hashlib.sha1(json.dumps(resp_hash, sort_keys=True).encode())\nUSER self.chat_completion_response_hashes.append(resp_hash.hexdigest())\nUSER \nUSER if show_func_err and show_content_err:\nUSER self.io.tool_error(show_func_err)\nUSER self.io.tool_error(show_content_err)\nUSER raise Exception(\"No data found in LLM response!\")\nUSER \nUSER show_resp = self.render_incremental_response(True)\nUSER self.io.assistant_output(show_resp, pretty=self.show_pretty())\nUSER \nUSER if (\nUSER hasattr(completion.choices[0], \"finish_reason\")\nUSER and completion.choices[0].finish_reason == \"length\"\nUSER ):\nUSER raise FinishReasonLength()\nUSER \nUSER def show_send_output_stream(self, completion):\nUSER for chunk in completion:\nUSER if len(chunk.choices) == 0:\nUSER continue\nUSER \nUSER if (\nUSER hasattr(chunk.choices[0], \"finish_reason\")\nUSER and chunk.choices[0].finish_reason == \"length\"\nUSER ):\nUSER raise FinishReasonLength()\nUSER \nUSER try:\nUSER func = chunk.choices[0].delta.function_call\nUSER # dump(func)\nUSER for k, v in func.items():\nUSER if k in self.partial_response_function_call:\nUSER self.partial_response_function_call[k] += v\nUSER else:\nUSER self.partial_response_function_call[k] = v\nUSER except AttributeError:\nUSER pass\nUSER \nUSER try:\nUSER text = chunk.choices[0].delta.content\nUSER if text:\nUSER self.partial_response_content += text\nUSER except AttributeError:\nUSER text = None\nUSER \nUSER if self.show_pretty():\nUSER self.live_incremental_response(False)\nUSER elif text:\nUSER try:\nUSER sys.stdout.write(text)\nUSER except UnicodeEncodeError:\nUSER # Safely encode and decode the text\nUSER safe_text = text.encode(sys.stdout.encoding, errors=\"backslashreplace\").decode(\nUSER sys.stdout.encoding\nUSER )\nUSER sys.stdout.write(safe_text)\nUSER sys.stdout.flush()\nUSER yield text\nUSER \nUSER def live_incremental_response(self, final):\nUSER show_resp = self.render_incremental_response(final)\nUSER self.mdstream.update(show_resp, final=final)\nUSER \nUSER def render_incremental_response(self, final):\nUSER return self.get_multi_response_content()\nUSER \nUSER def calculate_and_show_tokens_and_cost(self, messages, completion=None):\nUSER prompt_tokens = 0\nUSER completion_tokens = 0\nUSER cache_hit_tokens = 0\nUSER cache_write_tokens = 0\nUSER \nUSER if completion and hasattr(completion, \"usage\") and completion.usage is not None:\nUSER prompt_tokens = completion.usage.prompt_tokens\nUSER completion_tokens = completion.usage.completion_tokens\nUSER cache_hit_tokens = getattr(completion.usage, \"prompt_cache_hit_tokens\", 0) or getattr(\nUSER completion.usage, \"cache_read_input_tokens\", 0\nUSER )\nUSER cache_write_tokens = getattr(completion.usage, \"cache_creation_input_tokens\", 0)\nUSER \nUSER if hasattr(completion.usage, \"cache_read_input_tokens\") or hasattr(\nUSER completion.usage, \"cache_creation_input_tokens\"\nUSER ):\nUSER self.message_tokens_sent += prompt_tokens\nUSER self.message_tokens_sent += cache_write_tokens\nUSER else:\nUSER self.message_tokens_sent += prompt_tokens\nUSER \nUSER else:\nUSER prompt_tokens = self.main_model.token_count(messages)\nUSER completion_tokens = self.main_model.token_count(self.partial_response_content)\nUSER self.message_tokens_sent += prompt_tokens\nUSER \nUSER self.message_tokens_received += completion_tokens\nUSER \nUSER tokens_report = f\"Tokens: {format_tokens(self.message_tokens_sent)} sent\"\nUSER \nUSER if cache_write_tokens:\nUSER tokens_report += f\", {format_tokens(cache_write_tokens)} cache write\"\nUSER if cache_hit_tokens:\nUSER tokens_report += f\", {format_tokens(cache_hit_tokens)} cache hit\"\nUSER tokens_report += f\", {format_tokens(self.message_tokens_received)} received.\"\nUSER \nUSER if not self.main_model.info.get(\"input_cost_per_token\"):\nUSER self.usage_report = tokens_report\nUSER return\nUSER \nUSER cost = 0\nUSER \nUSER input_cost_per_token = self.main_model.info.get(\"input_cost_per_token\") or 0\nUSER output_cost_per_token = self.main_model.info.get(\"output_cost_per_token\") or 0\nUSER input_cost_per_token_cache_hit = (\nUSER self.main_model.info.get(\"input_cost_per_token_cache_hit\") or 0\nUSER )\nUSER \nUSER # deepseek\nUSER # prompt_cache_hit_tokens + prompt_cache_miss_tokens\nUSER # == prompt_tokens == total tokens that were sent\nUSER #\nUSER # Anthropic\nUSER # cache_creation_input_tokens + cache_read_input_tokens + prompt\nUSER # == total tokens that were\nUSER \nUSER if input_cost_per_token_cache_hit:\nUSER # must be deepseek\nUSER cost += input_cost_per_token_cache_hit * cache_hit_tokens\nUSER cost += (prompt_tokens - input_cost_per_token_cache_hit) * input_cost_per_token\nUSER else:\nUSER # hard code the anthropic adjustments, no-ops for other models since cache_x_tokens==0\nUSER cost += cache_write_tokens * input_cost_per_token * 1.25\nUSER cost += cache_hit_tokens * input_cost_per_token * 0.10\nUSER cost += prompt_tokens * input_cost_per_token\nUSER \nUSER cost += completion_tokens * output_cost_per_token\nUSER \nUSER self.total_cost += cost\nUSER self.message_cost += cost\nUSER \nUSER def format_cost(value):\nUSER if value == 0:\nUSER return \"0.00\"\nUSER magnitude = abs(value)\nUSER if magnitude >= 0.01:\nUSER return f\"{value:.2f}\"\nUSER else:\nUSER return f\"{value:.{max(2, 2 - int(math.log10(magnitude)))}f}\"\nUSER \nUSER cost_report = (\nUSER f\"Cost: ${format_cost(self.message_cost)} message,\"\nUSER f\" ${format_cost(self.total_cost)} session.\"\nUSER )\nUSER \nUSER if self.add_cache_headers and self.stream:\nUSER warning = \" Use --no-stream for accurate caching costs.\"\nUSER self.usage_report = tokens_report + \"\\n\" + cost_report + warning\nUSER return\nUSER \nUSER if cache_hit_tokens and cache_write_tokens:\nUSER sep = \"\\n\"\nUSER else:\nUSER sep = \" \"\nUSER \nUSER self.usage_report = tokens_report + sep + cost_report\nUSER \nUSER def show_usage_report(self):\nUSER if not self.usage_report:\nUSER return\nUSER \nUSER self.io.tool_output(self.usage_report)\nUSER \nUSER prompt_tokens = self.message_tokens_sent\nUSER completion_tokens = self.message_tokens_received\nUSER self.event(\nUSER \"message_send\",\nUSER main_model=self.main_model,\nUSER edit_format=self.edit_format,\nUSER prompt_tokens=prompt_tokens,\nUSER completion_tokens=completion_tokens,\nUSER total_tokens=prompt_tokens + completion_tokens,\nUSER cost=self.message_cost,\nUSER total_cost=self.total_cost,\nUSER )\nUSER \nUSER self.message_cost = 0.0\nUSER self.message_tokens_sent = 0\nUSER self.message_tokens_received = 0\nUSER \nUSER def get_multi_response_content(self, final=False):\nUSER cur = self.multi_response_content or \"\"\nUSER new = self.partial_response_content or \"\"\nUSER \nUSER if new.rstrip() != new and not final:\nUSER new = new.rstrip()\nUSER return cur + new\nUSER \nUSER def get_rel_fname(self, fname):\nUSER try:\nUSER return os.path.relpath(fname, self.root)\nUSER except ValueError:\nUSER return fname\nUSER \nUSER def get_inchat_relative_files(self):\nUSER files = [self.get_rel_fname(fname) for fname in self.abs_fnames]\nUSER return sorted(set(files))\nUSER \nUSER def is_file_safe(self, fname):\nUSER try:\nUSER return Path(self.abs_root_path(fname)).is_file()\nUSER except OSError:\nUSER return\nUSER \nUSER def get_all_relative_files(self):\nUSER if self.repo:\nUSER files = self.repo.get_tracked_files()\nUSER else:\nUSER files = self.get_inchat_relative_files()\nUSER \nUSER # This is quite slow in large repos\nUSER # files = [fname for fname in files if self.is_file_safe(fname)]\nUSER \nUSER return sorted(set(files))\nUSER \nUSER def get_all_abs_files(self):\nUSER files = self.get_all_relative_files()\nUSER files = [self.abs_root_path(path) for path in files]\nUSER return files\nUSER \nUSER def get_addable_relative_files(self):\nUSER all_files = set(self.get_all_relative_files())\nUSER inchat_files = set(self.get_inchat_relative_files())\nUSER read_only_files = set(self.get_rel_fname(fname) for fname in self.abs_read_only_fnames)\nUSER return all_files - inchat_files - read_only_files\nUSER \nUSER def check_for_dirty_commit(self, path):\nUSER if not self.repo:\nUSER return\nUSER if not self.dirty_commits:\nUSER return\nUSER if not self.repo.is_dirty(path):\nUSER return\nUSER \nUSER # We need a committed copy of the file in order to /undo, so skip this\nUSER # fullp = Path(self.abs_root_path(path))\nUSER # if not fullp.stat().st_size:\nUSER # return\nUSER \nUSER self.io.tool_output(f\"Committing {path} before applying edits.\")\nUSER self.need_commit_before_edits.add(path)\nUSER \nUSER def allowed_to_edit(self, path):\nUSER full_path = self.abs_root_path(path)\nUSER if self.repo:\nUSER need_to_add = not self.repo.path_in_repo(path)\nUSER else:\nUSER need_to_add = False\nUSER \nUSER if full_path in self.abs_fnames:\nUSER self.check_for_dirty_commit(path)\nUSER return True\nUSER \nUSER if self.repo and self.repo.git_ignored_file(path):\nUSER self.io.tool_warning(f\"Skipping edits to {path} that matches gitignore spec.\")\nUSER return\nUSER \nUSER if not Path(full_path).exists():\nUSER if not self.io.confirm_ask(\"Create new file?\", subject=path):\nUSER self.io.tool_output(f\"Skipping edits to {path}\")\nUSER return\nUSER \nUSER if not self.dry_run:\nUSER if not utils.touch_file(full_path):\nUSER self.io.tool_error(f\"Unable to create {path}, skipping edits.\")\nUSER return\nUSER \nUSER # Seems unlikely that we needed to create the file, but it was\nUSER # actually already part of the repo.\nUSER # But let's only add if we need to, just to be safe.\nUSER if need_to_add:\nUSER self.repo.repo.git.add(full_path)\nUSER \nUSER self.abs_fnames.add(full_path)\nUSER self.check_added_files()\nUSER return True\nUSER \nUSER if not self.io.confirm_ask(\nUSER \"Allow edits to file that has not been added to the chat?\",\nUSER subject=path,\nUSER ):\nUSER self.io.tool_output(f\"Skipping edits to {path}\")\nUSER return\nUSER \nUSER if need_to_add:\nUSER self.repo.repo.git.add(full_path)\nUSER \nUSER self.abs_fnames.add(full_path)\nUSER self.check_added_files()\nUSER self.check_for_dirty_commit(path)\nUSER \nUSER return True\nUSER \nUSER warning_given = False\nUSER \nUSER def check_added_files(self):\nUSER if self.warning_given:\nUSER return\nUSER \nUSER warn_number_of_files = 4\nUSER warn_number_of_tokens = 20 * 1024\nUSER \nUSER num_files = len(self.abs_fnames)\nUSER if num_files < warn_number_of_files:\nUSER return\nUSER \nUSER tokens = 0\nUSER for fname in self.abs_fnames:\nUSER if is_image_file(fname):\nUSER continue\nUSER content = self.io.read_text(fname)\nUSER tokens += self.main_model.token_count(content)\nUSER \nUSER if tokens < warn_number_of_tokens:\nUSER return\nUSER \nUSER self.io.tool_warning(\"Warning: it's best to only add files that need changes to the chat.\")\nUSER self.io.tool_warning(urls.edit_errors)\nUSER self.warning_given = True\nUSER \nUSER def prepare_to_edit(self, edits):\nUSER res = []\nUSER seen = dict()\nUSER \nUSER self.need_commit_before_edits = set()\nUSER \nUSER for edit in edits:\nUSER path = edit[0]\nUSER if path is None:\nUSER res.append(edit)\nUSER continue\nUSER if path == \"python\":\nUSER dump(edits)\nUSER if path in seen:\nUSER allowed = seen[path]\nUSER else:\nUSER allowed = self.allowed_to_edit(path)\nUSER seen[path] = allowed\nUSER \nUSER if allowed:\nUSER res.append(edit)\nUSER \nUSER self.dirty_commit()\nUSER self.need_commit_before_edits = set()\nUSER \nUSER return res\nUSER \nUSER def apply_updates(self):\nUSER edited = set()\nUSER try:\nUSER edits = self.get_edits()\nUSER edits = self.apply_edits_dry_run(edits)\nUSER edits = self.prepare_to_edit(edits)\nUSER edited = set(edit[0] for edit in edits)\nUSER \nUSER self.apply_edits(edits)\nUSER except ValueError as err:\nUSER self.num_malformed_responses += 1\nUSER \nUSER err = err.args[0]\nUSER \nUSER self.io.tool_error(\"The LLM did not conform to the edit format.\")\nUSER self.io.tool_output(urls.edit_errors)\nUSER self.io.tool_output()\nUSER self.io.tool_output(str(err))\nUSER \nUSER self.reflected_message = str(err)\nUSER return edited\nUSER \nUSER except ANY_GIT_ERROR as err:\nUSER self.io.tool_error(str(err))\nUSER return edited\nUSER except Exception as err:\nUSER self.io.tool_error(\"Exception while updating files:\")\nUSER self.io.tool_error(str(err), strip=False)\nUSER \nUSER traceback.print_exc()\nUSER \nUSER self.reflected_message = str(err)\nUSER return edited\nUSER \nUSER for path in edited:\nUSER if self.dry_run:\nUSER self.io.tool_output(f\"Did not apply edit to {path} (--dry-run)\")\nUSER else:\nUSER self.io.tool_output(f\"Applied edit to {path}\")\nUSER \nUSER return edited\nUSER \nUSER def parse_partial_args(self):\nUSER # dump(self.partial_response_function_call)\nUSER \nUSER data = self.partial_response_function_call.get(\"arguments\")\nUSER if not data:\nUSER return\nUSER \nUSER try:\nUSER return json.loads(data)\nUSER except JSONDecodeError:\nUSER pass\nUSER \nUSER try:\nUSER return json.loads(data + \"]}\")\nUSER except JSONDecodeError:\nUSER pass\nUSER \nUSER try:\nUSER return json.loads(data + \"}]}\")\nUSER except JSONDecodeError:\nUSER pass\nUSER \nUSER try:\nUSER return json.loads(data + '\"}]}')\nUSER except JSONDecodeError:\nUSER pass\nUSER \nUSER # commits...\nUSER \nUSER def get_context_from_history(self, history):\nUSER context = \"\"\nUSER if history:\nUSER for msg in history:\nUSER context += \"\\n\" + msg[\"role\"].upper() + \": \" + msg[\"content\"] + \"\\n\"\nUSER \nUSER return context\nUSER \nUSER def auto_commit(self, edited, context=None):\nUSER if not self.repo or not self.auto_commits or self.dry_run:\nUSER return\nUSER \nUSER if not context:\nUSER context = self.get_context_from_history(self.cur_messages)\nUSER \nUSER try:\nUSER res = self.repo.commit(fnames=edited, context=context, aider_edits=True)\nUSER if res:\nUSER self.show_auto_commit_outcome(res)\nUSER commit_hash, commit_message = res\nUSER return self.gpt_prompts.files_content_gpt_edits.format(\nUSER hash=commit_hash,\nUSER message=commit_message,\nUSER )\nUSER \nUSER return self.gpt_prompts.files_content_gpt_no_edits\nUSER except ANY_GIT_ERROR as err:\nUSER self.io.tool_error(f\"Unable to commit: {str(err)}\")\nUSER return\nUSER \nUSER def show_auto_commit_outcome(self, res):\nUSER commit_hash, commit_message = res\nUSER self.last_aider_commit_hash = commit_hash\nUSER self.aider_commit_hashes.add(commit_hash)\nUSER self.last_aider_commit_message = commit_message\nUSER if self.show_diffs:\nUSER self.commands.cmd_diff()\nUSER \nUSER def show_undo_hint(self):\nUSER if not self.commit_before_message:\nUSER return\nUSER if self.commit_before_message[-1] != self.repo.get_head_commit_sha():\nUSER self.io.tool_output(\"You can use /undo to undo and discard each aider commit.\")\nUSER \nUSER def dirty_commit(self):\nUSER if not self.need_commit_before_edits:\nUSER return\nUSER if not self.dirty_commits:\nUSER return\nUSER if not self.repo:\nUSER return\nUSER \nUSER self.repo.commit(fnames=self.need_commit_before_edits)\nUSER \nUSER # files changed, move cur messages back behind the files messages\nUSER # self.move_back_cur_messages(self.gpt_prompts.files_content_local_edits)\nUSER return True\nUSER \nUSER def get_edits(self, mode=\"update\"):\nUSER return []\nUSER \nUSER def apply_edits(self, edits):\nUSER return\nUSER \nUSER def apply_edits_dry_run(self, edits):\nUSER return edits\nUSER \nUSER def run_shell_commands(self):\nUSER if not self.suggest_shell_commands:\nUSER return \"\"\nUSER \nUSER done = set()\nUSER group = ConfirmGroup(set(self.shell_commands))\nUSER accumulated_output = \"\"\nUSER for command in self.shell_commands:\nUSER if command in done:\nUSER continue\nUSER done.add(command)\nUSER output = self.handle_shell_commands(command, group)\nUSER if output:\nUSER accumulated_output += output + \"\\n\\n\"\nUSER return accumulated_output\nUSER \nUSER def handle_shell_commands(self, commands_str, group):\nUSER commands = commands_str.strip().splitlines()\nUSER command_count = sum(\nUSER 1 for cmd in commands if cmd.strip() and not cmd.strip().startswith(\"#\")\nUSER )\nUSER prompt = \"Run shell command?\" if command_count == 1 else \"Run shell commands?\"\nUSER if not self.io.confirm_ask(\nUSER prompt,\nUSER subject=\"\\n\".join(commands),\nUSER explicit_yes_required=True,\nUSER group=group,\nUSER allow_never=True,\nUSER ):\nUSER return\nUSER \nUSER accumulated_output = \"\"\nUSER for command in commands:\nUSER command = command.strip()\nUSER if not command or command.startswith(\"#\"):\nUSER continue\nUSER \nUSER self.io.tool_output()\nUSER self.io.tool_output(f\"Running {command}\")\nUSER # Add the command to input history\nUSER self.io.add_to_input_history(f\"/run {command.strip()}\")\nUSER exit_status, output = run_cmd(command, error_print=self.io.tool_error, cwd=self.root)\nUSER if output:\nUSER accumulated_output += f\"Output from {command}\\n{output}\\n\"\nUSER \nUSER if accumulated_output.strip() and self.io.confirm_ask(\nUSER \"Add command output to the chat?\", allow_never=True\nUSER ):\nUSER num_lines = len(accumulated_output.strip().splitlines())\nUSER line_plural = \"line\" if num_lines == 1 else \"lines\"\nUSER self.io.tool_output(f\"Added {num_lines} {line_plural} of output to the chat.\")\nUSER return accumulated_output\nUSER ```\n-------\nASSISTANT type: text\nASSISTANT text: Ok, I will use that as the true, current contents of the files.\nASSISTANT cache_control: {'type': 'ephemeral'}\n-------\nUSER \nUSER I've written your instructions in comments in the code and marked them with \"ai\"\nUSER You can see the \"AI\" comments shown below (marked with \u2588).\nUSER Find them in the code files I've shared with you, and follow their instructions.\nUSER \nUSER After completing those instructions, also be sure to remove all the \"AI\" comments from the code too.\nUSER \nUSER aider/coders/base_coder.py:\nUSER \u22ee...\nUSER \u2502class Coder:\nUSER \u2502 abs_fnames = None\nUSER \u22ee...\nUSER \u2502 def send_message(self, inp):\nUSER \u2502 self.event(\"message_send_starting\")\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 interrupted = True\nUSER \u2502\nUSER \u2502 if interrupted:\nUSER \u2588 # check if the last messages was role==user, append the ^C Key.. to it if so. ai!\nUSER \u2502 self.cur_messages += [\nUSER \u2502 dict(role=\"user\", content=\"^C KeyboardInterrupt\"),\nUSER \u2502 dict(role=\"assistant\", content=\"I see that you interrupted my previous reply.\"),\nUSER \u22ee...\n-------\nUSER ^C KeyboardInterrupt\n-------\nASSISTANT I see that you interrupted my previous reply.\n-------\nUSER \nUSER I've written your instructions in comments in the code and marked them with \"ai\"\nUSER You can see the \"AI\" comments shown below (marked with \u2588).\nUSER Find them in the code files I've shared with you, and follow their instructions.\nUSER \nUSER After completing those instructions, also be sure to remove all the \"AI\" comments from the code too.\nUSER \nUSER aider/coders/base_coder.py:\nUSER \u22ee...\nUSER \u2502class Coder:\nUSER \u2502 abs_fnames = None\nUSER \u22ee...\nUSER \u2502 def send_message(self, inp):\nUSER \u2502 self.event(\"message_send_starting\")\nUSER \u2502\nUSER \u22ee...\nUSER \u2502 interrupted = True\nUSER \u2502\nUSER \u2502 if interrupted:\nUSER \u2588 # check if the last messages was role==user, append the ^C Key.. to it if so. ai!\nUSER \u2502 self.cur_messages += [\nUSER \u2502 dict(role=\"user\", content=\"^C KeyboardInterrupt\"),\nUSER \u2502 dict(role=\"assistant\", content=\"I see that you interrupted my previous reply.\"),\nUSER \u22ee..."}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945840}
+{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945844}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945847}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945847}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 19527, "completion_tokens": 236, "total_tokens": 19763, "cost": 0.062121, "total_cost": 0.062121}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945854}
+{"event": "command_code", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945871}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945871}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 22058, "completion_tokens": 191, "total_tokens": 22249, "cost": 0.069039, "total_cost": 0.13116}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945879}
+{"event": "command_commit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945909}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945913}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945929}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945931}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945931}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945940}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945940}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945940}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 21670, "completion_tokens": 263, "total_tokens": 21933, "cost": 0.068955, "total_cost": 0.068955}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945948}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945957}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 22349, "completion_tokens": 137, "total_tokens": 22486, "cost": 0.069102, "total_cost": 0.13805699999999999}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945963}
+{"event": "command_reset", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945977}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945981}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737945984}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 21509, "completion_tokens": 450, "total_tokens": 21959, "cost": 0.07127700000000001, "total_cost": 0.209334}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946000}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946049}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 22196, "completion_tokens": 227, "total_tokens": 22423, "cost": 0.06999300000000001, "total_cost": 0.279327}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946058}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946143}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 24626, "completion_tokens": 495, "total_tokens": 25121, "cost": 0.081303, "total_cost": 0.36063}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946159}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946200}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 25289, "completion_tokens": 343, "total_tokens": 25632, "cost": 0.081012, "total_cost": 0.441642}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946210}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946254}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946256}
+{"event": "cli session", "properties": {"main_model": "gpt-4", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946256}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946260}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946261}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946307}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946307}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946307}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946307}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946307}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 25942, "completion_tokens": 210, "total_tokens": 26152, "cost": 0.080976, "total_cost": 0.522618}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946315}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946327}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946328}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946330}
+{"event": "cli session", "properties": {"main_model": "gpt-4", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946330}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946333}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946334}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946362}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946364}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946367}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946369}
+{"event": "cli session", "properties": {"main_model": "gpt-4", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "gpt-4", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946369}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946371}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946402}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946406}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946407}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946411}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946543}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946550}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946550}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946550}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946694}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946696}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946696}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946698}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946698}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946828}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946830}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946830}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946849}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946851}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946851}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946898}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946900}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946900}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946967}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946969}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946970}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737946971}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947066}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947068}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947068}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947090}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947092}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947092}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947287}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947289}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947289}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947321}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947322}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947322}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947330}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947333}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947335}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947335}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947344}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947349}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947351}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947351}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 10010, "completion_tokens": 89, "total_tokens": 10099, "cost": 0.031365000000000004, "total_cost": 0.031365000000000004}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947355}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947355}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947361}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947363}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737947367}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737999053}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737999054}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737999054}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737999458}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737999461}
+{"event": "cli session", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "claude-3-5-sonnet-20241022", "editor_model": "deepseek/deepseek-chat", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737999461}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737999478}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737999649}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1737999704}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014260}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014264}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014264}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014425}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014429}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014432}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014432}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014442}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014446}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014449}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014449}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014456}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014462}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014463}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014463}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 68, "completion_tokens": 36, "total_tokens": 104, "cost": 1.9600000000000002e-05, "total_cost": 1.9600000000000002e-05}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014474}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014474}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014484}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014485}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014485}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 68, "completion_tokens": 38, "total_tokens": 106, "cost": 2.1056000000000003e-05, "total_cost": 2.1056000000000003e-05}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014574}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014574}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014659}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014661}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014661}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 68, "completion_tokens": 36, "total_tokens": 104, "cost": 2.0496e-05, "total_cost": 2.0496e-05}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014668}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014668}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014695}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014696}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014696}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 68, "completion_tokens": 39, "total_tokens": 107, "cost": 2.1336e-05, "total_cost": 2.1336e-05}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014700}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014700}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014756}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014757}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014757}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 68, "completion_tokens": 39, "total_tokens": 107, "cost": 2.1336e-05, "total_cost": 2.1336e-05}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014760}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014760}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014765}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014767}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014767}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014783}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014785}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014786}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738014786}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738015153}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738015969}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738015971}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738015971}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738015995}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738015998}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016000}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016000}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 78, "completion_tokens": 37, "total_tokens": 115, "cost": 0.000789, "total_cost": 0.000789}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016002}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016002}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016009}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016010}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016010}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016048}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016050}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016052}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016052}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016068}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016070}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016072}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016072}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016156}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016158}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016160}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016160}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 68, "completion_tokens": 39, "total_tokens": 107, "cost": 2.1336e-05, "total_cost": 2.1336e-05}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016211}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016211}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016870}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016872}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016872}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 68, "completion_tokens": 29, "total_tokens": 97, "cost": 1.8536e-05, "total_cost": 1.8536e-05}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016875}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016875}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016903}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016905}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016905}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 68, "completion_tokens": 31, "total_tokens": 99, "cost": 1.9096e-05, "total_cost": 1.9096e-05}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016908}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738016908}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017041}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017043}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017043}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017173}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017175}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017177}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017177}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 68, "completion_tokens": 30, "total_tokens": 98, "cost": 1.8816e-05, "total_cost": 1.8816e-05}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017278}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017278}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017339}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017340}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017341}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017404}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017405}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017406}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017407}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 68, "completion_tokens": 35, "total_tokens": 103, "cost": 2.0216e-05, "total_cost": 2.0216e-05}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017521}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017521}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017554}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017556}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017556}
+{"event": "message_send", "properties": {"main_model": "deepseek/deepseek-chat", "weak_model": "deepseek/deepseek-chat", "editor_model": "deepseek/deepseek-chat", "edit_format": "ask", "prompt_tokens": 68, "completion_tokens": 36, "total_tokens": 104, "cost": 2.0496e-05, "total_cost": 2.0496e-05}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017857}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738017857}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738025037}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738025039}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738025039}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738025042}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738025046}
+{"event": "command_web", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738025057}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738025087}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 21842, "completion_tokens": 341, "total_tokens": 22183, "cost": 0.070641, "total_cost": 0.070641}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738025098}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738025156}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 22411, "completion_tokens": 163, "total_tokens": 22574, "cost": 0.069678, "total_cost": 0.140319}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738025162}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031270}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031272}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031272}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031282}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031293}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031295}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031295}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031303}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031305}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031305}
+{"event": "message_send", "properties": {"main_model": "openrouter/deepseek/deepseek-chat", "weak_model": "openrouter/deepseek/deepseek-chat", "editor_model": "openrouter/deepseek/deepseek-chat", "edit_format": "diff", "prompt_tokens": 9986, "completion_tokens": 9, "total_tokens": 9995, "cost": 0.0014005600000000001, "total_cost": 0.0014005600000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031311}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031311}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031328}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031329}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031330}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031349}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031351}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031351}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738031355}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085256}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085256}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085431}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085434}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085434}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085435}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085444}
+{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085482}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085482}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 19700, "completion_tokens": 357, "total_tokens": 20057, "cost": 0.064455, "total_cost": 0.064455}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085517}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085518}
+{"event": "command_code", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085524}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085524}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 22172, "completion_tokens": 438, "total_tokens": 22610, "cost": 0.07308600000000001, "total_cost": 0.13754100000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085547}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085576}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 23192, "completion_tokens": 129, "total_tokens": 23321, "cost": 0.071511, "total_cost": 0.20905200000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085592}
+{"event": "command_diff", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085710}
+{"event": "command_git", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085722}
+{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085755}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085755}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 21308, "completion_tokens": 276, "total_tokens": 21584, "cost": 0.068064, "total_cost": 0.27711600000000003}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085771}
+{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085876}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085876}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 21601, "completion_tokens": 610, "total_tokens": 22211, "cost": 0.073953, "total_cost": 0.351069}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085906}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085912}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085916}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 24320, "completion_tokens": 574, "total_tokens": 24894, "cost": 0.08157, "total_cost": 0.432639}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085935}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085937}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 25204, "completion_tokens": 244, "total_tokens": 25448, "cost": 0.079272, "total_cost": 0.511911}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085950}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085951}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 25755, "completion_tokens": 282, "total_tokens": 26037, "cost": 0.081495, "total_cost": 0.593406}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085964}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085964}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 26574, "completion_tokens": 279, "total_tokens": 26853, "cost": 0.083907, "total_cost": 0.6773129999999999}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738085976}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086534}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086534}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086573}
+{"event": "repo", "properties": {"num_files": 430}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086575}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086575}
+{"event": "command_editor", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086583}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086653}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 10027, "completion_tokens": 966, "total_tokens": 10993, "cost": 0.044571, "total_cost": 0.044571}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086679}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086722}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 11868, "completion_tokens": 621, "total_tokens": 12489, "cost": 0.044919, "total_cost": 0.08949}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086738}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086751}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086782}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086795}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086809}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 13195, "completion_tokens": 377, "total_tokens": 13572, "cost": 0.04524, "total_cost": 0.13473000000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086828}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086847}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 13821, "completion_tokens": 355, "total_tokens": 14176, "cost": 0.046787999999999996, "total_cost": 0.181518}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086865}
+{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086893}
+{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086908}
+{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086913}
+{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086915}
+{"event": "command_tokens", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086916}
+{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086948}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086948}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 6796, "completion_tokens": 247, "total_tokens": 7043, "cost": 0.024093, "total_cost": 0.20561100000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738086958}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087086}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 9572, "completion_tokens": 227, "total_tokens": 9799, "cost": 0.032121000000000004, "total_cost": 0.23773200000000003}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087100}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087115}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 9937, "completion_tokens": 295, "total_tokens": 10232, "cost": 0.034236, "total_cost": 0.27196800000000004}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087127}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087383}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087383}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087409}
+{"event": "repo", "properties": {"num_files": 431}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087411}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087411}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087432}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 16779, "completion_tokens": 424, "total_tokens": 17203, "cost": 0.056697, "total_cost": 0.056697}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087451}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087566}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087566}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087566}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 33004, "completion_tokens": 272, "total_tokens": 33276, "cost": 0.103092, "total_cost": 0.15978900000000001}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087576}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087652}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 33331, "completion_tokens": 78, "total_tokens": 33409, "cost": 0.101163, "total_cost": 0.260952}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087665}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087672}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 33621, "completion_tokens": 136, "total_tokens": 33757, "cost": 0.10290300000000001, "total_cost": 0.36385500000000004}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087680}
+{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087686}
+{"event": "command_undo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087690}
+{"event": "command_drop", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087696}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087709}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087709}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 23664, "completion_tokens": 155, "total_tokens": 23819, "cost": 0.073317, "total_cost": 0.437172}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738087716}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738088542}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738088542}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089194}
+{"event": "repo", "properties": {"num_files": 431}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089196}
+{"event": "cli session", "properties": {"main_model": "openai/REDACTED", "weak_model": "openai/REDACTED", "editor_model": "openai/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089196}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089197}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089211}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089211}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089214}
+{"event": "repo", "properties": {"num_files": 431}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089215}
+{"event": "cli session", "properties": {"main_model": "openai/REDACTED", "weak_model": "openai/REDACTED", "editor_model": "openai/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089216}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089217}
+{"event": "message_send", "properties": {"main_model": "openai/REDACTED", "weak_model": "openai/REDACTED", "editor_model": "openai/REDACTED", "edit_format": "whole", "prompt_tokens": 1856, "completion_tokens": 24, "total_tokens": 1880, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089220}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089436}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738089436}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738090466}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738090466}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738090466}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738090771}
+{"event": "repo", "properties": {"num_files": 431}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738090774}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738090774}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738090775}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738090779}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738090779}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 7885, "completion_tokens": 195, "total_tokens": 8080, "cost": 0.02658, "total_cost": 0.02658}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738090788}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738090934}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738090934}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091601}
+{"event": "repo", "properties": {"num_files": 432}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091603}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091603}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091607}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091622}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 8693, "completion_tokens": 271, "total_tokens": 8964, "cost": 0.030144, "total_cost": 0.030144}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091632}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091683}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091683}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091693}
+{"event": "repo", "properties": {"num_files": 432}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091695}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091695}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091722}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 9158, "completion_tokens": 158, "total_tokens": 9316, "cost": 0.029844000000000002, "total_cost": 0.029844000000000002}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091729}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091766}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738091766}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099194}
+{"event": "repo", "properties": {"num_files": 432}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099197}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099197}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099244}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099244}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099244}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 16949, "completion_tokens": 281, "total_tokens": 17230, "cost": 0.055062, "total_cost": 0.055062}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099253}
+{"event": "command_ask", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099341}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099341}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "ask", "prompt_tokens": 15010, "completion_tokens": 311, "total_tokens": 15321, "cost": 0.049695, "total_cost": 0.104757}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099353}
+{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099414}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099442}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099442}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 16959, "completion_tokens": 152, "total_tokens": 17111, "cost": 0.053156999999999996, "total_cost": 0.157914}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099449}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099474}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 17160, "completion_tokens": 292, "total_tokens": 17452, "cost": 0.05586, "total_cost": 0.213774}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099498}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099820}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099849}
+{"event": "repo", "properties": {"num_files": 432}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099852}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099852}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099876}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099876}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099876}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099876}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099876}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 12221, "completion_tokens": 246, "total_tokens": 12467, "cost": 0.040353, "total_cost": 0.254127}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099884}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 16521, "completion_tokens": 235, "total_tokens": 16756, "cost": 0.053088, "total_cost": 0.053088}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099888}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099901}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 17244, "completion_tokens": 170, "total_tokens": 17414, "cost": 0.054282, "total_cost": 0.10737}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099907}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099913}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099913}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099917}
+{"event": "repo", "properties": {"num_files": 432}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099919}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099919}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099952}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738099952}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100124}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100124}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100124}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 11609, "completion_tokens": 177, "total_tokens": 11786, "cost": 0.037482, "total_cost": 0.037482}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100131}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100621}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100623}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100623}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100642}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100645}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100647}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100647}
+{"event": "message_send", "properties": {"main_model": "fireworks_ai/REDACTED", "weak_model": "fireworks_ai/accounts/fireworks/models/deepseek-v3", "editor_model": "fireworks_ai/accounts/fireworks/models/deepseek-v3", "edit_format": "diff", "prompt_tokens": 2344, "completion_tokens": 269, "total_tokens": 2613, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100669}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100669}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100679}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100681}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100681}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100686}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100711}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100712}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100712}
+{"event": "message_send", "properties": {"main_model": "fireworks_ai/REDACTED", "weak_model": "fireworks_ai/accounts/fireworks/models/deepseek-v3", "editor_model": "fireworks_ai/accounts/fireworks/models/deepseek-v3", "edit_format": "diff", "prompt_tokens": 2344, "completion_tokens": 236, "total_tokens": 2580, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100726}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100726}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100750}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100751}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100751}
+{"event": "message_send", "properties": {"main_model": "fireworks_ai/REDACTED", "weak_model": "fireworks_ai/accounts/fireworks/models/deepseek-v3", "editor_model": "fireworks_ai/accounts/fireworks/models/deepseek-v3", "edit_format": "diff", "prompt_tokens": 2344, "completion_tokens": 224, "total_tokens": 2568, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100763}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100763}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100796}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100798}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100798}
+{"event": "message_send_exception", "properties": {"exception": "No active exception to reraise"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100802}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100812}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100814}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100814}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 9981, "completion_tokens": 90, "total_tokens": 10071, "cost": 0.031293, "total_cost": 0.031293}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100819}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100819}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100840}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100842}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100842}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 9993, "completion_tokens": 78, "total_tokens": 10071, "cost": 0.031149000000000003, "total_cost": 0.031149000000000003}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100848}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100848}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100888}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100890}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100890}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 9993, "completion_tokens": 78, "total_tokens": 10071, "cost": 0.031149000000000003, "total_cost": 0.031149000000000003}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100895}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100895}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100907}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100909}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100909}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 10022, "completion_tokens": 54, "total_tokens": 10076, "cost": 0.010291999999999999, "total_cost": 0.010291999999999999}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100913}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100913}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100931}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100933}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100933}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 9978, "completion_tokens": 31, "total_tokens": 10009, "cost": 0.010133, "total_cost": 0.010133}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100937}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100937}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100960}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100962}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100962}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-haiku-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-haiku-20241022", "edit_format": "diff", "prompt_tokens": 10008, "completion_tokens": 31, "total_tokens": 10039, "cost": 0.010163, "total_cost": 0.010163}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100967}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100967}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100972}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100974}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100974}
+{"event": "message_send", "properties": {"main_model": "fireworks_ai/REDACTED", "weak_model": "fireworks_ai/accounts/fireworks/models/deepseek-v3", "editor_model": "fireworks_ai/accounts/fireworks/models/deepseek-v3", "edit_format": "diff", "prompt_tokens": 2344, "completion_tokens": 238, "total_tokens": 2582, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100988}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100988}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100998}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100999}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738100999}
+{"event": "message_send", "properties": {"main_model": "fireworks_ai/REDACTED", "weak_model": "fireworks_ai/accounts/fireworks/models/deepseek-v3", "editor_model": "fireworks_ai/accounts/fireworks/models/deepseek-v3", "edit_format": "diff", "prompt_tokens": 2344, "completion_tokens": 334, "total_tokens": 2678, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738101021}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738101021}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738101074}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738101076}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738101076}
+{"event": "message_send", "properties": {"main_model": "fireworks_ai/REDACTED", "weak_model": "fireworks_ai/accounts/fireworks/models/deepseek-v3", "editor_model": "fireworks_ai/accounts/fireworks/models/deepseek-v3", "edit_format": "diff", "prompt_tokens": 2344, "completion_tokens": 311, "total_tokens": 2655, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738101101}
+{"event": "exit", "properties": {"reason": "Completed --message"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738101101}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738102536}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738102536}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738102552}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738102554}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738102562}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738115955}
+{"event": "model warning", "properties": {"main_model": "groq/REDACTED", "weak_model": "groq/REDACTED", "editor_model": "groq/REDACTED"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738115957}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738115959}
+{"event": "cli session", "properties": {"main_model": "groq/REDACTED", "weak_model": "groq/REDACTED", "editor_model": "groq/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738115959}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738115960}
+{"event": "message_send", "properties": {"main_model": "groq/REDACTED", "weak_model": "groq/REDACTED", "editor_model": "groq/REDACTED", "edit_format": "whole", "prompt_tokens": 1928, "completion_tokens": 534, "total_tokens": 2462, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738115963}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738115964}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738115964}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738116064}
+{"event": "model warning", "properties": {"main_model": "groq/REDACTED", "weak_model": "groq/llama-3.3-70b-versatile", "editor_model": "groq/llama-3.3-70b-versatile"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738116066}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738116068}
+{"event": "cli session", "properties": {"main_model": "groq/REDACTED", "weak_model": "groq/llama-3.3-70b-versatile", "editor_model": "groq/llama-3.3-70b-versatile", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738116068}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738116073}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117530}
+{"event": "model warning", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117533}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117540}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117542}
+{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117542}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117542}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117561}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117563}
+{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117563}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117565}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117622}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117720}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117722}
+{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117723}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117724}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117753}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117754}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117756}
+{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117757}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117759}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117815}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117817}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117819}
+{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117819}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117820}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117840}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117840}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117852}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117853}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117853}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117855}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117861}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117862}
+{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117862}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117862}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117883}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117884}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117886}
+{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117886}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117887}
+{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117907}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117924}
+{"event": "command_chat-mode", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117926}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117931}
+{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 514, "completion_tokens": 85, "total_tokens": 599, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117943}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117951}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117951}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117956}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117958}
+{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117958}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117964}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117975}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117981}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117983}
+{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117983}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117984}
+{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 84, "completion_tokens": 101, "total_tokens": 185, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738117995}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118005}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118006}
+{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118023}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118028}
+{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 516, "completion_tokens": 52, "total_tokens": 568, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118033}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118048}
+{"event": "command_clear", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118052}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118054}
+{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 13988, "completion_tokens": 40, "total_tokens": 14028, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118079}
+{"event": "exit", "properties": {"reason": "Control-C"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118109}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118191}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118193}
+{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118193}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118217}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118217}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118237}
+{"event": "no-repo", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118239}
+{"event": "cli session", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "whole"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118239}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118241}
+{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 79, "completion_tokens": 9, "total_tokens": 88, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118250}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118261}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118263}
+{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 524, "completion_tokens": 65, "total_tokens": 589, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118280}
+{"event": "command_tokens", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118285}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118296}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118297}
+{"event": "message_send", "properties": {"main_model": "ollama/REDACTED", "weak_model": "ollama/REDACTED", "editor_model": "ollama/REDACTED", "edit_format": "ask", "prompt_tokens": 6458, "completion_tokens": 126, "total_tokens": 6584, "cost": 0, "total_cost": 0.0}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118366}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118390}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118390}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118663}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118665}
+{"event": "exit", "properties": {"reason": "Completed lint/test/commit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118674}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118899}
+{"event": "gui session", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118899}
+{"event": "exit", "properties": {"reason": "GUI session ended"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738118899}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119546}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119548}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119548}
+{"event": "command_add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119552}
+{"event": "command_editor", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119579}
+{"event": "command_read-only", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119655}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119659}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 9456, "completion_tokens": 415, "total_tokens": 9871, "cost": 0.034593, "total_cost": 0.034593}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119671}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119727}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119727}
+{"event": "launched", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119940}
+{"event": "repo", "properties": {"num_files": 433}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119940}
+{"event": "cli session", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119940}
+{"event": "ai-comments file-add", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119942}
+{"event": "ai-comments execute", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119942}
+{"event": "message_send_starting", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119942}
+{"event": "message_send", "properties": {"main_model": "claude-3-5-sonnet-20241022", "weak_model": "claude-3-5-haiku-20241022", "editor_model": "claude-3-5-sonnet-20241022", "edit_format": "diff", "prompt_tokens": 9471, "completion_tokens": 333, "total_tokens": 9804, "cost": 0.033408, "total_cost": 0.033408}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738119952}
+{"event": "command_exit", "properties": {}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738120000}
+{"event": "exit", "properties": {"reason": "/exit"}, "user_id": "c42c4e6b-f054-44d7-ae1f-6726cc41da88", "time": 1738120000}
diff --git a/aider/website/assets/sample.aider.conf.yml b/aider/website/assets/sample.aider.conf.yml
index 0afb5f6b6..fa85acda5 100644
--- a/aider/website/assets/sample.aider.conf.yml
+++ b/aider/website/assets/sample.aider.conf.yml
@@ -410,6 +410,9 @@
## Specify the encoding for input and output (default: utf-8)
#encoding: utf-8
+## Line endings to use when writing files (default: platform)
+#line-endings: platform
+
## Specify the config file (default: search for .aider.conf.yml in git root, cwd or home directory)
#config: xxx
diff --git a/aider/website/assets/sample.env b/aider/website/assets/sample.env
index 0c481afb4..cfb19aa6d 100644
--- a/aider/website/assets/sample.env
+++ b/aider/website/assets/sample.env
@@ -381,6 +381,9 @@
## Specify the encoding for input and output (default: utf-8)
#AIDER_ENCODING=utf-8
+## Line endings to use when writing files (default: platform)
+#AIDER_LINE_ENDINGS=platform
+
## Specify the .env file to load (default: .env in git root)
#AIDER_ENV_FILE=.env
diff --git a/aider/website/docs/config/adv-model-settings.md b/aider/website/docs/config/adv-model-settings.md
index 589a9d72a..4cdbf345e 100644
--- a/aider/website/docs/config/adv-model-settings.md
+++ b/aider/website/docs/config/adv-model-settings.md
@@ -103,7 +103,41 @@ For example:
These settings will be merged with any model-specific settings, with the
`aider/extra_params` settings taking precedence for any direct conflicts.
-### Example model settings
+### Controlling o1 reasoning effort
+
+You need this chunk of yaml:
+
+```
+ extra_params:
+ extra_body:
+ reasoning_effort: high
+```
+
+This is a full entry for o1 with that setting, obtained by finding the default
+entry in the list below and adding the above `extra_params` entry:
+
+```
+- name: o1
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ send_undo_reply: false
+ lazy: false
+ reminder: user
+ examples_as_sys_msg: false
+ cache_control: false
+ caches_by_default: false
+ use_system_prompt: true
+ use_temperature: false
+ streaming: false
+ editor_model_name: gpt-4o
+ editor_edit_format: editor-diff
+ extra_params:
+ extra_body:
+ reasoning_effort: high
+```
+
+### Default model settings
Below are all the pre-configured model settings to give a sense for the settings which are supported.
@@ -111,6 +145,10 @@ You can also look at the `ModelSettings` class in
[models.py](https://github.com/Aider-AI/aider/blob/main/aider/models.py)
file for more details about all of the model setting that aider supports.
+The first entry shows all the settings, with their default values.
+For a real model,
+you just need to include whichever fields that you want to override the defaults.
+
```yaml
-- cache_control: false
- caches_by_default: false
+- name: (default values)
edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gpt-3.5-turbo
- reminder: sys
- send_undo_reply: false
- streaming: true
+ weak_model_name: null
use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
+ send_undo_reply: false
lazy: false
- name: gpt-3.5-turbo-0125
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gpt-3.5-turbo-1106
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gpt-3.5-turbo-0613
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gpt-3.5-turbo-16k-0613
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: udiff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: true
- name: gpt-4-turbo-2024-04-09
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: udiff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: true
- name: gpt-4-turbo
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: true
- name: openai/gpt-4o
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: true
- name: openai/gpt-4o-2024-08-06
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: true
- name: gpt-4o-2024-08-06
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: true
- name: gpt-4o-2024-11-20
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: true
- name: openai/gpt-4o-2024-11-20
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: true
- name: gpt-4o
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: true
- name: gpt-4o-mini
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: true
- name: openai/gpt-4o-mini
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: openai/gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: udiff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: true
- extra_params: null
- lazy: true
- name: gpt-4-0125-preview
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: udiff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: true
- name: gpt-4-1106-preview
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gpt-4-vision-preview
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: true
- extra_params: null
- lazy: false
- name: gpt-4-0314
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gpt-4-0613
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gpt-4-32k-0613
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: claude-3-opus-20240229
reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: claude-3-5-haiku-20241022
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
examples_as_sys_msg: false
extra_params: null
- lazy: false
- name: openrouter/anthropic/claude-3-opus
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
+ cache_control: false
+ caches_by_default: false
use_system_prompt: true
use_temperature: true
- weak_model_name: openrouter/anthropic/claude-3-5-haiku
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
+ streaming: true
editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: claude-3-sonnet-20240229
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: claude-3-5-haiku-20241022
-- cache_control: true
- caches_by_default: false
+ editor_edit_format: null
+ remove_reasoning: null
+
+- name: anthropic/claude-3-5-haiku-20241022
edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: claude-3-5-sonnet-20240620
+ weak_model_name: anthropic/claude-3-5-haiku-20241022
+ use_repo_map: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ cache_control: true
+
+- name: anthropic/claude-3-5-sonnet-20240620
+ edit_format: diff
+ weak_model_name: anthropic/claude-3-5-haiku-20241022
+ use_repo_map: true
examples_as_sys_msg: true
extra_params:
extra_headers:
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
max_tokens: 8192
- lazy: false
- name: claude-3-5-sonnet-20240620
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: claude-3-5-haiku-20241022
-- cache_control: true
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
+ cache_control: true
editor_model_name: anthropic/claude-3-5-sonnet-20240620
+ editor_edit_format: editor-diff
+
+- name: anthropic/claude-3-5-sonnet-20241022
+ edit_format: diff
+ weak_model_name: anthropic/claude-3-5-haiku-20241022
+ use_repo_map: true
examples_as_sys_msg: true
extra_params:
extra_headers:
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
max_tokens: 8192
- lazy: false
- name: anthropic/claude-3-5-sonnet-20240620
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: anthropic/claude-3-5-haiku-20241022
-- cache_control: true
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
+ cache_control: true
editor_model_name: anthropic/claude-3-5-sonnet-20241022
- examples_as_sys_msg: true
- extra_params:
- extra_headers:
- anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
- max_tokens: 8192
- lazy: false
- name: anthropic/claude-3-5-sonnet-20241022
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
+ editor_edit_format: editor-diff
+
+- name: anthropic/claude-3-5-sonnet-latest
+ edit_format: diff
weak_model_name: anthropic/claude-3-5-haiku-20241022
-- cache_control: true
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0
+ use_repo_map: true
examples_as_sys_msg: true
extra_params:
extra_headers:
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
max_tokens: 8192
- lazy: false
- name: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0
-- cache_control: true
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
+ cache_control: true
editor_model_name: anthropic/claude-3-5-sonnet-20241022
- examples_as_sys_msg: true
- extra_params:
- extra_headers:
- anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
- max_tokens: 8192
- lazy: false
- name: anthropic/claude-3-5-sonnet-latest
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: anthropic/claude-3-5-haiku-20241022
-- cache_control: true
- caches_by_default: false
- edit_format: diff
editor_edit_format: editor-diff
- editor_model_name: claude-3-5-sonnet-20241022
- examples_as_sys_msg: true
- extra_params:
- extra_headers:
- anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
- max_tokens: 8192
- lazy: false
- name: claude-3-5-sonnet-20241022
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: claude-3-5-haiku-20241022
-- cache_control: true
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: true
- extra_params:
- extra_headers:
- anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
- lazy: false
- name: anthropic/claude-3-haiku-20240307
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
+
+- name: anthropic/claude-3-haiku-20240307
weak_model_name: anthropic/claude-3-haiku-20240307
-- cache_control: true
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params:
- extra_headers:
- anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
- lazy: false
- name: anthropic/claude-3-5-haiku-20241022
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: anthropic/claude-3-5-haiku-20241022
-- cache_control: true
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params:
- extra_headers:
- anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
- lazy: false
- name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0
-- cache_control: true
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
examples_as_sys_msg: true
extra_params:
extra_headers:
anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
- lazy: false
- name: claude-3-5-haiku-20241022
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: claude-3-5-haiku-20241022
-- cache_control: false
- caches_by_default: false
+ cache_control: true
+
+- name: azure/o1
edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
+ weak_model_name: azure/gpt-4o-mini
+ use_repo_map: true
+ use_temperature: false
+ streaming: false
+ editor_model_name: azure/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: azure/o1-mini
+ weak_model_name: azure/gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ editor_model_name: azure/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: azure/o1-preview
+ edit_format: diff
+ weak_model_name: azure/gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ editor_model_name: azure/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0
+ edit_format: diff
+ weak_model_name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0
+ use_repo_map: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ cache_control: true
+
+- name: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0
+ edit_format: diff
+ weak_model_name: bedrock/anthropic.claude-3-5-haiku-20241022-v1:0
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0
+ editor_edit_format: editor-diff
+
+- name: claude-3-5-haiku-20241022
+ edit_format: diff
+ weak_model_name: claude-3-5-haiku-20241022
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ cache_control: true
+
+- name: claude-3-5-sonnet-20240620
+ edit_format: diff
+ weak_model_name: claude-3-5-haiku-20241022
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: claude-3-5-sonnet-20240620
+ editor_edit_format: editor-diff
+
+- name: claude-3-5-sonnet-20241022
+ edit_format: diff
+ weak_model_name: claude-3-5-haiku-20241022
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: claude-3-5-sonnet-20241022
+ editor_edit_format: editor-diff
+
+- name: claude-3-haiku-20240307
+ weak_model_name: claude-3-haiku-20240307
+ examples_as_sys_msg: true
+ extra_params:
+ extra_headers:
+ anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
+ cache_control: true
+
+- name: claude-3-opus-20240229
+ edit_format: diff
+ weak_model_name: claude-3-5-haiku-20241022
+ use_repo_map: true
+
+- name: claude-3-sonnet-20240229
+ weak_model_name: claude-3-5-haiku-20241022
+
+- name: command-r-08-2024
+ weak_model_name: command-r-08-2024
+ use_repo_map: true
+
+- name: command-r-plus
+ weak_model_name: command-r-plus
+ use_repo_map: true
+
+- name: command-r-plus-08-2024
+ weak_model_name: command-r-plus-08-2024
+ use_repo_map: true
+
+- name: deepseek-chat
+ edit_format: diff
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+
+- name: deepseek-coder
+ edit_format: diff
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ caches_by_default: true
+
+- name: deepseek/deepseek-chat
+ edit_format: diff
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ caches_by_default: true
+
+- name: deepseek/deepseek-coder
+ edit_format: diff
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ caches_by_default: true
+
+- name: deepseek/deepseek-reasoner
+ edit_format: diff
+ weak_model_name: deepseek/deepseek-chat
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ caches_by_default: true
+ use_temperature: false
+ editor_model_name: deepseek/deepseek-chat
+ editor_edit_format: editor-diff
+
+- name: gemini/gemini-1.5-flash-002
+
+- name: gemini/gemini-1.5-flash-exp-0827
+
+- name: gemini/gemini-1.5-pro
+ edit_format: diff-fenced
+ use_repo_map: true
+
+- name: gemini/gemini-1.5-pro-002
+ edit_format: diff
+ use_repo_map: true
+
+- name: gemini/gemini-1.5-pro-exp-0827
+ edit_format: diff-fenced
+ use_repo_map: true
+
+- name: gemini/gemini-1.5-pro-latest
+ edit_format: diff-fenced
+ use_repo_map: true
+
+- name: gemini/gemini-2.0-flash-exp
+ edit_format: diff
+ use_repo_map: true
+
+- name: gemini/gemini-exp-1114
+ edit_format: diff
+ use_repo_map: true
+
+- name: gemini/gemini-exp-1121
+ edit_format: diff
+ use_repo_map: true
+
+- name: gemini/gemini-exp-1206
+ edit_format: diff
+ use_repo_map: true
+
+- name: gpt-3.5-turbo
+ weak_model_name: gpt-4o-mini
+ reminder: sys
+
+- name: gpt-3.5-turbo-0125
+ weak_model_name: gpt-4o-mini
+ reminder: sys
+
+- name: gpt-3.5-turbo-0613
+ weak_model_name: gpt-4o-mini
+ reminder: sys
+
+- name: gpt-3.5-turbo-1106
+ weak_model_name: gpt-4o-mini
+ reminder: sys
+
+- name: gpt-3.5-turbo-16k-0613
+ weak_model_name: gpt-4o-mini
+ reminder: sys
+
+- name: gpt-4-0125-preview
+ edit_format: udiff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: gpt-4-0314
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: gpt-4-0613
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ reminder: sys
+
+- name: gpt-4-1106-preview
+ edit_format: udiff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+
+- name: gpt-4-32k-0613
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ reminder: sys
+
+- name: gpt-4-turbo
+ edit_format: udiff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+
+- name: gpt-4-turbo-2024-04-09
+ edit_format: udiff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+
+- name: gpt-4-vision-preview
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ reminder: sys
+
+- name: gpt-4o
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+ editor_edit_format: editor-diff
+
+- name: gpt-4o-2024-08-06
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: gpt-4o-2024-11-20
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: gpt-4o-mini
+ weak_model_name: gpt-4o-mini
+ lazy: true
+ reminder: sys
+
+- name: groq/llama3-70b-8192
+ edit_format: diff
+ weak_model_name: groq/llama3-8b-8192
+ examples_as_sys_msg: true
+
+- name: o1
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ use_temperature: false
+ streaming: false
+ editor_model_name: gpt-4o
+ editor_edit_format: editor-diff
+
+- name: o1-mini
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ editor_model_name: gpt-4o
+ editor_edit_format: editor-diff
+
+- name: o1-preview
+ edit_format: architect
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ editor_model_name: gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openai/gpt-4o
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+ editor_edit_format: editor-diff
+
+- name: openai/gpt-4o-2024-08-06
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: openai/gpt-4o-2024-11-20
+ edit_format: diff
+ weak_model_name: gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: openai/gpt-4o-mini
+ weak_model_name: openai/gpt-4o-mini
+ lazy: true
+ reminder: sys
+
+- name: openai/o1
+ edit_format: diff
+ weak_model_name: openai/gpt-4o-mini
+ use_repo_map: true
+ use_temperature: false
+ streaming: false
+ editor_model_name: openai/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openai/o1-mini
+ weak_model_name: openai/gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ editor_model_name: openai/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openai/o1-preview
+ edit_format: diff
+ weak_model_name: openai/gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ editor_model_name: openai/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openrouter/anthropic/claude-3-opus
+ edit_format: diff
+ weak_model_name: openrouter/anthropic/claude-3-5-haiku
+ use_repo_map: true
+
+- name: openrouter/anthropic/claude-3.5-sonnet
+ edit_format: diff
+ weak_model_name: openrouter/anthropic/claude-3-5-haiku
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: openrouter/anthropic/claude-3.5-sonnet
+ editor_edit_format: editor-diff
+
+- name: openrouter/anthropic/claude-3.5-sonnet:beta
+ edit_format: diff
+ weak_model_name: openrouter/anthropic/claude-3-5-haiku:beta
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ cache_control: true
+ editor_model_name: openrouter/anthropic/claude-3.5-sonnet:beta
+ editor_edit_format: editor-diff
+
+- name: openrouter/deepseek/deepseek-chat
+ edit_format: diff
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: openrouter/deepseek/deepseek-coder
+ edit_format: diff
+ use_repo_map: true
+ reminder: sys
+ examples_as_sys_msg: true
+
+- name: openrouter/deepseek/deepseek-r1
+ edit_format: diff
+ weak_model_name: openrouter/deepseek/deepseek-chat
+ use_repo_map: true
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ caches_by_default: true
+ use_temperature: false
+ editor_model_name: openrouter/deepseek/deepseek-chat
+ editor_edit_format: editor-diff
+
+- name: openrouter/meta-llama/llama-3-70b-instruct
+ edit_format: diff
+ weak_model_name: openrouter/meta-llama/llama-3-70b-instruct
+ examples_as_sys_msg: true
+
+- name: openrouter/openai/gpt-4o
+ edit_format: diff
+ weak_model_name: openrouter/openai/gpt-4o-mini
+ use_repo_map: true
+ lazy: true
+ reminder: sys
+ examples_as_sys_msg: true
+ editor_edit_format: editor-diff
+
+- name: openrouter/openai/o1
+ edit_format: diff
+ weak_model_name: openrouter/openai/gpt-4o-mini
+ use_repo_map: true
+ use_temperature: false
+ streaming: false
+ editor_model_name: openrouter/openai/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openrouter/openai/o1-mini
+ weak_model_name: openrouter/openai/gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ streaming: false
+ editor_model_name: openrouter/openai/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openrouter/openai/o1-preview
+ edit_format: diff
+ weak_model_name: openrouter/openai/gpt-4o-mini
+ use_repo_map: true
+ use_system_prompt: false
+ use_temperature: false
+ streaming: false
+ editor_model_name: openrouter/openai/gpt-4o
+ editor_edit_format: editor-diff
+
+- name: openrouter/qwen/qwen-2.5-coder-32b-instruct
+ edit_format: diff
+ weak_model_name: openrouter/qwen/qwen-2.5-coder-32b-instruct
+ use_repo_map: true
+ editor_model_name: openrouter/qwen/qwen-2.5-coder-32b-instruct
+ editor_edit_format: editor-diff
+
+- name: vertex_ai/claude-3-5-haiku@20241022
+ edit_format: diff
+ weak_model_name: vertex_ai/claude-3-5-haiku@20241022
+ use_repo_map: true
extra_params:
max_tokens: 4096
- lazy: false
- name: vertex_ai/claude-3-5-haiku@20241022
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
+
+- name: vertex_ai/claude-3-5-sonnet-v2@20241022
+ edit_format: diff
weak_model_name: vertex_ai/claude-3-5-haiku@20241022
-- cache_control: true
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: true
- extra_params:
- extra_headers:
- anthropic-beta: prompt-caching-2024-07-31,pdfs-2024-09-25
- lazy: false
- name: claude-3-haiku-20240307
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: claude-3-haiku-20240307
-- cache_control: true
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: openrouter/anthropic/claude-3.5-sonnet
+ use_repo_map: true
examples_as_sys_msg: true
extra_params:
max_tokens: 8192
- lazy: false
- name: openrouter/anthropic/claude-3.5-sonnet
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: openrouter/anthropic/claude-3-5-haiku
-- cache_control: true
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: openrouter/anthropic/claude-3.5-sonnet:beta
- examples_as_sys_msg: true
- extra_params:
- max_tokens: 8192
- lazy: false
- name: openrouter/anthropic/claude-3.5-sonnet:beta
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: openrouter/anthropic/claude-3-5-haiku:beta
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: vertex_ai/claude-3-5-sonnet@20240620
- examples_as_sys_msg: true
- extra_params:
- max_tokens: 8192
- lazy: false
- name: vertex_ai/claude-3-5-sonnet@20240620
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: vertex_ai/claude-3-5-haiku@20241022
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
editor_model_name: vertex_ai/claude-3-5-sonnet-v2@20241022
- examples_as_sys_msg: true
- extra_params:
- max_tokens: 8192
- lazy: false
- name: vertex_ai/claude-3-5-sonnet-v2@20241022
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
+ editor_edit_format: editor-diff
+
+- name: vertex_ai/claude-3-5-sonnet@20240620
+ edit_format: diff
weak_model_name: vertex_ai/claude-3-5-haiku@20241022
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: vertex_ai/claude-3-opus@20240229
- reminder: user
- send_undo_reply: false
- streaming: true
use_repo_map: true
- use_system_prompt: true
- use_temperature: true
+ examples_as_sys_msg: true
+ extra_params:
+ max_tokens: 8192
+ editor_model_name: vertex_ai/claude-3-5-sonnet@20240620
+ editor_edit_format: editor-diff
+
+- name: vertex_ai/claude-3-opus@20240229
+ edit_format: diff
weak_model_name: vertex_ai/claude-3-5-haiku@20241022
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: vertex_ai/claude-3-sonnet@20240229
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
+ use_repo_map: true
+
+- name: vertex_ai/claude-3-sonnet@20240229
weak_model_name: vertex_ai/claude-3-5-haiku@20241022
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: command-r-plus
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: command-r-plus
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: command-r-08-2024
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: command-r-08-2024
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: command-r-plus-08-2024
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: command-r-plus-08-2024
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: true
- extra_params: null
- lazy: false
- name: groq/llama3-70b-8192
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: groq/llama3-8b-8192
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: true
- extra_params: null
- lazy: false
- name: openrouter/meta-llama/llama-3-70b-instruct
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: openrouter/meta-llama/llama-3-70b-instruct
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gemini/gemini-1.5-pro-002
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gemini/gemini-1.5-flash-002
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
+
+- name: vertex_ai/gemini-pro-experimental
edit_format: diff-fenced
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gemini/gemini-1.5-pro
- reminder: user
- send_undo_reply: false
- streaming: true
use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: diff-fenced
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gemini/gemini-1.5-pro-latest
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: diff-fenced
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gemini/gemini-1.5-pro-exp-0827
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gemini/gemini-exp-1206
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gemini/gemini-exp-1114
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gemini/gemini-exp-1121
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: diff-fenced
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: vertex_ai/gemini-pro-experimental
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gemini/gemini-1.5-flash-exp-0827
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: false
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: gemini/gemini-2.0-flash-exp
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: true
- extra_params:
- max_tokens: 8192
- lazy: false
- name: deepseek/deepseek-chat
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: true
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: true
- extra_params:
- max_tokens: 8192
- lazy: false
- name: deepseek/deepseek-coder
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: true
- extra_params:
- max_tokens: 8192
- lazy: false
- name: deepseek-chat
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: true
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: true
- extra_params:
- max_tokens: 8192
- lazy: false
- name: deepseek-coder
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: true
- extra_params: null
- lazy: false
- name: openrouter/deepseek/deepseek-coder
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: null
- editor_model_name: null
- examples_as_sys_msg: true
- extra_params: null
- lazy: false
- name: openrouter/deepseek/deepseek-chat
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: null
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: null
- examples_as_sys_msg: false
- extra_params: null
- lazy: true
- name: openrouter/openai/gpt-4o
- reminder: sys
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: openrouter/openai/gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: editor-diff
- editor_model_name: openai/gpt-4o
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: openai/o1-mini
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: false
- use_temperature: false
- weak_model_name: openai/gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: editor-diff
- editor_model_name: azure/gpt-4o
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: azure/o1-mini
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: false
- use_temperature: false
- weak_model_name: azure/gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: editor-diff
- editor_model_name: gpt-4o
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: o1-mini
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: false
- use_temperature: false
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: openai/gpt-4o
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: openai/o1-preview
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: false
- use_temperature: false
- weak_model_name: openai/gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: azure/gpt-4o
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: azure/o1-preview
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: false
- use_temperature: false
- weak_model_name: azure/gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: architect
- editor_edit_format: editor-diff
- editor_model_name: gpt-4o
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: o1-preview
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: false
- use_temperature: false
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: whole
- editor_edit_format: editor-diff
- editor_model_name: openrouter/openai/gpt-4o
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: openrouter/openai/o1-mini
- reminder: user
- send_undo_reply: false
- streaming: false
- use_repo_map: true
- use_system_prompt: false
- use_temperature: false
- weak_model_name: openrouter/openai/gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: openrouter/openai/gpt-4o
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: openrouter/openai/o1-preview
- reminder: user
- send_undo_reply: false
- streaming: false
- use_repo_map: true
- use_system_prompt: false
- use_temperature: false
- weak_model_name: openrouter/openai/gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: openrouter/openai/gpt-4o
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: openrouter/openai/o1
- reminder: user
- send_undo_reply: false
- streaming: false
- use_repo_map: true
- use_system_prompt: true
- use_temperature: false
- weak_model_name: openrouter/openai/gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: openai/gpt-4o
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: openai/o1
- reminder: user
- send_undo_reply: false
- streaming: false
- use_repo_map: true
- use_system_prompt: true
- use_temperature: false
- weak_model_name: openai/gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: gpt-4o
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: o1
- reminder: user
- send_undo_reply: false
- streaming: false
- use_repo_map: true
- use_system_prompt: true
- use_temperature: false
- weak_model_name: gpt-4o-mini
-- cache_control: false
- caches_by_default: false
- edit_format: diff
- editor_edit_format: editor-diff
- editor_model_name: openrouter/qwen/qwen-2.5-coder-32b-instruct
- examples_as_sys_msg: false
- extra_params: null
- lazy: false
- name: openrouter/qwen/qwen-2.5-coder-32b-instruct
- reminder: user
- send_undo_reply: false
- streaming: true
- use_repo_map: true
- use_system_prompt: true
- use_temperature: true
- weak_model_name: openrouter/qwen/qwen-2.5-coder-32b-instruct
```
diff --git a/aider/website/docs/config/aider_conf.md b/aider/website/docs/config/aider_conf.md
index 9b9e2521c..ce36e54cf 100644
--- a/aider/website/docs/config/aider_conf.md
+++ b/aider/website/docs/config/aider_conf.md
@@ -7,13 +7,15 @@ description: How to configure aider with a yaml config file.
# YAML config file
Most of aider's options can be set in an `.aider.conf.yml` file.
-Aider will look for a this file in these locations and
-load whichever is found first.
+Aider will look for a this file in these locations:
-- As specified with the `--config ` parameter.
-- The current directory.
-- The root of your git repo.
- Your home directory.
+- The root of your git repo.
+- The current directory.
+
+If the files above exist, they will be loaded in that order. Files loaded last will take priority.
+
+You can also specify the `--config ` parameter, which will only load the one config file.
{% include keys.md %}
@@ -462,6 +464,9 @@ cog.outl("```")
## Specify the encoding for input and output (default: utf-8)
#encoding: utf-8
+## Line endings to use when writing files (default: platform)
+#line-endings: platform
+
## Specify the config file (default: search for .aider.conf.yml in git root, cwd or home directory)
#config: xxx
diff --git a/aider/website/docs/config/dotenv.md b/aider/website/docs/config/dotenv.md
index 8cf3928fe..d7bf7503d 100644
--- a/aider/website/docs/config/dotenv.md
+++ b/aider/website/docs/config/dotenv.md
@@ -421,6 +421,9 @@ cog.outl("```")
## Specify the encoding for input and output (default: utf-8)
#AIDER_ENCODING=utf-8
+## Line endings to use when writing files (default: platform)
+#AIDER_LINE_ENDINGS=platform
+
## Specify the .env file to load (default: .env in git root)
#AIDER_ENV_FILE=.env
diff --git a/aider/website/docs/config/model-aliases.md b/aider/website/docs/config/model-aliases.md
index b805dce57..ae32c80b1 100644
--- a/aider/website/docs/config/model-aliases.md
+++ b/aider/website/docs/config/model-aliases.md
@@ -59,6 +59,7 @@ for alias, model in sorted(MODEL_ALIASES.items()):
- `flash`: gemini/gemini-2.0-flash-exp
- `haiku`: claude-3-5-haiku-20241022
- `opus`: claude-3-opus-20240229
+- `r1`: deepseek/deepseek-reasoner
- `sonnet`: claude-3-5-sonnet-20241022
diff --git a/aider/website/docs/config/options.md b/aider/website/docs/config/options.md
index 4660be72d..fc672186b 100644
--- a/aider/website/docs/config/options.md
+++ b/aider/website/docs/config/options.md
@@ -73,7 +73,7 @@ usage: aider [-h] [--model] [--opus] [--sonnet] [--haiku] [--4]
[--show-prompts] [--voice-format] [--voice-language]
[--voice-input-device] [--file] [--read] [--vim]
[--chat-language] [--yes-always] [-v] [--load]
- [--encoding] [-c] [--env-file]
+ [--encoding] [--line-endings] [-c] [--env-file]
[--suggest-shell-commands | --no-suggest-shell-commands]
[--fancy-input | --no-fancy-input]
[--multiline | --no-multiline]
@@ -705,6 +705,11 @@ Specify the encoding for input and output (default: utf-8)
Default: utf-8
Environment variable: `AIDER_ENCODING`
+### `--line-endings VALUE`
+Line endings to use when writing files (default: platform)
+Default: platform
+Environment variable: `AIDER_LINE_ENDINGS`
+
### `--config CONFIG_FILE`
Specify the config file (default: search for .aider.conf.yml in git root, cwd or home directory)
Aliases:
diff --git a/aider/website/docs/faq.md b/aider/website/docs/faq.md
index a2922ff0c..9d13a6486 100644
--- a/aider/website/docs/faq.md
+++ b/aider/website/docs/faq.md
@@ -141,6 +141,18 @@ When starting a fresh aider session, you can include recent git history in the c
Remember, the chat history already includes recent changes made during the current session, so this tip is most useful when starting a new aider session and you want to provide context about recent work.
+You can also use aider to review PR branches:
+
+```
+/run git diff one-branch..another-branch
+
+...
+
+Add 6.9k tokens of command output to the chat? (Y)es/(N)o [Yes]: Yes
+
+/ask Are there any problems with the way this change works with the FooBar class?
+```
+
{: .tip }
The `/git` command will not work for this purpose, as its output is not included in the chat.
@@ -237,10 +249,21 @@ tr:hover { background-color: #f5f5f5; }
Model Name | Total Tokens | Percent |
-deepseek/deepseek-chat | 1,258,436 | 86.2% |
-claude-3-5-sonnet-20241022 | 178,352 | 12.2% |
-o1 | 22,748 | 1.6% |
+claude-3-5-sonnet-20241022 | 984,849 | 50.4% |
+deepseek/deepseek-chat | 588,766 | 30.1% |
+deepseek/REDACTED | 258,010 | 13.2% |
+deepseek/deepseek-reasoner | 40,597 | 2.1% |
+claude-3-5-haiku-20241022 | 30,124 | 1.5% |
+ollama/REDACTED | 22,641 | 1.2% |
+fireworks_ai/REDACTED | 15,676 | 0.8% |
+openrouter/deepseek/deepseek-chat | 9,995 | 0.5% |
+groq/REDACTED | 2,462 | 0.1% |
+openai/REDACTED | 1,880 | 0.1% |
+
+{: .note :}
+Some models show as REDACTED, because they are new or unpopular models.
+Aider's analytics only records the names of "well known" LLMs.
## How are the "aider wrote xx% of code" stats computed?
diff --git a/aider/website/docs/languages.md b/aider/website/docs/languages.md
index ac91ab537..d9e8f842c 100644
--- a/aider/website/docs/languages.md
+++ b/aider/website/docs/languages.md
@@ -81,7 +81,7 @@ cog.out(get_supported_languages_md())
| jsdoc | .jsdoc | | ✓ |
| json | .json | | ✓ |
| julia | .jl | | ✓ |
-| kotlin | .kt | | ✓ |
+| kotlin | .kt | ✓ | ✓ |
| lua | .lua | | ✓ |
| make | .mk | | ✓ |
| objc | .m | | ✓ |
diff --git a/aider/website/docs/leaderboards/edit.md b/aider/website/docs/leaderboards/edit.md
index aa23e4a4e..01a5dc57a 100644
--- a/aider/website/docs/leaderboards/edit.md
+++ b/aider/website/docs/leaderboards/edit.md
@@ -113,9 +113,8 @@ import subprocess
import datetime
files = [
- 'aider/website/docs/leaderboards/index.md',
+ 'aider/website/docs/leaderboards/edit.md',
'aider/website/_data/edit_leaderboard.yml',
- 'aider/website/_data/refactor_leaderboard.yml'
]
def get_last_modified_date(file):
@@ -129,6 +128,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.')}")
]]]-->
-December 16, 2024.
+January 16, 2025.
diff --git a/aider/website/docs/leaderboards/index.md b/aider/website/docs/leaderboards/index.md
index 7e50e9a2e..d36309009 100644
--- a/aider/website/docs/leaderboards/index.md
+++ b/aider/website/docs/leaderboards/index.md
@@ -19,13 +19,6 @@ While [aider can connect to almost any LLM](/docs/llms.html),
it works best with models that score well on the benchmarks.
-{: .note :}
-The
-[original aider code editing leaderboard](edit.html)
-has been replaced by this
-new, much more challenging
-[polyglot leaderboard](https://aider.chat/2024/12/21/polyglot.html).
-
## Polyglot leaderboard
[Aider's polyglot benchmark](/docs/benchmarks.html#the-benchmark)
@@ -107,8 +100,7 @@ import datetime
files = [
'aider/website/docs/leaderboards/index.md',
- 'aider/website/_data/edit_leaderboard.yml',
- 'aider/website/_data/refactor_leaderboard.yml'
+ 'aider/website/_data/polyglot_leaderboard.yml',
]
def get_last_modified_date(file):
@@ -122,6 +114,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.')}")
]]]-->
-December 26, 2024.
+January 28, 2025.
diff --git a/aider/website/docs/leaderboards/refactor.md b/aider/website/docs/leaderboards/refactor.md
index f78941428..96a7bea2b 100644
--- a/aider/website/docs/leaderboards/refactor.md
+++ b/aider/website/docs/leaderboards/refactor.md
@@ -50,3 +50,29 @@ Therefore, results are available for fewer models.
+
+By Paul Gauthier,
+last updated
+
+January 16, 2025.
+
+
diff --git a/aider/website/docs/llms.md b/aider/website/docs/llms.md
index 939bbef87..1e30795f8 100644
--- a/aider/website/docs/llms.md
+++ b/aider/website/docs/llms.md
@@ -19,7 +19,7 @@ Aider works best with these models, which are skilled at editing code:
- [GPT-4o](/docs/llms/openai.html)
- [Claude 3.5 Sonnet](/docs/llms/anthropic.html)
- [Claude 3 Opus](/docs/llms/anthropic.html)
-- [DeepSeek Coder V2](/docs/llms/deepseek.html)
+- [DeepSeek V3](/docs/llms/deepseek.html)
## Free models
diff --git a/aider/website/docs/llms/deepseek.md b/aider/website/docs/llms/deepseek.md
index 361758427..c49c49c7e 100644
--- a/aider/website/docs/llms/deepseek.md
+++ b/aider/website/docs/llms/deepseek.md
@@ -6,7 +6,8 @@ nav_order: 500
# DeepSeek
Aider can connect to the DeepSeek.com API.
-The DeepSeek Coder V2 model has a top score on aider's code editing benchmark.
+To work with DeepSeek's models, you need to set the `DEEPSEEK_API_KEY` environment variable with your [DeepSeek API key](https://platform.deepseek.com/api_keys).
+The DeepSeek Chat V3 model has a top score on aider's code editing benchmark.
```
python -m pip install -U aider-chat
@@ -14,7 +15,7 @@ python -m pip install -U aider-chat
export DEEPSEEK_API_KEY= # Mac/Linux
setx DEEPSEEK_API_KEY # Windows, restart shell after setx
-# Use DeepSeek Coder V2
+# Use DeepSeek Chat v3
aider --deepseek
```
diff --git a/aider/website/docs/llms/ollama.md b/aider/website/docs/llms/ollama.md
index 3e42648ed..5207656f5 100644
--- a/aider/website/docs/llms/ollama.md
+++ b/aider/website/docs/llms/ollama.md
@@ -45,7 +45,19 @@ setx OLLAMA_API_KEY # Windows, restart shell after setx
[Ollama uses a 2k context window by default](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-specify-the-context-window-size),
which is very small for working with aider.
+Unlike most other LLM servers, Ollama does not throw an error if you submit
+a request that exceeds the context window.
+Instead, it just silently truncates the request by discarding the "oldest" messages
+in the chat to make it fit within the context window.
+
+So if your context window is too small, you won't get an explicit error.
+The biggest symptom will be that aider says it can't see (some of) the files
+you added to the chat.
+That's because ollama is silently discarding them because they exceed the context window.
+
Aider sets Ollama's context window to 8k by default.
+Larger context windows will allow you to work with larger amounts of code,
+but will use memory and increase latency.
If you would like
a larger context window
you can use a
@@ -58,11 +70,3 @@ like this:
num_ctx: 8192
```
-Unlike most other LLM servers, Ollama does not throw an error if you submit
-a request that exceeds the context window.
-Instead, it just silently truncates the request by discarding the "oldest" messages
-in the chat to make it fit within the context window.
-So if your context window is too small, you won't get an error.
-Aider will probably just fail to work well and experience
-a lot of
-[file editing problems](https://aider.chat/docs/troubleshooting/edit-errors.html).
diff --git a/aider/website/docs/llms/openrouter.md b/aider/website/docs/llms/openrouter.md
index 20888a33c..9d561bf1c 100644
--- a/aider/website/docs/llms/openrouter.md
+++ b/aider/website/docs/llms/openrouter.md
@@ -39,5 +39,39 @@ If you get errors, check your
Be sure to "enable providers that may train on inputs"
to allow use of all models.
+## Controlling provider selection
+
+OpenRouter often has multiple providers serving each model.
+You can control which OpenRouter providers are used for your requests in two ways:
+
+1. By "ignoring" certain providers in your
+[OpenRouter account settings](https://openrouter.ai/settings/preferences).
+This disables those named providers across all the models that you access via OpenRouter.
+
+2. By configuring "provider routing" in a `.aider.model.settings.yml` file.
+
+Place that file in your home directory or the root if your git project, with
+entries like this:
+
+```yaml
+- name: openrouter/anthropic/claude-3.5-sonnet
+ extra_params:
+ extra_body:
+ provider:
+ # Only use these providers, in this order
+ order: ["Anthropic", "Together"]
+ # Don't fall back to other providers
+ allow_fallbacks: false
+ # Skip providers that may train on inputs
+ data_collection: "deny"
+ # Only use providers supporting all parameters
+ require_parameters: true
+```
+
+See [OpenRouter's provider routing docs](https://openrouter.ai/docs/provider-routing) for full details on these settings.
+
+See [Advanced model settings](https://aider.chat/docs/config/adv-model-settings.html#model-settings)
+for more details about model settings files.
+
diff --git a/aider/website/docs/more/infinite-output.md b/aider/website/docs/more/infinite-output.md
index 06b61c5cd..4e046fbf3 100644
--- a/aider/website/docs/more/infinite-output.md
+++ b/aider/website/docs/more/infinite-output.md
@@ -67,6 +67,8 @@ cog.out(model_list)
- codestral/codestral-latest
- deepseek/deepseek-chat
- deepseek/deepseek-coder
+- deepseek/deepseek-reasoner
+- eu.anthropic.claude-3-5-haiku-20241022-v1:0
- eu.anthropic.claude-3-5-sonnet-20241022-v2:0
- mistral/codestral-2405
- mistral/codestral-latest
@@ -91,6 +93,7 @@ cog.out(model_list)
- mistral/pixtral-large-2411
- mistral/pixtral-large-latest
- openrouter/anthropic/claude-3.5-sonnet
+- openrouter/deepseek/deepseek-r1
- us.anthropic.claude-3-5-haiku-20241022-v1:0
- us.anthropic.claude-3-5-sonnet-20241022-v2:0
- vertex_ai/claude-3-5-haiku
diff --git a/aider/website/docs/troubleshooting/edit-errors.md b/aider/website/docs/troubleshooting/edit-errors.md
index 7aab589b1..a6de214e3 100644
--- a/aider/website/docs/troubleshooting/edit-errors.md
+++ b/aider/website/docs/troubleshooting/edit-errors.md
@@ -24,6 +24,8 @@ In these cases, here are some things you might try.
Many LLMs now have very large context windows,
but filling them with irrelevant code or conversation
can confuse the model.
+Above about 25k tokens of context, most models start to become distracted and become less likely
+to conform to their system prompt.
- Don't add too many files to the chat, *just* add the files you think need to be edited.
Aider also sends the LLM a [map of your entire git repo](https://aider.chat/docs/repomap.html), so other relevant code will be included automatically.
@@ -33,8 +35,8 @@ Aider also sends the LLM a [map of your entire git repo](https://aider.chat/docs
## Use a more capable model
-If possible try using GPT-4o, Claude 3.5 Sonnet or Claude 3 Opus,
-as they are the strongest and most capable models.
+If possible try using GPT-4o, Claude 3.5 Sonnet, DeepSeek V3 or DeepSeek R1.
+They are the strongest and most capable models.
Weaker models
are more prone to
@@ -62,6 +64,12 @@ Aider v0.50.2-dev
Models: claude-3-5-sonnet-20240620 with ♾️ diff edit format
```
+## Try architect mode
+
+Run aider with `--architect` or `/chat-mode architect` to enable [architect mode](../usage/modes.md#architect-mode-and-the-editor-model).
+This mode first proposes changes, then uses a separate model to handle the file edits.
+This two-step process often produces more reliable edits, especially with models that have trouble
+following edit format instructions.
## More help
diff --git a/aider/website/docs/usage/caching.md b/aider/website/docs/usage/caching.md
index f79bc6d9c..3173a3e83 100644
--- a/aider/website/docs/usage/caching.md
+++ b/aider/website/docs/usage/caching.md
@@ -4,14 +4,13 @@ highlight_image: /assets/prompt-caching.jpg
parent: Usage
nav_order: 750
description: Aider supports prompt caching for cost savings and faster coding.
-
---
# Prompt caching
Aider supports prompt caching for cost savings and faster coding.
Currently Anthropic provides caching for Sonnet and Haiku,
-and DeepSeek provides caching for Coder.
+and DeepSeek provides caching for Chat.
Aider organizes the chat history to try and cache:
@@ -48,4 +47,3 @@ every 5 minutes to keep the cache warm.
Aider will ping up to `N` times over a period of `N*5` minutes
after each message you send.
-
diff --git a/aider/website/docs/usage/commands.md b/aider/website/docs/usage/commands.md
index 9d2e13a81..b73d82ac8 100644
--- a/aider/website/docs/usage/commands.md
+++ b/aider/website/docs/usage/commands.md
@@ -22,7 +22,7 @@ cog.out(get_help_md())
|Command|Description|
|:------|:----------|
| **/add** | Add files to the chat so aider can edit them or review them in detail |
-| **/architect** | Enter architect mode to discuss high-level design and architecture. If no prompt provided, switches to architect mode. |
+| **/architect** | Enter architect/editor mode using 2 different models. If no prompt provided, switches to architect/editor mode. |
| **/ask** | Ask questions about the code base without editing any files. If no prompt provided, switches to ask mode. |
| **/chat-mode** | Switch to a new chat mode |
| **/clear** | Clear the chat history |
diff --git a/aider/website/docs/usage/not-code.md b/aider/website/docs/usage/not-code.md
new file mode 100644
index 000000000..6a0bd8158
--- /dev/null
+++ b/aider/website/docs/usage/not-code.md
@@ -0,0 +1,179 @@
+---
+parent: Usage
+nav_order: 901
+description: Use aider to edit configuration files, documentation, and other text-based formats.
+---
+
+
+# Editing config & text files
+
+Aider isn't just for code, it can be very helpful when editing
+almost any text file.
+You can use aider to make changes to your shell & ssh settings,
+Dockerfiles
+or pretty much any configuration or documentation file.
+
+Here are some practical examples of modifying common config/text files:
+
+## Shell Configuration
+
+
+$ aider .bashrc
+
+Added .bashrc to the chat.
+
+
+#### Add an alias 'll' that lists all files, with all details in human readable format. And update PATH to include uv installed tools.
+
+```
++ alias ll='ls -alh'
++ export PATH="$PATH:$HOME/.local/bin:$PATH"
+```
+
+
+## SSH Configurations
+
+
+$ aider ~/.ssh/config
+
+Added config to the chat.
+
+#### Create a Host entry 'my-server' using bastion.example.com as JumpHost
+
+```
++ Host my-server
++ HostName 192.168.1.100
++ User deploy
++ Port 2222
++ IdentityFile ~/.ssh/deploy_key
++ ProxyJump bastion.example.com
+```
+
+
+## Docker Setup
+
+
+$ aider Dockerfile docker-compose.yml
+
+Added Dockerfile and docker-compose.yml to the chat.
+
+#### Set non-root user and enable healthchecks
+
+```
++ USER appuser
++ HEALTHCHECK --interval=30s --timeout=3s \
++ CMD curl -f http://localhost:8000/health || exit 1
+```
+
+#### Expose port 5432 and add volume for postgres data
+
+```
+ services:
+ postgres:
+ image: postgres:15
++ ports:
++ - "5432:5432"
++ volumes:
++ - pgdata:/var/lib/postgresql/data
+```
+
+
+## Git Configuration
+
+
+$ aider .gitconfig
+
+Added .gitconfig to the chat.
+
+#### Set default push behavior to current branch and enable color UI
+
+```
++ [push]
++ default = current
++ [color]
++ ui = auto
+```
+
+
+## System Configuration
+
+$ aider /etc/hosts # May need sudo
+
+Added hosts to the chat.
+
+#### Block tracking domains by pointing them to 127.0.0.1
+
+```
++ 127.0.0.1 ads.example.com
++ 127.0.0.1 track.analytics.co
+```
+
+
+
+## Editor Configs
+
+$ aider .vimrc
+
+Added .vimrc to the chat.
+
+#### Enable line numbers and set 4-space tabs for Python
+
+```
++ set number
++ autocmd FileType python set tabstop=4 shiftwidth=4 expandtab
+```
+
+
+## VSCode Configuration
+
+$ aider settings.json
+
+Added settings.json to the chat.
+
+#### Enable auto-format on save and set default formatter
+
+```
++ "editor.formatOnSave": true,
++ "editor.defaultFormatter": "esbenp.prettier-vscode"
+```
+
+
+## Markdown Documentation
+
+$ aider README.md
+
+Added README.md to the chat.
+
+
+#### Add installation section with brew and pip options
+
+```
++ ## Installation
++ ```
++ # Homebrew
++ brew install cool-app-10k
++
++ # PyPI
++ pipx install cool-app-10k
++ ```
+```
+
+
+## XML Configuration
+
+$ aider pom.xml
+
+Added pom.xml to the chat.
+#### Add JUnit 5 dependency with test scope
+
+```
++
++ org.junit.jupiter
++ junit-jupiter-api
++ 5.9.2
++ test
++
+```
+
+
+
diff --git a/aider/website/index.md b/aider/website/index.md
index 33ea4c25a..e9b80f235 100644
--- a/aider/website/index.md
+++ b/aider/website/index.md
@@ -79,11 +79,14 @@ aider-install
# Change directory into your code base
cd /to/your/project
+# Work with DeepSeek on your code
+aider --model deepseek --api-key deepseek=your-key-goes-here
+
# Work with Claude 3.5 Sonnet on your code
-aider --model sonnet --anthropic-api-key your-key-goes-here
+aider --model sonnet --api-key anthropic=your-key-goes-here
# Work with GPT-4o on your code
-aider --model gpt-4o --openai-api-key your-key-goes-here
+aider --model gpt-4o --api-key openai=your-key-goes-here
```
@@ -99,7 +102,7 @@ for more details.
- Ask for changes:
- Add new features or test cases.
- Describe a bug.
- - Paste in an error message or or GitHub issue URL.
+ - Paste in an error message or GitHub issue URL.
- Refactor code.
- Update docs.
- Aider will edit your files to complete your request.
diff --git a/benchmark/benchmark.py b/benchmark/benchmark.py
index 1d27ab58f..f8267761a 100755
--- a/benchmark/benchmark.py
+++ b/benchmark/benchmark.py
@@ -16,6 +16,7 @@ from types import SimpleNamespace
from typing import List, Optional
import git
+import importlib_resources
import lox
import pandas as pd
import prompts
@@ -202,6 +203,9 @@ def main(
num_ctx: Optional[int] = typer.Option(
None, "--num-ctx", help="Override model context window size"
),
+ read_model_settings: str = typer.Option(
+ None, "--read-model-settings", help="Load aider model settings from YAML file"
+ ),
exercises_dir: str = typer.Option(
EXERCISES_DIR_DEFAULT, "--exercises-dir", help="Directory with exercise files"
),
@@ -310,6 +314,22 @@ def main(
test_dnames = sorted(str(d.relative_to(original_dname)) for d in exercise_dirs)
+ resource_metadata = importlib_resources.files("aider.resources").joinpath("model-metadata.json")
+ model_metadata_files_loaded = models.register_litellm_models([resource_metadata])
+ dump(model_metadata_files_loaded)
+
+ if read_model_settings:
+ try:
+ files_loaded = models.register_models([read_model_settings])
+ if verbose:
+ if files_loaded:
+ print(f"Loaded model settings from: {files_loaded[0]}")
+ else:
+ print(f"No model settings loaded from: {read_model_settings}")
+ except Exception as e:
+ print(f"Error loading model settings: {e}")
+ return 1
+
if keywords:
keywords = keywords.split(",")
test_dnames = [dn for dn in test_dnames for keyword in keywords if keyword in dn]
@@ -642,6 +662,7 @@ def run_test_real(
editor_edit_format,
num_ctx=None,
sleep=0,
+ read_model_settings=None,
):
if not os.path.isdir(testdir):
print("Not a dir:", testdir)
@@ -717,17 +738,6 @@ def run_test_real(
else:
print(f"Warning: Solution file not found: {src}")
- # Copy all test files
- for file_path in test_files:
- src = testdir / Path(file_path)
- if src.exists():
- original_fname = original_dname / testdir.name / file_path
- if original_fname.exists():
- os.makedirs(src.parent, exist_ok=True)
- shutil.copy(original_fname, src)
- else:
- print(f"Warning: Test file not found: {src}")
-
file_list = " ".join(fname.name for fname in fnames)
instructions = ""
@@ -758,6 +768,8 @@ def run_test_real(
editor_edit_format=editor_edit_format,
)
+ dump(main_model.max_chat_history_tokens)
+
if num_ctx:
if not main_model.extra_params:
main_model.extra_params = {}
@@ -785,6 +797,7 @@ def run_test_real(
dump(coder.ignore_mentions)
coder.show_announcements()
+ coder.get_file_mentions = lambda x: set() # No loading of any other files
timeouts = 0
@@ -796,6 +809,7 @@ def run_test_real(
test_outcomes = []
for i in range(tries):
start = time.time()
+
if no_aider:
pass
elif replay:
@@ -925,15 +939,6 @@ def run_test_real(
def run_unit_tests(original_dname, testdir, history_fname, test_files):
timeout = 60 * 3
- # Remove @Disabled annotations from Java test files
- for file_path in test_files:
- if file_path.endswith(".java"):
- test_file = testdir / file_path
- if test_file.exists():
- content = test_file.read_text()
- content = re.sub(r"@Disabled\([^)]*\)\s*\n", "", content)
- test_file.write_text(content)
-
# Map of file extensions to test commands
TEST_COMMANDS = {
".py": ["pytest"],
@@ -965,6 +970,15 @@ def run_unit_tests(original_dname, testdir, history_fname, test_files):
os.makedirs(dst.parent, exist_ok=True)
shutil.copy(src, dst)
+ # Remove @Disabled annotations from Java test files
+ for file_path in test_files:
+ if file_path.endswith(".java"):
+ test_file = testdir / file_path
+ if test_file.exists():
+ content = test_file.read_text()
+ content = re.sub(r"@Disabled\([^)]*\)\s*\n", "", content)
+ test_file.write_text(content)
+
print(" ".join(command))
result = subprocess.run(
diff --git a/benchmark/rsync.sh b/benchmark/rsync.sh
index 0de23c9d0..3960f2cd7 100755
--- a/benchmark/rsync.sh
+++ b/benchmark/rsync.sh
@@ -19,15 +19,27 @@ git -C "$REPO_ROOT" ls-files --exclude-standard --others --ignored --directory >
# Create remote directory if needed
ssh "$DEST" "mkdir -p ~/aider"
-# Sync the repository
-rsync -avz --delete \
- --exclude-from="$EXCLUDE_FILE" \
- "$REPO_ROOT/" \
- "$DEST:~/aider/"
+sync_repo() {
+ # Sync the repository
+ rsync -avz --delete \
+ --exclude-from="$EXCLUDE_FILE" \
+ "$REPO_ROOT/" \
+ "$DEST:~/aider/" || sleep 0.1
+
+ rsync -av .env .gitignore .aider.model.settings.yml "$DEST:~/aider/." || sleep 0.1
-rsync -a .env .gitignore "$DEST:~/aider/."
+ echo Done syncing, waiting.
+}
+
+sync_repo
-rsync -a ~/dotfiles/screenrc "$DEST:.screenrc"
+while true; do
+ fswatch -o $REPO_ROOT | while read ; do
+ sync_repo
+ done
+done
+
# Clean up
rm "$EXCLUDE_FILE"
+
diff --git a/requirements.txt b/requirements.txt
index 1053368fc..40d97ad0b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,18 +6,18 @@
#
aiohappyeyeballs==2.4.4
# via aiohttp
-aiohttp==3.11.10
+aiohttp==3.11.11
# via litellm
-aiosignal==1.3.1
+aiosignal==1.3.2
# via aiohttp
annotated-types==0.7.0
# via pydantic
-anyio==4.7.0
+anyio==4.8.0
# via
# httpx
# openai
# watchfiles
-attrs==24.2.0
+attrs==25.1.0
# via
# aiohttp
# jsonschema
@@ -28,7 +28,7 @@ backoff==2.2.1
# posthog
beautifulsoup4==4.12.3
# via -r requirements/requirements.in
-certifi==2024.8.30
+certifi==2024.12.14
# via
# httpcore
# httpx
@@ -37,9 +37,9 @@ cffi==1.17.1
# via
# sounddevice
# soundfile
-charset-normalizer==3.4.0
+charset-normalizer==3.4.1
# via requests
-click==8.1.7
+click==8.1.8
# via litellm
configargparse==1.7
# via -r requirements/requirements.in
@@ -49,7 +49,7 @@ diskcache==5.6.3
# via -r requirements/requirements.in
distro==1.9.0
# via openai
-filelock==3.16.1
+filelock==3.17.0
# via huggingface-hub
flake8==7.1.1
# via -r requirements/requirements.in
@@ -57,11 +57,11 @@ frozenlist==1.5.0
# via
# aiohttp
# aiosignal
-fsspec==2024.10.0
+fsspec==2024.12.0
# via huggingface-hub
-gitdb==4.0.11
+gitdb==4.0.12
# via gitpython
-gitpython==3.1.43
+gitpython==3.1.44
# via -r requirements/requirements.in
grep-ast==0.4.1
# via -r requirements/requirements.in
@@ -73,7 +73,7 @@ httpx==0.27.2
# via
# litellm
# openai
-huggingface-hub==0.26.5
+huggingface-hub==0.28.0
# via tokenizers
idna==3.10
# via
@@ -85,11 +85,11 @@ importlib-metadata==7.2.1
# via
# -r requirements/requirements.in
# litellm
-importlib-resources==6.4.5
+importlib-resources==6.5.2
# via -r requirements/requirements.in
-jinja2==3.1.4
+jinja2==3.1.5
# via litellm
-jiter==0.8.0
+jiter==0.8.2
# via openai
json5==0.10.0
# via -r requirements/requirements.in
@@ -99,7 +99,7 @@ jsonschema==4.23.0
# litellm
jsonschema-specifications==2024.10.1
# via jsonschema
-litellm==1.53.9
+litellm==1.59.8
# via -r requirements/requirements.in
markdown-it-py==3.0.0
# via rich
@@ -123,7 +123,8 @@ numpy==1.26.4
# via
# -r requirements/requirements.in
# scipy
-openai==1.57.0
+ # soundfile
+openai==1.60.2
# via litellm
packaging==24.2
# via
@@ -137,15 +138,15 @@ pexpect==4.9.0
# via -r requirements/requirements.in
pillow==10.4.0
# via -r requirements/requirements.in
-posthog==3.7.4
+posthog==3.11.0
# via -r requirements/requirements.in
-prompt-toolkit==3.0.48
+prompt-toolkit==3.0.50
# via -r requirements/requirements.in
propcache==0.2.1
# via
# aiohttp
# yarl
-psutil==6.1.0
+psutil==6.1.1
# via -r requirements/requirements.in
ptyprocess==0.7.0
# via pexpect
@@ -153,19 +154,19 @@ pycodestyle==2.12.1
# via flake8
pycparser==2.22
# via cffi
-pydantic==2.10.3
+pydantic==2.10.6
# via
# litellm
# openai
-pydantic-core==2.27.1
+pydantic-core==2.27.2
# via pydantic
pydub==0.25.1
# via -r requirements/requirements.in
pyflakes==3.2.0
# via flake8
-pygments==2.18.0
+pygments==2.19.1
# via rich
-pypandoc==1.14
+pypandoc==1.15
# via -r requirements/requirements.in
pyperclip==1.9.0
# via -r requirements/requirements.in
@@ -177,7 +178,7 @@ pyyaml==6.0.2
# via
# -r requirements/requirements.in
# huggingface-hub
-referencing==0.35.1
+referencing==0.36.2
# via
# jsonschema
# jsonschema-specifications
@@ -186,7 +187,6 @@ regex==2024.11.6
requests==2.32.3
# via
# huggingface-hub
- # litellm
# mixpanel
# posthog
# tiktoken
@@ -203,7 +203,7 @@ six==1.17.0
# mixpanel
# posthog
# python-dateutil
-smmap==5.0.1
+smmap==5.0.2
# via gitdb
sniffio==1.3.1
# via
@@ -212,7 +212,7 @@ sniffio==1.3.1
# openai
sounddevice==0.5.1
# via -r requirements/requirements.in
-soundfile==0.12.1
+soundfile==0.13.1
# via -r requirements/requirements.in
soupsieve==2.6
# via beautifulsoup4
@@ -239,11 +239,12 @@ typing-extensions==4.12.2
# openai
# pydantic
# pydantic-core
-urllib3==2.2.3
+ # referencing
+urllib3==2.3.0
# via
# mixpanel
# requests
-watchfiles==1.0.0
+watchfiles==1.0.4
# via -r requirements/requirements.in
wcwidth==0.2.13
# via prompt-toolkit
@@ -253,5 +254,5 @@ zipp==3.21.0
# via importlib-metadata
# The following packages are considered to be unsafe in a requirements file:
-pip==24.3.1
+pip==25.0
# via -r requirements/requirements.in
diff --git a/requirements/requirements-browser.txt b/requirements/requirements-browser.txt
index 7b2b9c46c..c99d6525a 100644
--- a/requirements/requirements-browser.txt
+++ b/requirements/requirements-browser.txt
@@ -6,7 +6,7 @@
#
altair==5.5.0
# via streamlit
-attrs==24.2.0
+attrs==25.1.0
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -15,35 +15,35 @@ attrs==24.2.0
# referencing
blinker==1.9.0
# via streamlit
-cachetools==5.5.0
+cachetools==5.5.1
# via streamlit
-certifi==2024.8.30
+certifi==2024.12.14
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# -c requirements/requirements-dev.txt
# -c requirements/requirements-help.txt
# requests
-charset-normalizer==3.4.0
+charset-normalizer==3.4.1
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# -c requirements/requirements-dev.txt
# -c requirements/requirements-help.txt
# requests
-click==8.1.7
+click==8.1.8
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# -c requirements/requirements-dev.txt
# -c requirements/requirements-help.txt
# streamlit
-gitdb==4.0.11
+gitdb==4.0.12
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# gitpython
-gitpython==3.1.43
+gitpython==3.1.44
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -55,7 +55,7 @@ idna==3.10
# -c requirements/requirements-dev.txt
# -c requirements/requirements-help.txt
# requests
-jinja2==3.1.4
+jinja2==3.1.5
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -92,7 +92,7 @@ mdurl==0.1.2
# -c requirements.txt
# -c requirements/requirements-dev.txt
# markdown-it-py
-narwhals==1.16.0
+narwhals==1.24.0
# via altair
numpy==1.26.4
# via
@@ -122,13 +122,13 @@ pillow==10.4.0
# -c requirements/requirements-dev.txt
# -c requirements/requirements-help.txt
# streamlit
-protobuf==5.29.1
+protobuf==5.29.3
# via streamlit
-pyarrow==18.1.0
+pyarrow==19.0.0
# via streamlit
pydeck==0.9.1
# via streamlit
-pygments==2.18.0
+pygments==2.19.1
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -144,7 +144,7 @@ pytz==2024.2
# via
# -c requirements/requirements-dev.txt
# pandas
-referencing==0.35.1
+referencing==0.36.2
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -175,14 +175,14 @@ six==1.17.0
# -c requirements.txt
# -c requirements/requirements-dev.txt
# python-dateutil
-smmap==5.0.1
+smmap==5.0.2
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# gitdb
-streamlit==1.40.2
+streamlit==1.41.1
# via -r requirements/requirements-browser.in
-tenacity==8.5.0
+tenacity==9.0.0
# via
# -c requirements/requirements-help.txt
# streamlit
@@ -197,12 +197,13 @@ typing-extensions==4.12.2
# -c requirements/requirements-dev.txt
# -c requirements/requirements-help.txt
# altair
+ # referencing
# streamlit
-tzdata==2024.2
+tzdata==2025.1
# via
# -c requirements/requirements-dev.txt
# pandas
-urllib3==2.2.3
+urllib3==2.3.0
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
diff --git a/requirements/requirements-dev.txt b/requirements/requirements-dev.txt
index 566454dd2..311962175 100644
--- a/requirements/requirements-dev.txt
+++ b/requirements/requirements-dev.txt
@@ -10,25 +10,25 @@ babel==2.16.0
# via sphinx
build==1.2.2.post1
# via pip-tools
-certifi==2024.8.30
+certifi==2024.12.14
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# requests
cfgv==3.4.0
# via pre-commit
-charset-normalizer==3.4.0
+charset-normalizer==3.4.1
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# requests
-click==8.1.7
+click==8.1.8
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# pip-tools
# typer
-codespell==2.3.0
+codespell==2.4.0
# via -r requirements/requirements-dev.in
cogapp==3.4.1
# via -r requirements/requirements-dev.in
@@ -46,14 +46,14 @@ docutils==0.21.2
# via
# sphinx
# sphinx-rtd-theme
-filelock==3.16.1
+filelock==3.17.0
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# virtualenv
-fonttools==4.55.2
+fonttools==4.55.7
# via matplotlib
-identify==2.6.3
+identify==2.6.6
# via pre-commit
idna==3.10
# via
@@ -66,12 +66,12 @@ imgcat==0.6.0
# via -r requirements/requirements-dev.in
iniconfig==2.0.0
# via pytest
-jinja2==3.1.4
+jinja2==3.1.5
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# sphinx
-kiwisolver==1.4.7
+kiwisolver==1.4.8
# via matplotlib
lox==0.12.0
# via -r requirements/requirements-dev.in
@@ -85,7 +85,7 @@ markupsafe==3.0.2
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# jinja2
-matplotlib==3.9.3
+matplotlib==3.10.0
# via -r requirements/requirements-dev.in
mdurl==0.1.2
# via
@@ -130,15 +130,15 @@ pox==0.3.5
# via pathos
ppft==1.7.6.9
# via pathos
-pre-commit==4.0.1
+pre-commit==4.1.0
# via -r requirements/requirements-dev.in
-pygments==2.18.0
+pygments==2.19.1
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# rich
# sphinx
-pyparsing==3.2.0
+pyparsing==3.2.1
# via matplotlib
pyproject-hooks==1.2.0
# via
@@ -173,7 +173,7 @@ rich==13.9.4
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# typer
-semver==3.0.2
+semver==3.0.4
# via -r requirements/requirements-dev.in
shellingham==1.5.4
# via typer
@@ -211,23 +211,23 @@ typing-extensions==4.12.2
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# typer
-tzdata==2024.2
+tzdata==2025.1
# via pandas
-urllib3==2.2.3
+urllib3==2.3.0
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# requests
-virtualenv==20.28.0
+virtualenv==20.29.1
# via pre-commit
wheel==0.45.1
# via pip-tools
# The following packages are considered to be unsafe in a requirements file:
-pip==24.3.1
+pip==25.0
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# pip-tools
-setuptools==75.6.0
+setuptools==75.8.0
# via pip-tools
diff --git a/requirements/requirements-help.txt b/requirements/requirements-help.txt
index ddf1ad0b2..bcad47a8e 100644
--- a/requirements/requirements-help.txt
+++ b/requirements/requirements-help.txt
@@ -9,13 +9,13 @@ aiohappyeyeballs==2.4.4
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# aiohttp
-aiohttp==3.11.10
+aiohttp==3.11.11
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# huggingface-hub
# llama-index-core
-aiosignal==1.3.1
+aiosignal==1.3.2
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -25,17 +25,17 @@ annotated-types==0.7.0
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# pydantic
-anyio==4.7.0
+anyio==4.8.0
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# httpx
-attrs==24.2.0
+attrs==25.1.0
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# aiohttp
-certifi==2024.8.30
+certifi==2024.12.14
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -43,13 +43,13 @@ certifi==2024.8.30
# httpcore
# httpx
# requests
-charset-normalizer==3.4.0
+charset-normalizer==3.4.1
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# -c requirements/requirements-dev.txt
# requests
-click==8.1.7
+click==8.1.8
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -57,11 +57,11 @@ click==8.1.7
# nltk
dataclasses-json==0.6.7
# via llama-index-core
-deprecated==1.2.15
+deprecated==1.2.18
# via llama-index-core
dirtyjson==1.0.8
# via llama-index-core
-filelock==3.16.1
+filelock==3.17.0
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -77,7 +77,7 @@ frozenlist==1.5.0
# -c requirements.txt
# aiohttp
# aiosignal
-fsspec==2024.10.0
+fsspec==2024.12.0
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -103,7 +103,7 @@ httpx==0.27.2
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# llama-index-core
-huggingface-hub[inference]==0.26.5
+huggingface-hub[inference]==0.28.0
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -120,7 +120,7 @@ idna==3.10
# httpx
# requests
# yarl
-jinja2==3.1.4
+jinja2==3.1.5
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -130,11 +130,11 @@ joblib==1.4.2
# via
# nltk
# scikit-learn
-llama-index-core==0.12.0
+llama-index-core==0.12.14
# via
# -r requirements/requirements-help.in
# llama-index-embeddings-huggingface
-llama-index-embeddings-huggingface==0.4.0
+llama-index-embeddings-huggingface==0.5.1
# via -r requirements/requirements-help.in
markupsafe==3.0.2
# via
@@ -142,7 +142,7 @@ markupsafe==3.0.2
# -c requirements.txt
# -c requirements/requirements-dev.txt
# jinja2
-marshmallow==3.23.1
+marshmallow==3.26.0
# via dataclasses-json
mpmath==1.3.0
# via sympy
@@ -194,12 +194,12 @@ propcache==0.2.1
# -c requirements.txt
# aiohttp
# yarl
-pydantic==2.10.3
+pydantic==2.10.6
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# llama-index-core
-pydantic-core==2.27.1
+pydantic-core==2.27.2
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
@@ -228,9 +228,9 @@ requests==2.32.3
# llama-index-core
# tiktoken
# transformers
-safetensors==0.4.5
+safetensors==0.5.2
# via transformers
-scikit-learn==1.5.2
+scikit-learn==1.6.1
# via sentence-transformers
scipy==1.13.1
# via
@@ -238,7 +238,7 @@ scipy==1.13.1
# -c requirements.txt
# scikit-learn
# sentence-transformers
-sentence-transformers==3.3.1
+sentence-transformers==3.4.0
# via llama-index-embeddings-huggingface
sniffio==1.3.1
# via
@@ -246,13 +246,13 @@ sniffio==1.3.1
# -c requirements.txt
# anyio
# httpx
-sqlalchemy[asyncio]==2.0.36
+sqlalchemy[asyncio]==2.0.37
# via
# llama-index-core
# sqlalchemy
sympy==1.13.3
# via torch
-tenacity==8.5.0
+tenacity==9.0.0
# via llama-index-core
threadpoolctl==3.5.0
# via scikit-learn
@@ -296,13 +296,13 @@ typing-inspect==0.9.0
# via
# dataclasses-json
# llama-index-core
-urllib3==2.2.3
+urllib3==2.3.0
# via
# -c /Users/gauthier/Projects/aider/requirements.txt
# -c requirements.txt
# -c requirements/requirements-dev.txt
# requests
-wrapt==1.17.0
+wrapt==1.17.2
# via
# deprecated
# llama-index-core
diff --git a/scripts/update-docs.sh b/scripts/update-docs.sh
index fdf4791b3..ecde8ac01 100755
--- a/scripts/update-docs.sh
+++ b/scripts/update-docs.sh
@@ -27,6 +27,8 @@ cog $ARG \
aider/website/docs/config/adv-model-settings.md \
aider/website/docs/config/model-aliases.md \
aider/website/docs/leaderboards/index.md \
+ aider/website/docs/leaderboards/edit.md \
+ aider/website/docs/leaderboards/refactor.md \
aider/website/docs/llms/other.md \
aider/website/docs/more/infinite-output.md \
aider/website/docs/legal/privacy.md
diff --git a/tests/basic/test_coder.py b/tests/basic/test_coder.py
index 88026cfb0..f18ce5515 100644
--- a/tests/basic/test_coder.py
+++ b/tests/basic/test_coder.py
@@ -7,11 +7,12 @@ from unittest.mock import MagicMock, patch
import git
from aider.coders import Coder
-from aider.coders.base_coder import UnknownEditFormat
+from aider.coders.base_coder import FinishReasonLength, UnknownEditFormat
from aider.dump import dump # noqa: F401
from aider.io import InputOutput
from aider.models import Model
from aider.repo import GitRepo
+from aider.sendchat import sanity_check_messages
from aider.utils import GitTemporaryDirectory
@@ -974,6 +975,71 @@ This command will print 'Hello, World!' to the console."""
self.assertIn("Output tokens:", error_message)
self.assertIn("Total tokens:", error_message)
+ def test_keyboard_interrupt_handling(self):
+ with GitTemporaryDirectory():
+ io = InputOutput(yes=True)
+ coder = Coder.create(self.GPT35, "diff", io=io)
+
+ # Simulate keyboard interrupt during message processing
+ def mock_send(*args, **kwargs):
+ coder.partial_response_content = "Partial response"
+ coder.partial_response_function_call = dict()
+ raise KeyboardInterrupt()
+
+ coder.send = mock_send
+
+ # Initial valid state
+ sanity_check_messages(coder.cur_messages)
+
+ # Process message that will trigger interrupt
+ list(coder.send_message("Test message"))
+
+ # Verify messages are still in valid state
+ sanity_check_messages(coder.cur_messages)
+ self.assertEqual(coder.cur_messages[-1]["role"], "assistant")
+
+ def test_token_limit_error_handling(self):
+ with GitTemporaryDirectory():
+ io = InputOutput(yes=True)
+ coder = Coder.create(self.GPT35, "diff", io=io)
+
+ # Simulate token limit error
+ def mock_send(*args, **kwargs):
+ coder.partial_response_content = "Partial response"
+ coder.partial_response_function_call = dict()
+ raise FinishReasonLength()
+
+ coder.send = mock_send
+
+ # Initial valid state
+ sanity_check_messages(coder.cur_messages)
+
+ # Process message that hits token limit
+ list(coder.send_message("Long message"))
+
+ # Verify messages are still in valid state
+ sanity_check_messages(coder.cur_messages)
+ self.assertEqual(coder.cur_messages[-1]["role"], "assistant")
+
+ def test_message_sanity_after_partial_response(self):
+ with GitTemporaryDirectory():
+ io = InputOutput(yes=True)
+ coder = Coder.create(self.GPT35, "diff", io=io)
+
+ # Simulate partial response then interrupt
+ def mock_send(*args, **kwargs):
+ coder.partial_response_content = "Partial response"
+ coder.partial_response_function_call = dict()
+ raise KeyboardInterrupt()
+
+ coder.send = mock_send
+
+ list(coder.send_message("Test"))
+
+ # Verify message structure remains valid
+ sanity_check_messages(coder.cur_messages)
+ self.assertEqual(coder.cur_messages[-1]["role"], "assistant")
+
if __name__ == "__main__":
unittest.main()
diff --git a/tests/basic/test_io.py b/tests/basic/test_io.py
index d6762df93..3aadaff3d 100644
--- a/tests/basic/test_io.py
+++ b/tests/basic/test_io.py
@@ -12,6 +12,23 @@ from aider.utils import ChdirTemporaryDirectory
class TestInputOutput(unittest.TestCase):
+ def test_line_endings_validation(self):
+ # Test valid line endings
+ for ending in ["platform", "lf", "crlf"]:
+ io = InputOutput(line_endings=ending)
+ self.assertEqual(
+ io.newline, None if ending == "platform" else "\n" if ending == "lf" else "\r\n"
+ )
+
+ # Test invalid line endings
+ with self.assertRaises(ValueError) as cm:
+ io = InputOutput(line_endings="invalid")
+ self.assertIn("Invalid line_endings value: invalid", str(cm.exception))
+ # Check each valid option is in the error message
+ self.assertIn("platform", str(cm.exception))
+ self.assertIn("crlf", str(cm.exception))
+ self.assertIn("lf", str(cm.exception))
+
def test_no_color_environment_variable(self):
with patch.dict(os.environ, {"NO_COLOR": "1"}):
io = InputOutput(fancy_input=False)
diff --git a/tests/basic/test_repomap.py b/tests/basic/test_repomap.py
index 6f47cee09..a007ba3f0 100644
--- a/tests/basic/test_repomap.py
+++ b/tests/basic/test_repomap.py
@@ -290,6 +290,7 @@ class TestRepoMapAllLanguages(unittest.TestCase):
"elixir": ("ex", "Greeter"),
"java": ("java", "Greeting"),
"javascript": ("js", "Person"),
+ "kotlin": ("kt", "Greeting"),
"ocaml": ("ml", "Greeter"),
"php": ("php", "greet"),
"python": ("py", "Person"),
diff --git a/tests/basic/test_sendchat.py b/tests/basic/test_sendchat.py
index fb2b6fb5a..6fe0d807e 100644
--- a/tests/basic/test_sendchat.py
+++ b/tests/basic/test_sendchat.py
@@ -93,3 +93,80 @@ class TestSendChat(unittest.TestCase):
assert result is None
# Should only print the error message
assert mock_print.call_count == 1
+
+ def test_ensure_alternating_roles_empty(self):
+ from aider.sendchat import ensure_alternating_roles
+
+ messages = []
+ result = ensure_alternating_roles(messages)
+ assert result == []
+
+ def test_ensure_alternating_roles_single_message(self):
+ from aider.sendchat import ensure_alternating_roles
+
+ messages = [{"role": "user", "content": "Hello"}]
+ result = ensure_alternating_roles(messages)
+ assert result == messages
+
+ def test_ensure_alternating_roles_already_alternating(self):
+ from aider.sendchat import ensure_alternating_roles
+
+ messages = [
+ {"role": "user", "content": "Hello"},
+ {"role": "assistant", "content": "Hi there"},
+ {"role": "user", "content": "How are you?"},
+ ]
+ result = ensure_alternating_roles(messages)
+ assert result == messages
+
+ def test_ensure_alternating_roles_consecutive_user(self):
+ from aider.sendchat import ensure_alternating_roles
+
+ messages = [
+ {"role": "user", "content": "Hello"},
+ {"role": "user", "content": "Are you there?"},
+ ]
+ expected = [
+ {"role": "user", "content": "Hello"},
+ {"role": "assistant", "content": ""},
+ {"role": "user", "content": "Are you there?"},
+ ]
+ result = ensure_alternating_roles(messages)
+ assert result == expected
+
+ def test_ensure_alternating_roles_consecutive_assistant(self):
+ from aider.sendchat import ensure_alternating_roles
+
+ messages = [
+ {"role": "assistant", "content": "Hi there"},
+ {"role": "assistant", "content": "How can I help?"},
+ ]
+ expected = [
+ {"role": "assistant", "content": "Hi there"},
+ {"role": "user", "content": ""},
+ {"role": "assistant", "content": "How can I help?"},
+ ]
+ result = ensure_alternating_roles(messages)
+ assert result == expected
+
+ def test_ensure_alternating_roles_mixed_sequence(self):
+ from aider.sendchat import ensure_alternating_roles
+
+ messages = [
+ {"role": "user", "content": "Hello"},
+ {"role": "user", "content": "Are you there?"},
+ {"role": "assistant", "content": "Yes"},
+ {"role": "assistant", "content": "How can I help?"},
+ {"role": "user", "content": "Write code"},
+ ]
+ expected = [
+ {"role": "user", "content": "Hello"},
+ {"role": "assistant", "content": ""},
+ {"role": "user", "content": "Are you there?"},
+ {"role": "assistant", "content": "Yes"},
+ {"role": "user", "content": ""},
+ {"role": "assistant", "content": "How can I help?"},
+ {"role": "user", "content": "Write code"},
+ ]
+ result = ensure_alternating_roles(messages)
+ assert result == expected
diff --git a/tests/fixtures/languages/kotlin/test.kt b/tests/fixtures/languages/kotlin/test.kt
new file mode 100644
index 000000000..c3f9772ac
--- /dev/null
+++ b/tests/fixtures/languages/kotlin/test.kt
@@ -0,0 +1,16 @@
+interface Greeting {
+ fun greet(name: String): String
+}
+
+class Test : Greeting {
+ private val prefix = "Hello"
+
+ override fun greet(name: String): String {
+ return "$prefix, $name!"
+ }
+}
+
+fun main(args: Array) {
+ val greeter = Test()
+ println(greeter.greet("World"))
+}