Merge branch 'main' into mixpanel

This commit is contained in:
Paul Gauthier 2024-08-13 07:09:34 -07:00
commit f52265362f
20 changed files with 135 additions and 64 deletions

View file

@ -1,6 +1,19 @@
# Release history
### main branch
- Infinite output for DeepSeek Coder, Mistral models in addition to Anthropic's models.
- New `--deepseek` switch to use DeepSeek Coder.
- New `--chat-mode <mode>` switch to launch in ask/help/code modes.
- New `/code <message>` command request a code edit while in `ask` mode.
- Web scraper is more robust if page never idles.
- Improved token and cost reporting for infinite output.
- Improvements and bug fixes for `/read` only files.
- Bug fix to persist files added during `/ask`.
- Bug fix for chat history size in `/tokens`.
### Aider v0.49.1
- Bugfix to `/help`.

View file

@ -109,6 +109,14 @@ def get_parser(default_config_files, git_root):
const=gpt_3_model_name,
help=f"Use {gpt_3_model_name} model for the main chat",
)
deepseek_model = "deepseek/deepseek-coder"
group.add_argument(
"--deepseek",
action="store_const",
dest="model",
const=deepseek_model,
help=f"Use {deepseek_model} model for the main chat",
)
##########
group = parser.add_argument_group("Model Settings")

View file

