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 # 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 ### Aider v0.49.1
- Bugfix to `/help`. - Bugfix to `/help`.

View file

@ -109,6 +109,14 @@ def get_parser(default_config_files, git_root):
const=gpt_3_model_name, const=gpt_3_model_name,
help=f"Use {gpt_3_model_name} model for the main chat", 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") group = parser.add_argument_group("Model Settings")

View file

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

View file

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

View file

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

View file

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

View file

@ -16,6 +16,19 @@ cog.out(text)
# Release history # 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 ### Aider v0.49.1
- Bugfix to `/help`. - Bugfix to `/help`.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,7 +6,7 @@ nav_order: 500
# DeepSeek # DeepSeek
Aider can connect to the DeepSeek.com API. 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 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 setx DEEPSEEK_API_KEY <key> # Windows, restart shell after setx
# Use DeepSeek Coder V2 # 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 aiohappyeyeballs==2.3.5
# via aiohttp # via aiohttp
aiohttp==3.10.2 aiohttp==3.10.3
# via litellm # via litellm
aiosignal==1.3.1 aiosignal==1.3.1
# via aiohttp # via aiohttp
@ -92,7 +92,7 @@ jsonschema==4.23.0
# litellm # litellm
jsonschema-specifications==2023.12.1 jsonschema-specifications==2023.12.1
# via jsonschema # via jsonschema
litellm==1.43.4 litellm==1.43.9
# via -r requirements/requirements.in # via -r requirements/requirements.in
markdown-it-py==3.0.0 markdown-it-py==3.0.0
# via rich # via rich
@ -112,7 +112,7 @@ numpy==1.26.4
# via # via
# -r requirements/requirements.in # -r requirements/requirements.in
# scipy # scipy
openai==1.40.2 openai==1.40.6
# via litellm # via litellm
packaging==24.1 packaging==24.1
# via # via
@ -125,7 +125,9 @@ pathspec==0.12.1
pillow==10.4.0 pillow==10.4.0
# via -r requirements/requirements.in # via -r requirements/requirements.in
prompt-toolkit==3.0.47 prompt-toolkit==3.0.47
# via -r requirements/requirements.in # via
# -r requirements/requirements.in
# pypager
pycodestyle==2.12.1 pycodestyle==2.12.1
# via flake8 # via flake8
pycparser==2.22 pycparser==2.22
@ -139,7 +141,11 @@ pydantic-core==2.20.1
pyflakes==3.2.0 pyflakes==3.2.0
# via flake8 # via flake8
pygments==2.18.0 pygments==2.18.0
# via rich # via
# pypager
# rich
pypager==3.0.1
# via -r requirements/requirements.in
pypandoc==1.13 pypandoc==1.13
# via -r requirements/requirements.in # via -r requirements/requirements.in
pyperclip==1.9.0 pyperclip==1.9.0
@ -176,7 +182,7 @@ sniffio==1.3.1
# anyio # anyio
# httpx # httpx
# openai # openai
sounddevice==0.4.7 sounddevice==0.5.0
# via -r requirements/requirements.in # via -r requirements/requirements.in
soundfile==0.12.1 soundfile==0.12.1
# via -r requirements/requirements.in # via -r requirements/requirements.in
@ -210,5 +216,5 @@ wcwidth==0.2.13
# via prompt-toolkit # via prompt-toolkit
yarl==1.9.4 yarl==1.9.4
# via aiohttp # via aiohttp
zipp==3.19.2 zipp==3.20.0
# via importlib-metadata # via importlib-metadata

View file

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

View file

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

View file

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

View file

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

View file

@ -224,6 +224,15 @@ class TestMain(TestCase):
main(["--yes", fname, "--encoding", "iso-8859-15"]) 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.main.InputOutput")
@patch("aider.coders.base_coder.Coder.run") @patch("aider.coders.base_coder.Coder.run")
def test_main_message_adds_to_input_history(self, mock_run, MockInputOutput): def test_main_message_adds_to_input_history(self, mock_run, MockInputOutput):