Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.4.dev"
__version__ = "0.88.5.dev"
safe_version = __version__

try:
Expand Down
16 changes: 14 additions & 2 deletions aider/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,12 @@ def get_parser(default_config_files, git_root):
" (default: current directory)"
),
)

group.add_argument(
"--map-memory-cache",
action="store_true",
help="Store repo map in memory (default: False)",
default=False,
)
##########
group = parser.add_argument_group("History Files")
default_input_history_file = (
Expand Down Expand Up @@ -745,7 +750,14 @@ def get_parser(default_config_files, git_root):
help="Print the system prompts and exit (debug)",
default=False,
)

group.add_argument(
"--linear-output",
action="store_true",
help=(
"Run input and output sequentially instead of us simultaneous streams (default: False)"
),
default=False,
)
##########
group = parser.add_argument_group("Voice settings")
group.add_argument(
Expand Down
75 changes: 72 additions & 3 deletions aider/coders/base_coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ def __init__(
map_cache_dir=".",
repomap_in_memory=False,
preserve_todo_list=False,
linear_output=False,
):
# initialize from args.map_cache_dir
self.map_cache_dir = map_cache_dir
Expand Down Expand Up @@ -469,6 +470,7 @@ def __init__(

self.dry_run = dry_run
self.pretty = self.io.pretty
self.linear_output = linear_output

self.main_model = main_model

Expand Down Expand Up @@ -1058,12 +1060,67 @@ async def run(self, with_message=None, preproc=True):
while self.io.confirmation_in_progress:
await asyncio.sleep(0.1) # Yield control and wait briefly

if self.linear_output:
return await self._run_linear(with_message, preproc)

if self.io.prompt_session:
with patch_stdout(raw=True):
return await self._run_patched(with_message, preproc)
else:
return await self._run_patched(with_message, preproc)

async def _run_linear(self, with_message=None, preproc=True):
try:
if with_message:
self.io.user_input(with_message)
await self.run_one(with_message, preproc)
return self.partial_response_content

user_message = None
await self.io.cancel_input_task()
await self.io.cancel_processing_task()

while True:
try:
if self.commands.cmd_running:
await asyncio.sleep(0.1)
continue

if not self.suppress_announcements_for_next_prompt:
self.show_announcements()
self.suppress_announcements_for_next_prompt = True

self.io.input_task = asyncio.create_task(self.get_input())
await asyncio.sleep(0)
await self.io.input_task
user_message = self.io.input_task.result()

self.io.processing_task = asyncio.create_task(
self._processing_logic(user_message, preproc)
)

await self.io.processing_task

self.io.ring_bell()
user_message = None
except KeyboardInterrupt:
if self.io.input_task:
self.io.set_placeholder("")
await self.io.cancel_input_task()

if self.io.processing_task:
await self.io.cancel_processing_task()
self.io.stop_spinner()

self.keyboard_interrupt()
except (asyncio.CancelledError, IndexError):
pass
except EOFError:
return
finally:
await self.io.cancel_input_task()
await self.io.cancel_processing_task()

async def _run_patched(self, with_message=None, preproc=True):
try:
if with_message:
Expand All @@ -1077,6 +1134,10 @@ async def _run_patched(self, with_message=None, preproc=True):

while True:
try:
if self.commands.cmd_running:
await asyncio.sleep(0.1)
continue

if (
not self.io.confirmation_in_progress
and not user_message
Expand Down Expand Up @@ -1134,6 +1195,10 @@ async def _run_patched(self, with_message=None, preproc=True):
try:
user_message = self.io.input_task.result()
await self.io.cancel_input_task()

if self.commands.is_run_command(user_message):
self.commands.cmd_running = True

except (asyncio.CancelledError, KeyboardInterrupt):
user_message = None

Expand Down Expand Up @@ -1170,7 +1235,6 @@ async def _run_patched(self, with_message=None, preproc=True):
user_message = None

except (asyncio.CancelledError, KeyboardInterrupt):
print("error of some sort")
pass

# Stop spinner when processing task completes
Expand All @@ -1180,6 +1244,7 @@ async def _run_patched(self, with_message=None, preproc=True):
self.io.processing_task = asyncio.create_task(
self._processing_logic(user_message, preproc)
)

# Start spinner for processing task
self.io.start_spinner("Processing...")

Expand Down Expand Up @@ -1243,6 +1308,12 @@ async def preproc_user_input(self, inp):
return

if self.commands.is_command(inp):
if inp[0] in "!":
inp = f"/run {inp[1:]}"

if self.commands.is_run_command(inp):
self.commands.cmd_running = True

return await self.commands.run(inp)

await self.check_for_file_mentions(inp)
Expand All @@ -1254,8 +1325,6 @@ async def run_one(self, user_message, preproc):
self.init_before_message()

if preproc:
if user_message[0] in "!":
user_message = f"/run {user_message[1:]}"
message = await self.preproc_user_input(user_message)
else:
message = user_message
Expand Down
88 changes: 51 additions & 37 deletions aider/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def __init__(

# Store the original read-only filenames provided via args.read
self.original_read_only_fnames = set(original_read_only_fnames or [])
self.cmd_running = False

def cmd_model(self, args):
"Switch the Main Model to a new LLM"
Expand Down Expand Up @@ -256,6 +257,9 @@ async def cmd_web(self, args, return_content=False):
def is_command(self, inp):
return inp[0] in "/!"

def is_run_command(self, inp):
return inp and (inp[0] in "!" or inp[:5] == "/test" or inp[:4] == "/run")

def get_raw_completions(self, cmd):
assert cmd.startswith("/")
cmd = cmd[1:]
Expand Down Expand Up @@ -1151,51 +1155,61 @@ async def cmd_test(self, args):

async def cmd_run(self, args, add_on_nonzero_exit=False):
"Run a shell command and optionally add the output to the chat (alias: !)"
exit_status, combined_output = await asyncio.to_thread(
run_cmd,
args,
verbose=self.verbose,
error_print=self.io.tool_error,
cwd=self.coder.root,
)
try:
self.cmd_running = True
exit_status, combined_output = await asyncio.to_thread(
run_cmd,
args,
verbose=self.verbose,
error_print=self.io.tool_error,
cwd=self.coder.root,
)
self.cmd_running = False

if combined_output is None:
return
# This print statement, for whatever reason,
# allows the thread to properly yield control of the terminal
# to the main program
print("")

# Calculate token count of output
token_count = self.coder.main_model.token_count(combined_output)
k_tokens = token_count / 1000
if combined_output is None:
return

if add_on_nonzero_exit:
add = exit_status != 0
else:
add = await self.io.confirm_ask(
f"Add {k_tokens:.1f}k tokens of command output to the chat?"
)
# Calculate token count of output
token_count = self.coder.main_model.token_count(combined_output)
k_tokens = token_count / 1000

if add:
num_lines = len(combined_output.strip().splitlines())
line_plural = "line" if num_lines == 1 else "lines"
self.io.tool_output(f"Added {num_lines} {line_plural} of output to the chat.")
if add_on_nonzero_exit:
add = exit_status != 0
else:
add = await self.io.confirm_ask(
f"Add {k_tokens:.1f}k tokens of command output to the chat?"
)

msg = prompts.run_output.format(
command=args,
output=combined_output,
)
if add:
num_lines = len(combined_output.strip().splitlines())
line_plural = "line" if num_lines == 1 else "lines"
self.io.tool_output(f"Added {num_lines} {line_plural} of output to the chat.")

self.coder.cur_messages += [
dict(role="user", content=msg),
dict(role="assistant", content="Ok."),
]
msg = prompts.run_output.format(
command=args,
output=combined_output,
)

self.coder.cur_messages += [
dict(role="user", content=msg),
dict(role="assistant", content="Ok."),
]

if add_on_nonzero_exit and exit_status != 0:
# Return the formatted output message for test failures
return msg
elif add and exit_status != 0:
self.io.placeholder = "What's wrong? Fix"
if add_on_nonzero_exit and exit_status != 0:
# Return the formatted output message for test failures
return msg
elif add and exit_status != 0:
self.io.placeholder = "What's wrong? Fix"

# Return None if output wasn't added or command succeeded
return None
# Return None if output wasn't added or command succeeded
return None
finally:
self.cmd_running = False

def cmd_exit(self, args):
"Exit the application"
Expand Down
Loading
Loading