mirror of
https://github.com/Aider-AI/aider.git
synced 2025-05-24 22:34:59 +00:00
Merge pull request #631 from daniel-vainsencher/dvf_llm_log
This commit is contained in:
commit
a596a32290
5 changed files with 52 additions and 12 deletions
|
@ -21,11 +21,17 @@ def get_parser(default_config_files, git_root):
|
||||||
auto_env_var_prefix="AIDER_",
|
auto_env_var_prefix="AIDER_",
|
||||||
)
|
)
|
||||||
group = parser.add_argument_group("Main")
|
group = parser.add_argument_group("Main")
|
||||||
|
group.add_argument(
|
||||||
|
"--llm-history-file",
|
||||||
|
metavar="LLM_HISTORY_FILE",
|
||||||
|
default=None,
|
||||||
|
help="Log the conversation with the LLM to this file (for example, .aider.llm.history)",
|
||||||
|
)
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
"files",
|
"files",
|
||||||
metavar="FILE",
|
metavar="FILE",
|
||||||
nargs="*",
|
nargs="*",
|
||||||
help="files to edit with an LLM (optional)",
|
help="files to edit with an LLM (optional)"
|
||||||
)
|
)
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
"--openai-api-key",
|
"--openai-api-key",
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import datetime
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
@ -27,7 +28,7 @@ from aider.mdstream import MarkdownStream
|
||||||
from aider.repo import GitRepo
|
from aider.repo import GitRepo
|
||||||
from aider.repomap import RepoMap
|
from aider.repomap import RepoMap
|
||||||
from aider.sendchat import send_with_retries
|
from aider.sendchat import send_with_retries
|
||||||
from aider.utils import is_image_file
|
from aider.utils import is_image_file, format_messages, format_content
|
||||||
|
|
||||||
from ..dump import dump # noqa: F401
|
from ..dump import dump # noqa: F401
|
||||||
|
|
||||||
|
@ -783,6 +784,8 @@ class Coder:
|
||||||
|
|
||||||
messages = self.format_messages()
|
messages = self.format_messages()
|
||||||
|
|
||||||
|
self.io.log_llm_history("TO LLM", format_messages(messages))
|
||||||
|
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
utils.show_messages(messages, functions=self.functions)
|
utils.show_messages(messages, functions=self.functions)
|
||||||
|
|
||||||
|
@ -805,6 +808,9 @@ class Coder:
|
||||||
exhausted = True
|
exhausted = True
|
||||||
else:
|
else:
|
||||||
raise err
|
raise err
|
||||||
|
except Exception as err:
|
||||||
|
self.io.tool_error(f"Unexpected error: {err}")
|
||||||
|
return
|
||||||
|
|
||||||
if exhausted:
|
if exhausted:
|
||||||
self.show_exhausted_error()
|
self.show_exhausted_error()
|
||||||
|
@ -824,6 +830,8 @@ class Coder:
|
||||||
|
|
||||||
self.io.tool_output()
|
self.io.tool_output()
|
||||||
|
|
||||||
|
self.io.log_llm_history("LLM RESPONSE", format_content("ASSISTANT", content))
|
||||||
|
|
||||||
if interrupted:
|
if interrupted:
|
||||||
content += "\n^C KeyboardInterrupt"
|
content += "\n^C KeyboardInterrupt"
|
||||||
self.cur_messages += [dict(role="assistant", content=content)]
|
self.cur_messages += [dict(role="assistant", content=content)]
|
||||||
|
|
17
aider/io.py
17
aider/io.py
|
@ -107,6 +107,7 @@ class InputOutput:
|
||||||
tool_error_color="red",
|
tool_error_color="red",
|
||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
dry_run=False,
|
dry_run=False,
|
||||||
|
llm_history_file=None,
|
||||||
editingmode=EditingMode.EMACS,
|
editingmode=EditingMode.EMACS,
|
||||||
):
|
):
|
||||||
self.editingmode = editingmode
|
self.editingmode = editingmode
|
||||||
|
@ -128,6 +129,7 @@ class InputOutput:
|
||||||
self.yes = yes
|
self.yes = yes
|
||||||
|
|
||||||
self.input_history_file = input_history_file
|
self.input_history_file = input_history_file
|
||||||
|
self.llm_history_file = llm_history_file
|
||||||
if chat_history_file is not None:
|
if chat_history_file is not None:
|
||||||
self.chat_history_file = Path(chat_history_file)
|
self.chat_history_file = Path(chat_history_file)
|
||||||
else:
|
else:
|
||||||
|
@ -209,10 +211,11 @@ class InputOutput:
|
||||||
else:
|
else:
|
||||||
style = None
|
style = None
|
||||||
|
|
||||||
|
completer_instance = AutoCompleter(
|
||||||
|
root, rel_fnames, addable_rel_fnames, commands, self.encoding
|
||||||
|
)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
completer_instance = AutoCompleter(
|
|
||||||
root, rel_fnames, addable_rel_fnames, commands, self.encoding
|
|
||||||
)
|
|
||||||
if multiline_input:
|
if multiline_input:
|
||||||
show = ". "
|
show = ". "
|
||||||
|
|
||||||
|
@ -271,6 +274,14 @@ class InputOutput:
|
||||||
fh = FileHistory(self.input_history_file)
|
fh = FileHistory(self.input_history_file)
|
||||||
return fh.load_history_strings()
|
return fh.load_history_strings()
|
||||||
|
|
||||||
|
def log_llm_history(self, role, content):
|
||||||
|
if not self.llm_history_file:
|
||||||
|
return
|
||||||
|
timestamp = datetime.now().isoformat(timespec='seconds')
|
||||||
|
with open(self.llm_history_file, 'a', encoding=self.encoding) as log_file:
|
||||||
|
log_file.write(f"{role.upper()} {timestamp}\n")
|
||||||
|
log_file.write(content + "\n")
|
||||||
|
|
||||||
def user_input(self, inp, log_only=True):
|
def user_input(self, inp, log_only=True):
|
||||||
if not log_only:
|
if not log_only:
|
||||||
style = dict(style=self.user_input_color) if self.user_input_color else dict()
|
style = dict(style=self.user_input_color) if self.user_input_color else dict()
|
||||||
|
|
|
@ -261,6 +261,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
||||||
tool_error_color=args.tool_error_color,
|
tool_error_color=args.tool_error_color,
|
||||||
dry_run=args.dry_run,
|
dry_run=args.dry_run,
|
||||||
encoding=args.encoding,
|
encoding=args.encoding,
|
||||||
|
llm_history_file=args.llm_history_file,
|
||||||
editingmode=editing_mode,
|
editingmode=editing_mode,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -84,24 +84,38 @@ def safe_abs_path(res):
|
||||||
return str(res)
|
return str(res)
|
||||||
|
|
||||||
|
|
||||||
def show_messages(messages, title=None, functions=None):
|
def format_content(role, content):
|
||||||
|
formatted_lines = []
|
||||||
|
for line in content.splitlines():
|
||||||
|
formatted_lines.append(f"{role} {line}")
|
||||||
|
return "\n".join(formatted_lines)
|
||||||
|
|
||||||
|
|
||||||
|
def format_messages(messages, title=None):
|
||||||
|
output = []
|
||||||
if title:
|
if title:
|
||||||
print(title.upper(), "*" * 50)
|
output.append(f"{title.upper()} {'*' * 50}")
|
||||||
|
|
||||||
for msg in messages:
|
for msg in messages:
|
||||||
print()
|
output.append("")
|
||||||
role = msg["role"].upper()
|
role = msg["role"].upper()
|
||||||
content = msg.get("content")
|
content = msg.get("content")
|
||||||
if isinstance(content, list): # Handle list content (e.g., image messages)
|
if isinstance(content, list): # Handle list content (e.g., image messages)
|
||||||
for item in content:
|
for item in content:
|
||||||
if isinstance(item, dict) and "image_url" in item:
|
if isinstance(item, dict) and "image_url" in item:
|
||||||
print(role, "Image URL:", item["image_url"]["url"])
|
output.append(f"{role} Image URL: {item['image_url']['url']}")
|
||||||
elif isinstance(content, str): # Handle string content
|
elif isinstance(content, str): # Handle string content
|
||||||
for line in content.splitlines():
|
output.append(format_content(role, content))
|
||||||
print(role, line)
|
|
||||||
content = msg.get("function_call")
|
content = msg.get("function_call")
|
||||||
if content:
|
if content:
|
||||||
print(role, content)
|
output.append(f"{role} {content}")
|
||||||
|
|
||||||
|
return "\n".join(output)
|
||||||
|
|
||||||
|
|
||||||
|
def show_messages(messages, title=None, functions=None):
|
||||||
|
formatted_output = format_messages(messages, title)
|
||||||
|
print(formatted_output)
|
||||||
|
|
||||||
if functions:
|
if functions:
|
||||||
dump(functions)
|
dump(functions)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue