diff --git a/README.md b/README.md
index 3c4e7e3df08..05a6a54716b 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,32 @@
-## Documentation and Other Notes
+## Why `aider-ce`?
+
+`aider-ce` (aka `cecli`, pronounced like "Cecily") is a community-driven fork of the [Aider](https://aider.chat/) AI pair programming tool.
+Aider is a fantastic piece of software with a wonderful community but it has been painfully slow in receiving updates in the quickly evolving AI tooling space.
+
+We aim to foster an open, collaborative ecosystem where new features, experiments, and improvements can be developed and shared rapidly. We believe in genuine FOSS principles and actively welcome contributors of all skill levels.
+
+If you are looking for bleeding-edge features or want to get your hands dirty with the internals of an AI coding agent, here's your sign.
+LLMs are a part of our lives from here on out so join us in learning about and crafting the future.
+
+### Links
+
+[Discord Chat](https://discord.gg/McwdCRuqkJ) 🞄
+[Changelog](https://github.com/dwash96/aider-ce/blob/main/CHANGELOG.md) 🞄
+[Issue Queue](https://github.com/dwash96/aider-ce/issues)
+
+## Documentation/Other Notes:
+
* [Agent Mode](https://github.com/dwash96/aider-ce/blob/main/aider/website/docs/config/agent-mode.md)
* [MCP Configuration](https://github.com/dwash96/aider-ce/blob/main/aider/website/docs/config/mcp.md)
* [Session Management](https://github.com/dwash96/aider-ce/blob/main/aider/website/docs/sessions.md)
* [Aider Original Documentation (still mostly applies)](https://aider.chat/)
-* [Changelog](https://github.com/dwash96/aider-ce/blob/main/CHANGELOG.md)
-* [Discord Community](https://discord.gg/McwdCRuqkJ)
+
+You can see a selection of the enhancements and updates by comparing the help output:
+```bash
+aider --help > aider.help.txt
+cecli --help > cecli.help.txt
+diff aider.help.txt cecli.help.txt -uw --color
+```
## Installation Instructions
This project can be installed using several methods:
@@ -62,8 +84,8 @@ mcp-servers: |
"context7":{
"transport":"http",
"url":"https://mcp.context7.com/mcp"
- }
- }
+ }
+ }
}
```
@@ -87,7 +109,7 @@ The current priorities are to improve core capabilities and user experience of t
2. **Repo Map Accuracy** - [Discussion](https://github.com/dwash96/aider-ce/issues/45)
* [x] [Bias page ranking toward active/editable files in repo map parsing](https://github.com/Aider-AI/aider/issues/2405)
- * [x] [Include import information in repo map for richer context](https://github.com/Aider-AI/aider/issues/2688)
+ * [x] [Include import information in repo map for richer context](https://github.com/Aider-AI/aider/issues/2688)
* [x] [Handle non-unique symbols that break down in large codebases](https://github.com/Aider-AI/aider/issues/2341)
3. **Context Discovery** - [Discussion](https://github.com/dwash96/aider-ce/issues/46)
@@ -98,7 +120,7 @@ The current priorities are to improve core capabilities and user experience of t
4. **Context Delivery** - [Discussion](https://github.com/dwash96/aider-ce/issues/47)
* [ ] Use workflow for internal discovery to better target file snippets needed for specific tasks
- * [ ] Add support for partial files and code snippets in model completion messages
+ * [ ] Add support for partial files and code snippets in model completion messages
5. **TUI Experience** - [Discussion](https://github.com/dwash96/aider-ce/issues/48)
* [ ] Add a full TUI (probably using textual) to have a visual interface competitive with the other coding agent terminal programs
@@ -128,6 +150,7 @@ The current priorities are to improve core capabilities and user experience of t
@shladnik
@itlackey
@tomjuggler
+@szmania
@vk4s
@titusz
@daniel-vainsencher
@@ -143,6 +166,6 @@ The current priorities are to improve core capabilities and user experience of t
@itsmeknt
@cheahjs
@youknow04
+@pjcreath
@pcamp
-@miradnanali
-@o-nix
\ No newline at end of file
+@ErichBSchulz
\ No newline at end of file
diff --git a/aider/__init__.py b/aider/__init__.py
index 40adcbeff8e..6221a955f03 100644
--- a/aider/__init__.py
+++ b/aider/__init__.py
@@ -1,6 +1,6 @@
from packaging import version
-__version__ = "0.88.39.dev"
+__version__ = "0.88.40.dev"
safe_version = __version__
try:
diff --git a/aider/args.py b/aider/args.py
index 91137539a9c..da383283cef 100644
--- a/aider/args.py
+++ b/aider/args.py
@@ -246,13 +246,24 @@ def get_parser(default_config_files, git_root):
"--auto-save",
action=argparse.BooleanOptionalAction,
default=False,
- help="Enable/disable automatic saving of sessions as 'auto-save' (default: False)",
+ help=(
+ "Enable/disable automatic saving of sessions as --auto-save-session-name (default:"
+ " False)"
+ ),
+ )
+ group.add_argument(
+ "--auto-save-session-name",
+ help="Specify session name for auto-save and auto-load (default: auto-save)",
+ default="auto-save",
)
group.add_argument(
"--auto-load",
action=argparse.BooleanOptionalAction,
default=False,
- help="Enable/disable automatic loading of 'auto-save' session on startup (default: False)",
+ help=(
+ "Enable/disable automatic loading of --auto-save-session-name session on startup"
+ " (default: False)"
+ ),
)
group.add_argument(
"--mcp-servers",
diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py
index 910fabef7fc..4c93997305e 100755
--- a/aider/coders/base_coder.py
+++ b/aider/coders/base_coder.py
@@ -191,8 +191,9 @@ async def create(
done_messages = from_coder.done_messages
if edit_format != from_coder.edit_format and done_messages and summarize_from_coder:
try:
+ io.tool_warning("Summarizing messages, please wait...")
done_messages = await from_coder.summarizer.summarize_all(done_messages)
- except ValueError:
+ except (KeyboardInterrupt, ValueError):
# If summarization fails, keep the original messages and warn the user
io.tool_warning(
"Chat history summarization failed, continuing with full history"
@@ -3206,7 +3207,8 @@ def consolidate_chunks(self):
self.partial_response_reasoning_content = reasoning_content or ""
try:
- self.partial_response_content = response.choices[0].message.content or ""
+ if not self.partial_response_reasoning_content:
+ self.partial_response_content = response.choices[0].message.content or ""
except AttributeError as e:
content_err = e
@@ -3769,7 +3771,7 @@ def apply_edits_dry_run(self, edits):
return edits
async def auto_save_session(self):
- """Automatically save the current session as 'auto-save'."""
+ """Automatically save the current session to {auto-save-session-name}.json."""
if not getattr(self.args, "auto_save", False):
return
@@ -3791,7 +3793,10 @@ async def auto_save_session(self):
session_manager = SessionManager(self, self.io)
loop = asyncio.get_running_loop()
self._autosave_future = loop.run_in_executor(
- None, session_manager.save_session, "auto-save", False
+ None,
+ session_manager.save_session,
+ getattr(self.args, "auto_save_session_name", "auto-save"),
+ False,
)
except Exception:
# Don't show errors for auto-save to avoid interrupting the user experience
@@ -3841,9 +3846,7 @@ async def handle_shell_commands(self, commands_str, group):
if not command or command.startswith("#"):
continue
- if command and getattr(self.args, "command_prefix", None):
- command_prefix = getattr(self.args, "command_prefix", None)
- command = f"{command_prefix} {command}"
+ command = self.format_command_with_prefix(command)
self.io.tool_output()
self.io.tool_output(f"Running {command}")
@@ -3862,3 +3865,32 @@ async def handle_shell_commands(self, commands_str, group):
line_plural = "line" if num_lines == 1 else "lines"
self.io.tool_output(f"Added {num_lines} {line_plural} of output to the chat.")
return accumulated_output
+
+ def format_command_with_prefix(self, command):
+ """
+ Format a command with a command prefix.
+
+ If the command prefix contains a {} placeholder, replace it with the command.
+ Otherwise, append the command to the prefix with a space.
+
+ Args:
+ command (str): The command to format
+
+ Returns:
+ str: The formatted command
+ """
+ command_prefix = None
+
+ if command and getattr(self.args, "command_prefix", None):
+ command_prefix = getattr(self.args, "command_prefix", None)
+
+ if not command_prefix:
+ return command
+
+ # Check if the prefix contains a {} placeholder
+ if "{}" in command_prefix:
+ # Replace the {} placeholder with the command
+ return command_prefix.replace("{}", command)
+ else:
+ # Append the command to the prefix with a space
+ return f"{command_prefix} {command}"
diff --git a/aider/commands.py b/aider/commands.py
index 73a702334ed..b209c97a43d 100644
--- a/aider/commands.py
+++ b/aider/commands.py
@@ -2160,6 +2160,13 @@ def cmd_load_session(self, args):
session_manager = sessions.SessionManager(self.coder, self.io)
session_manager.load_session(args.strip())
+ def cmd_command_prefix(self, args=""):
+ """Change Command Prefix For All Running Commands"""
+ if not args.strip():
+ setattr(self.coder.args, "command_prefix", "")
+
+ setattr(self.coder.args, "command_prefix", args.strip())
+
def cmd_copy_context(self, args=None):
"""Copy the current chat context as markdown, suitable to paste into a web UI"""
diff --git a/aider/llm.py b/aider/llm.py
index f3813e24301..31a166834c2 100644
--- a/aider/llm.py
+++ b/aider/llm.py
@@ -1,6 +1,9 @@
+import asyncio
+import contextlib
import importlib
import os
import warnings
+from collections.abc import Coroutine
from aider.dump import dump # noqa: F401
@@ -44,11 +47,50 @@ def _load_litellm(self):
return
self._lazy_module = importlib.import_module("litellm")
+ self._lazy_module.disable_streaming_logging = True
self._lazy_module.suppress_debug_info = True
self._lazy_module.set_verbose = False
self._lazy_module.drop_params = True
self._lazy_module._logging._disable_debugging()
+ # Patch GLOBAL_LOGGING_WORKER to avoid event loop binding issues
+ # See: https://github.com/BerriAI/litellm/issues/16518
+ # See: https://github.com/BerriAI/litellm/issues/14521
+ try:
+ from litellm.litellm_core_utils import logging_worker
+ except ImportError:
+ # Module didn't exist before litellm 1.76.0
+ # https://github.com/BerriAI/litellm/pull/13905
+ pass
+ else:
+
+ class NoOpLoggingWorker:
+ """No-op worker that executes callbacks immediately without queuing."""
+
+ def start(self) -> None:
+ pass
+
+ def enqueue(self, coroutine: Coroutine) -> None:
+ # Execute immediately in current loop instead of queueing,
+ # and do nothing if there's no current loop
+ with contextlib.suppress(RuntimeError):
+ # This logging task is fire-and-forget
+ asyncio.create_task(coroutine)
+
+ def ensure_initialized_and_enqueue(self, async_coroutine: Coroutine) -> None:
+ self.enqueue(async_coroutine)
+
+ async def stop(self) -> None:
+ pass
+
+ async def flush(self) -> None:
+ pass
+
+ async def clear_queue(self) -> None:
+ pass
+
+ logging_worker.GLOBAL_LOGGING_WORKER = NoOpLoggingWorker()
+
litellm = LazyLiteLLM()
diff --git a/aider/main.py b/aider/main.py
index 35898acb907..5fc2a9eaf2c 100644
--- a/aider/main.py
+++ b/aider/main.py
@@ -1315,7 +1315,9 @@ def get_io(pretty):
from aider.sessions import SessionManager
session_manager = SessionManager(coder, io)
- session_manager.load_session("auto-save")
+ session_manager.load_session(
+ args.auto_save_session_name if args.auto_save_session_name else "auto-save"
+ )
except Exception:
# Don't show errors for auto-load to avoid interrupting the user experience
pass
diff --git a/aider/tools/command.py b/aider/tools/command.py
index cfed959bc65..9a9e3537b84 100644
--- a/aider/tools/command.py
+++ b/aider/tools/command.py
@@ -32,9 +32,7 @@ async def execute(cls, coder, command_string):
# Ask for confirmation before executing.
# allow_never=True enables the 'Always' option.
# confirm_ask handles remembering the 'Always' choice based on the subject.
- if command_string and getattr(coder.args, "command_prefix", None):
- command_prefix = getattr(coder.args, "command_prefix", None)
- command_string = f"{command_prefix} {command_string}"
+ command_string = coder.format_command_with_prefix(command_string)
confirmed = (
True
diff --git a/aider/tools/command_interactive.py b/aider/tools/command_interactive.py
index 1ccb621f7e7..ffff8f8156c 100644
--- a/aider/tools/command_interactive.py
+++ b/aider/tools/command_interactive.py
@@ -31,9 +31,7 @@ async def execute(cls, coder, command_string):
Execute an interactive shell command using run_cmd (which uses pexpect/PTY).
"""
try:
- if command_string and getattr(coder.args, "command_prefix", None):
- command_prefix = getattr(coder.args, "command_prefix", None)
- command_string = f"{command_prefix} {command_string}"
+ command_string = coder.format_command_with_prefix(command_string)
confirmed = (
True