@ -73,6 +73,9 @@ class Coder:
multi_response_content = ""
partial_response_content = ""
commit_before_message = []
message_cost = 0.0
message_tokens_sent = 0
message_tokens_received = 0
@classmethod
def create(
@ -149,7 +152,10 @@ class Coder:
main_model = self.main_model
weak_model = main_model.weak_model
prefix = "Model:"
output = f" {main_model.name} with {self.edit_format} edit format"
output = f" {main_model.name} with"
if main_model.info.get("supports_assistant_prefill"):
output += " ♾️"
output += f" {self.edit_format} edit format"
if weak_model is not main_model:
prefix = "Models:"
output += f", weak model {weak_model.name}"
@ -993,7 +999,7 @@ class Coder:
return
except FinishReasonLength:
# We hit the output limit!
if not self.main_model.can_prefill:
if not self.main_model.info.get("supports_assistant_prefill"):
exhausted = True
break
@ -1002,7 +1008,9 @@ class Coder:
if messages[-1]["role"] == "assistant":
messages[-1]["content"] = self.multi_response_content
else:
messages.append(dict(role="assistant", content=self.multi_response_content))
messages.append(
dict(role="assistant", content=self.multi_response_content, prefix=True)
)
except Exception as err:
self.io.tool_error(f"Unexpected error: {err}")
traceback.print_exc()
@ -1017,8 +1025,7 @@ class Coder:
self.io.tool_output()
if self.usage_report:
self.io.tool_output(self.usage_report)
self.show_usage_report()
if exhausted:
self.show_exhausted_error()
@ -1241,7 +1248,6 @@ class Coder:
self.io.log_llm_history("TO LLM", format_messages(messages))
interrupted = False
try:
hash_object, completion = send_completion(
model.name,
@ -1258,9 +1264,9 @@ class Coder:
yield from self.show_send_output_stream(completion)
else:
self.show_send_output(completion)
except KeyboardInterrupt:
except KeyboardInterrupt as kbi:
self.keyboard_interrupt()
interrupted = True
raise kbi
finally:
self.io.log_llm_history(
"LLM RESPONSE",
@ -1275,10 +1281,7 @@ class Coder:
if args:
self.io.ai_output(json.dumps(args, indent=4))
if interrupted:
raise KeyboardInterrupt
self.calculate_and_show_tokens_and_cost(messages, completion)
self.calculate_and_show_tokens_and_cost(messages, completion)
def show_send_output(self, completion):
if self.verbose:
@ -1390,13 +1393,19 @@ class Coder:
prompt_tokens = self.main_model.token_count(messages)
completion_tokens = self.main_model.token_count(self.partial_response_content)
self.usage_report = f"Tokens: {prompt_tokens:,} sent, {completion_tokens:,} received."
self.message_tokens_sent += prompt_tokens
self.message_tokens_received += completion_tokens
tokens_report = (
f"Tokens: {self.message_tokens_sent:,} sent, {self.message_tokens_received:,} received."
)
if self.main_model.info.get("input_cost_per_token"):
cost += prompt_tokens * self.main_model.info.get("input_cost_per_token")
if self.main_model.info.get("output_cost_per_token"):
cost += completion_tokens * self.main_model.info.get("output_cost_per_token")
self.total_cost += cost
self.message_cost += cost
def format_cost(value):
if value == 0:
@ -1407,9 +1416,20 @@ class Coder:
else:
return f"{value:.{max(2, 2 - int(math.log10(magnitude)))}f}"
self.usage_report += (
f" Cost: ${format_cost(cost)} request, ${format_cost(self.total_cost)} session."
cost_report = (
f" Cost: ${format_cost(self.message_cost)} message,"
f" ${format_cost(self.total_cost)} session."
)
self.usage_report = tokens_report + cost_report
else:
self.usage_report = tokens_report
def show_usage_report(self):
if self.usage_report:
self.io.tool_output(self.usage_report)
self.message_cost = 0.0
self.message_tokens_sent = 0
self.message_tokens_received = 0
self.event(
"message_send",

View file

@ -423,11 +423,11 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
return main(argv, input, output, right_repo_root, return_coder=return_coder)
if args.just_check_update:
update_available = check_version(io, just_check=True)
update_available = check_version(io, just_check=True, verbose=args.verbose)
return 0 if not update_available else 1
if args.check_update:
check_version(io)
check_version(io, verbose=args.verbose)
if args.models:
models.print_matching_models(io, args.models)

View file

@ -70,7 +70,6 @@ class ModelSettings:
lazy: bool = False
reminder_as_sys_msg: bool = False
examples_as_sys_msg: bool = False
can_prefill: bool = False
extra_headers: Optional[dict] = None
max_tokens: Optional[int] = None
@ -248,7 +247,6 @@ MODEL_SETTINGS = [
weak_model_name="claude-3-haiku-20240307",
use_repo_map=True,
send_undo_reply=True,
can_prefill=True,
),
ModelSettings(
"openrouter/anthropic/claude-3-opus",
@ -256,13 +254,11 @@ MODEL_SETTINGS = [
weak_model_name="openrouter/anthropic/claude-3-haiku",
use_repo_map=True,
send_undo_reply=True,
can_prefill=True,
),
ModelSettings(
"claude-3-sonnet-20240229",
"whole",
weak_model_name="claude-3-haiku-20240307",
can_prefill=True,
),
ModelSettings(
"claude-3-5-sonnet-20240620",
@ -270,7 +266,6 @@ MODEL_SETTINGS = [
weak_model_name="claude-3-haiku-20240307",
use_repo_map=True,
examples_as_sys_msg=True,
can_prefill=True,
accepts_images=True,
max_tokens=8192,
extra_headers={"anthropic-beta": "max-tokens-3-5-sonnet-2024-07-15"},
@ -281,7 +276,6 @@ MODEL_SETTINGS = [
weak_model_name="claude-3-haiku-20240307",
use_repo_map=True,
examples_as_sys_msg=True,
can_prefill=True,
max_tokens=8192,
extra_headers={
"anthropic-beta": "max-tokens-3-5-sonnet-2024-07-15",
@ -295,7 +289,6 @@ MODEL_SETTINGS = [
weak_model_name="openrouter/anthropic/claude-3-haiku-20240307",
use_repo_map=True,
examples_as_sys_msg=True,
can_prefill=True,
accepts_images=True,
max_tokens=8192,
extra_headers={
@ -312,7 +305,6 @@ MODEL_SETTINGS = [
weak_model_name="vertex_ai/claude-3-haiku@20240307",
use_repo_map=True,
examples_as_sys_msg=True,
can_prefill=True,
accepts_images=True,
),
ModelSettings(
@ -321,13 +313,11 @@ MODEL_SETTINGS = [
weak_model_name="vertex_ai/claude-3-haiku@20240307",
use_repo_map=True,
send_undo_reply=True,
can_prefill=True,
),
ModelSettings(
"vertex_ai/claude-3-sonnet@20240229",
"whole",
weak_model_name="vertex_ai/claude-3-haiku@20240307",
can_prefill=True,
),
# Cohere
ModelSettings(
@ -486,14 +476,10 @@ class Model:
if "gpt-3.5" in model or "gpt-4" in model:
self.reminder_as_sys_msg = True
if "anthropic" in model:
self.can_prefill = True
if "3.5-sonnet" in model or "3-5-sonnet" in model:
self.edit_format = "diff"
self.use_repo_map = True
self.examples_as_sys_msg = True
self.can_prefill = True
# use the defaults
if self.edit_format == "diff":

View file

@ -57,6 +57,7 @@ def send_completion(
temperature=temperature,
stream=stream,
)
if functions is not None:
kwargs["functions"] = functions
if extra_headers is not None:

View file

@ -10,12 +10,15 @@ from aider import utils
from aider.dump import dump # noqa: F401
def check_version(io, just_check=False):
def check_version(io, just_check=False, verbose=False):
fname = Path.home() / ".aider" / "caches" / "versioncheck"
if not just_check and fname.exists():
day = 60 * 60 * 24
since = time.time() - fname.stat().st_mtime
if since < day:
if verbose:
hours = since / 60 / 60
io.tool_output(f"Too soon to check version: {hours:.1f} hours")
return
# To keep startup fast, avoid importing this unless needed
@ -27,7 +30,7 @@ def check_version(io, just_check=False):
latest_version = data["info"]["version"]
current_version = aider.__version__
if just_check:
if just_check or verbose:
io.tool_output(f"Current version: {current_version}")
io.tool_output(f"Latest version: {latest_version}")
@ -41,11 +44,13 @@ def check_version(io, just_check=False):
fname.parent.mkdir(parents=True, exist_ok=True)
fname.touch()
if just_check:
if just_check or verbose:
if is_update_available:
io.tool_output("Update available")
else:
io.tool_output("No update available")
if just_check:
return is_update_available
if not is_update_available:

View file

@ -16,6 +16,19 @@ cog.out(text)
# Release history
### main branch
- Infinite output for DeepSeek Coder, Mistral models in addition to Anthropic's models.
- New `--deepseek` switch to use DeepSeek Coder.
- New `--chat-mode <mode>` switch to launch in ask/help/code modes.
- New `/code <message>` command request a code edit while in `ask` mode.
- Web scraper is more robust if page never idles.
- Improved token and cost reporting for infinite output.
- Improvements and bug fixes for `/read` only files.
- Bug fix to persist files added during `/ask`.
- Bug fix for chat history size in `/tokens`.
### Aider v0.49.1
- Bugfix to `/help`.

View file

@ -47,6 +47,9 @@
## Use gpt-3.5-turbo model for the main chat
#35turbo: false
## Use deepseek/deepseek-coder model for the main chat
#deepseek: false
#################
# Model Settings:

View file

@ -51,6 +51,9 @@
## Use gpt-3.5-turbo model for the main chat
#AIDER_35TURBO=
## Use deepseek/deepseek-coder model for the main chat
#AIDER_DEEPSEEK=
#################
# Model Settings:

View file

@ -86,6 +86,9 @@ cog.outl("```")
## Use gpt-3.5-turbo model for the main chat
#35turbo: false
## Use deepseek/deepseek-coder model for the main chat
#deepseek: false
#################
# Model Settings:

View file

@ -93,6 +93,9 @@ cog.outl("```")
## Use gpt-3.5-turbo model for the main chat
#AIDER_35TURBO=
## Use deepseek/deepseek-coder model for the main chat
#AIDER_DEEPSEEK=
#################
# Model Settings:

View file

@ -27,7 +27,7 @@ cog.out(get_md_help())
```
usage: aider [-h] [--openai-api-key] [--anthropic-api-key] [--model]
[--opus] [--sonnet] [--4] [--4o] [--mini] [--4-turbo]
[--35turbo] [--models] [--openai-api-base]
[--35turbo] [--deepseek] [--models] [--openai-api-base]
[--openai-api-type] [--openai-api-version]
[--openai-api-deployment-id] [--openai-organization-id]
[--model-settings-file] [--model-metadata-file]
@ -118,6 +118,10 @@ Aliases:
- `--3`
- `-3`
### `--deepseek`
Use deepseek/deepseek-coder model for the main chat
Environment variable: `AIDER_DEEPSEEK`
## Model Settings:
### `--models MODEL`

View file

@ -6,7 +6,7 @@ nav_order: 500
# DeepSeek
Aider can connect to the DeepSeek.com API.
The DeepSeek Coder V2 model gets the top score on aider's code editing benchmark.
The DeepSeek Coder V2 model has a top score on aider's code editing benchmark.
```
python -m pip install aider-chat
@ -15,10 +15,6 @@ export DEEPSEEK_API_KEY=<key> # Mac/Linux
setx DEEPSEEK_API_KEY <key> # Windows, restart shell after setx
# Use DeepSeek Coder V2
aider --model deepseek/deepseek-coder
aider --deepseek
```
See the [model warnings](warnings.html)
section for information on warnings which will occur
when working with models that aider is not familiar with.

View file

@ -6,7 +6,7 @@
#
aiohappyeyeballs==2.3.5
# via aiohttp
aiohttp==3.10.2
aiohttp==3.10.3
# via litellm
aiosignal==1.3.1
# via aiohttp
@ -92,7 +92,7 @@ jsonschema==4.23.0
# litellm
jsonschema-specifications==2023.12.1
# via jsonschema
litellm==1.43.4
litellm==1.43.9
# via -r requirements/requirements.in
markdown-it-py==3.0.0
# via rich
@ -112,7 +112,7 @@ numpy==1.26.4
# via
# -r requirements/requirements.in
# scipy
openai==1.40.2
openai==1.40.6
# via litellm
packaging==24.1
# via
@ -125,7 +125,9 @@ pathspec==0.12.1
pillow==10.4.0
# via -r requirements/requirements.in
prompt-toolkit==3.0.47
# via -r requirements/requirements.in
# via
# -r requirements/requirements.in
# pypager
pycodestyle==2.12.1
# via flake8
pycparser==2.22
@ -139,7 +141,11 @@ pydantic-core==2.20.1
pyflakes==3.2.0
# via flake8
pygments==2.18.0
# via rich
# via
# pypager
# rich
pypager==3.0.1
# via -r requirements/requirements.in
pypandoc==1.13
# via -r requirements/requirements.in
pyperclip==1.9.0
@ -176,7 +182,7 @@ sniffio==1.3.1
# anyio
# httpx
# openai
sounddevice==0.4.7
sounddevice==0.5.0
# via -r requirements/requirements.in
soundfile==0.12.1
# via -r requirements/requirements.in
@ -210,5 +216,5 @@ wcwidth==0.2.13
# via prompt-toolkit
yarl==1.9.4
# via aiohttp
zipp==3.19.2
zipp==3.20.0
# via importlib-metadata

View file

@ -4,7 +4,7 @@
#
# pip-compile --output-file=requirements/requirements-browser.txt requirements/requirements-browser.in
#
altair==5.3.0
altair==5.4.0
# via streamlit
attrs==24.2.0
# via
@ -64,10 +64,11 @@ mdurl==0.1.2
# via
# -c requirements/../requirements.txt
# markdown-it-py
narwhals==1.3.0
# via altair
numpy==1.26.4
# via
# -c requirements/../requirements.txt
# altair
# pandas
# pyarrow
# pydeck
@ -78,9 +79,7 @@ packaging==24.1
# altair
# streamlit
pandas==2.2.2
# via
# altair
# streamlit
# via streamlit
pillow==10.4.0
# via
# -c requirements/../requirements.txt
@ -129,13 +128,12 @@ tenacity==8.5.0
# via streamlit
toml==0.10.2
# via streamlit
toolz==0.12.1
# via altair
tornado==6.4.1
# via streamlit
typing-extensions==4.12.2
# via
# -c requirements/../requirements.txt
# altair
# streamlit
tzdata==2024.1
# via pandas
@ -143,5 +141,5 @@ urllib3==2.2.2
# via
# -c requirements/../requirements.txt
# requests
watchdog==4.0.1
watchdog==4.0.2
# via -r requirements/requirements-browser.in

View file

@ -75,7 +75,7 @@ markupsafe==2.1.5
# via
# -c requirements/../requirements.txt
# jinja2
matplotlib==3.9.1.post1
matplotlib==3.9.2
# via -r requirements/requirements-dev.in
mdurl==0.1.2
# via

View file

@ -8,7 +8,7 @@ aiohappyeyeballs==2.3.5
# via
# -c requirements/../requirements.txt
# aiohttp
aiohttp==3.10.2
aiohttp==3.10.3
# via
# -c requirements/../requirements.txt
# huggingface-hub
@ -112,11 +112,11 @@ joblib==1.4.2
# via
# nltk
# scikit-learn
llama-index-core==0.10.63
llama-index-core==0.10.65
# via
# -r requirements/requirements-help.in
# llama-index-embeddings-huggingface
llama-index-embeddings-huggingface==0.2.2
llama-index-embeddings-huggingface==0.2.3
# via -r requirements/requirements-help.in
markupsafe==2.1.5
# via
@ -142,7 +142,7 @@ networkx==3.2.1
# -c requirements/../requirements.txt
# llama-index-core
# torch
nltk==3.8.1
nltk==3.8.2
# via llama-index-core
numpy==1.26.4
# via
@ -153,7 +153,7 @@ numpy==1.26.4
# scipy
# sentence-transformers
# transformers
openai==1.40.2
openai==1.40.6
# via
# -c requirements/../requirements.txt
# llama-index-core
@ -224,7 +224,7 @@ sqlalchemy[asyncio]==2.0.32
# via
# llama-index-core
# sqlalchemy
sympy==1.13.1
sympy==1.13.2
# via torch
tenacity==8.5.0
# via llama-index-core

View file

@ -6,7 +6,7 @@
#
greenlet==3.0.3
# via playwright
playwright==1.45.1
playwright==1.46.0
# via -r requirements/requirements-playwright.in
pyee==11.1.0
# via playwright

View file

@ -224,6 +224,15 @@ class TestMain(TestCase):
main(["--yes", fname, "--encoding", "iso-8859-15"])
def test_main_exit_calls_version_check(self):
with GitTemporaryDirectory():
with patch("aider.main.check_version") as mock_check_version, patch(
"aider.main.InputOutput"
) as mock_input_output:
main(["--exit"], input=DummyInput(), output=DummyOutput())
mock_check_version.assert_called_once()
mock_input_output.assert_called_once()
@patch("aider.main.InputOutput")
@patch("aider.coders.base_coder.Coder.run")
def test_main_message_adds_to_input_history(self, mock_run, MockInputOutput):