Merge pull request #631 from daniel-vainsencher/dvf_llm_log

This commit is contained in:
paul-gauthier 2024-06-17 13:58:46 -07:00 committed by GitHub
commit a596a32290
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 52 additions and 12 deletions

View file

@ -21,11 +21,17 @@ def get_parser(default_config_files, git_root):
auto_env_var_prefix="AIDER_",
)
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(
"files",
metavar="FILE",
nargs="*",
help="files to edit with an LLM (optional)",
help="files to edit with an LLM (optional)"
)
group.add_argument(
"--openai-api-key",

View file

@ -1,5 +1,6 @@
#!/usr/bin/env python
import datetime
import hashlib
import json
import os
@ -27,7 +28,7 @@ from aider.mdstream import MarkdownStream
from aider.repo import GitRepo
from aider.repomap import RepoMap
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
@ -783,6 +784,8 @@ class Coder:
messages = self.format_messages()
self.io.log_llm_history("TO LLM", format_messages(messages))
if self.verbose:
utils.show_messages(messages, functions=self.functions)
@ -805,6 +808,9 @@ class Coder:
exhausted = True
else:
raise err
except Exception as err:
self.io.tool_error(f"Unexpected error: {err}")
return
if exhausted:
self.show_exhausted_error()
@ -824,6 +830,8 @@ class Coder:
self.io.tool_output()
self.io.log_llm_history("LLM RESPONSE", format_content("ASSISTANT", content))
if interrupted:
content += "\n^C KeyboardInterrupt"
self.cur_messages += [dict(role="assistant", content=content)]

View file

@ -107,6 +107,7 @@ class InputOutput:
tool_error_color="red",
encoding="utf-8",
dry_run=False,
llm_history_file=None,
editingmode=EditingMode.EMACS,
):
self.editingmode = editingmode
@ -128,6 +129,7 @@ class InputOutput:
self.yes = yes
self.input_history_file = input_history_file
self.llm_history_file = llm_history_file
if chat_history_file is not None:
self.chat_history_file = Path(chat_history_file)
else:
@ -209,10 +211,11 @@ class InputOutput:
else:
style = None
while True:
completer_instance = AutoCompleter(
root, rel_fnames, addable_rel_fnames, commands, self.encoding
)
while True:
if multiline_input:
show = ". "
@ -271,6 +274,14 @@ class InputOutput:
fh = FileHistory(self.input_history_file)
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):
if not log_only:
style = dict(style=self.user_input_color) if self.user_input_color else dict()

View file

@ -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,
dry_run=args.dry_run,
encoding=args.encoding,
llm_history_file=args.llm_history_file,
editingmode=editing_mode,
)

View file

@ -84,24 +84,38 @@ def safe_abs_path(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:
print(title.upper(), "*" * 50)
output.append(f"{title.upper()} {'*' * 50}")
for msg in messages:
print()
output.append("")
role = msg["role"].upper()
content = msg.get("content")
if isinstance(content, list): # Handle list content (e.g., image messages)
for item in content:
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
for line in content.splitlines():
print(role, line)
output.append(format_content(role, content))
content = msg.get("function_call")
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:
dump(functions)