Skip to content
Merged
41 changes: 32 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -62,8 +84,8 @@ mcp-servers: |
"context7":{
"transport":"http",
"url":"https://mcp.context7.com/mcp"
}
}
}
}
}
```

Expand All @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -128,6 +150,7 @@ The current priorities are to improve core capabilities and user experience of t
<a href="https://github.com/shladnik">@shladnik</a>
<a href="https://github.com/itlackey">@itlackey</a>
<a href="https://github.com/tomjuggler">@tomjuggler</a>
<a href="https://github.com/szmania">@szmania</a>
<a href="https://github.com/vk4s">@vk4s</a>
<a href="https://github.com/titusz">@titusz</a>
<a href="https://github.com/daniel-vainsencher">@daniel-vainsencher</a>
Expand All @@ -143,6 +166,6 @@ The current priorities are to improve core capabilities and user experience of t
<a href="https://github.com/itsmeknt">@itsmeknt</a>
<a href="https://github.com/cheahjs">@cheahjs</a>
<a href="https://github.com/youknow04">@youknow04</a>
<a href="https://github.com/pjcreath">@pjcreath</a>
<a href="https://github.com/pcamp">@pcamp</a>
<a href="https://github.com/miradnanali">@miradnanali</a>
<a href="https://github.com/o-nix">@o-nix</a>
<a href="https://github.com/ErichBSchulz">@ErichBSchulz</a>
2 changes: 1 addition & 1 deletion aider/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from packaging import version

__version__ = "0.88.39.dev"
__version__ = "0.88.40.dev"
safe_version = __version__

try:
Expand Down
15 changes: 13 additions & 2 deletions aider/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
46 changes: 39 additions & 7 deletions aider/coders/base_coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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}")
Expand All @@ -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}"
7 changes: 7 additions & 0 deletions aider/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"""

Expand Down
42 changes: 42 additions & 0 deletions aider/llm.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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()

Expand Down
4 changes: 3 additions & 1 deletion aider/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions aider/tools/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions aider/tools/command_interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading