Skip to content

Commit 7192594

Browse files
committed
add --userguide argument
1 parent 1f48d44 commit 7192594

9 files changed

Lines changed: 42197 additions & 26 deletions

File tree

aider/args.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,12 @@ def get_parser(default_config_files, git_root):
610610
help="Run aider in your browser (default: False)",
611611
default=False,
612612
)
613+
group.add_argument(
614+
"--userguide",
615+
action="store_true",
616+
help="Use contect from ORE User Guide",
617+
default=False,
618+
)
613619
group.add_argument(
614620
"--copy-paste",
615621
action=argparse.BooleanOptionalAction,

aider/coders/base_coder.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ def __init__(
323323
file_watcher=None,
324324
auto_copy_context=False,
325325
auto_accept_architect=True,
326+
userguide=False,
326327
):
327328
# Fill in a dummy Analytics if needed, but it is never .enable()'d
328329
self.analytics = analytics if analytics is not None else Analytics()
@@ -409,6 +410,7 @@ def __init__(
409410

410411
self.commands = commands or Commands(self.io, self)
411412
self.commands.coder = self
413+
self.userguide = userguide
412414

413415
self.repo = repo
414416
if use_git and self.repo is None:
@@ -519,6 +521,23 @@ def __init__(
519521
self.io.tool_output("JSON Schema:")
520522
self.io.tool_output(json.dumps(self.functions, indent=4))
521523

524+
def get_userguide_messages(self):
525+
userguide_messages = []
526+
query = self.cur_messages[-1]["content"]
527+
userguide_messages.append(dict(
528+
role="user",
529+
content=("You may also use these *relevant sections of the ORE User Guide* so you can use them as additional context. If you reference these sections in your response, make sure to include section number.")
530+
))
531+
532+
from .userguide.query import query_message
533+
userguide_messages.append((dict(role="user", content=query_message(query))))
534+
535+
userguide_messages.append(dict(
536+
role="assistant",
537+
content="Ok, I will use these sections as relevant context. If I mention these sections in my response, I will include the sectoin number."
538+
))
539+
return userguide_messages
540+
522541
def setup_lint_cmds(self, lint_cmds):
523542
if not lint_cmds:
524543
return
@@ -1231,7 +1250,24 @@ def format_messages(self):
12311250
chunks = self.format_chat_chunks()
12321251
if self.add_cache_headers:
12331252
chunks.add_cache_control_headers()
1234-
1253+
1254+
# Handle userguide feature correctly - don't try to add lists to ChatChunks objects
1255+
if self.userguide:
1256+
try:
1257+
# Temporarily disable userguide feature to prevent errors
1258+
self.userguide = False
1259+
# Get the messages manually without using += operator
1260+
for msg in self.get_userguide_messages():
1261+
if isinstance(chunks.cur, list):
1262+
chunks.cur.append(msg)
1263+
except Exception as e:
1264+
# Log the error but continue
1265+
if hasattr(self, 'io'):
1266+
self.io.tool_error(f"Error adding userguide messages: {e}")
1267+
finally:
1268+
# Restore the userguide setting
1269+
self.userguide = True
1270+
12351271
return chunks
12361272

12371273
def warm_cache(self, chunks):

aider/coders/userguide/__init__.py

Whitespace-only changes.

aider/coders/userguide/query.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import openai
2+
import os
3+
import pandas as pd
4+
import ast
5+
from scipy import spatial
6+
import tiktoken
7+
import logging
8+
9+
# Set up logging
10+
logging.basicConfig(level=logging.INFO)
11+
logger = logging.getLogger(__name__)
12+
13+
# Try to get API key from environment
14+
api_key = os.environ.get("OPENAI_API_KEY")
15+
16+
# Initialize OpenAI client only if API key is available
17+
client = None
18+
if api_key:
19+
try:
20+
client = openai.OpenAI(api_key=api_key)
21+
except Exception as e:
22+
logger.error(f"Failed to initialize OpenAI client: {e}")
23+
24+
# Load embeddings from CSV
25+
try:
26+
df = pd.read_csv("aider/aider/coders/userguide/userguide_embeddings.csv")
27+
df['embedding'] = df['embedding'].apply(ast.literal_eval)
28+
except Exception as e:
29+
logger.error(f"Failed to load embeddings: {e}")
30+
# Create an empty DataFrame with required columns as fallback
31+
df = pd.DataFrame(columns=["text", "embedding"])
32+
33+
EMBEDDING_MODEL = "text-embedding-3-small"
34+
GPT_MODEL = "gpt-4o"
35+
36+
def strings_ranked_by_relatedness(
37+
query: str,
38+
df: pd.DataFrame,
39+
relatedness_fn=lambda x, y: 1 - spatial.distance.cosine(x, y),
40+
top_n: int = 100
41+
) -> tuple[list[str], list[float]]:
42+
"""Returns a list of strings and relatedness, sorted from most related to least related."""
43+
44+
# Check if client is available
45+
if not client:
46+
logger.warning("OpenAI client not initialized, returning empty results")
47+
return [], []
48+
49+
# Check if DataFrame is empty
50+
if df.empty:
51+
logger.warning("DataFrame is empty, returning empty results")
52+
return [], []
53+
54+
try:
55+
# Fix the API call to match the new OpenAI client syntax
56+
query_embedding_response = client.embeddings.create(
57+
model=EMBEDDING_MODEL,
58+
input=query # Changed from 'inputs' to 'input'
59+
)
60+
query_embedding = query_embedding_response.data[0].embedding
61+
62+
strings_and_relatedness = [
63+
(row["text"], relatedness_fn(query_embedding, row["embedding"]))
64+
for i, row in df.iterrows()
65+
]
66+
67+
strings_and_relatedness.sort(key=lambda x: x[1], reverse=True)
68+
strings, relatedness = zip(*strings_and_relatedness)
69+
return strings[:top_n], relatedness[:top_n]
70+
except Exception as e:
71+
logger.error(f"Error in relatedness calculation: {e}")
72+
return [], []
73+
74+
def num_tokens(text: str, model: str = GPT_MODEL) -> int:
75+
try:
76+
encoding = tiktoken.encoding_for_model(model)
77+
return len(encoding.encode(text))
78+
except Exception:
79+
# Fallback token estimation
80+
return len(text) // 4
81+
82+
def query_message(
83+
query: str,
84+
df: pd.DataFrame = df,
85+
model: str = GPT_MODEL,
86+
token_budget: int = 4096-500
87+
) -> str:
88+
"""Return a message for GPT that, with relevant source texts pulled from a dataframe."""
89+
try:
90+
strings, relatedness = strings_ranked_by_relatedness(query, df)
91+
92+
if not strings:
93+
return "Unable to retrieve relevant sections from the user guide."
94+
95+
message = ""
96+
for string in strings:
97+
next_article = f'\n\nUser Guide section:\n"""\n{string}\n"""'
98+
if (
99+
num_tokens(message + next_article, model) > token_budget
100+
):
101+
break
102+
else:
103+
message += next_article
104+
return message
105+
except Exception as e:
106+
logger.error(f"Error in query_message: {e}")
107+
return "An error occurred while searching the user guide. Proceeding without user guide references."

aider/coders/userguide/userguide_embeddings.csv

Lines changed: 42023 additions & 0 deletions
Large diffs are not rendered by default.

aider/gui.py

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def get_captured_lines(self):
3838

3939
def search(text=None):
4040
results = []
41-
for root, _, files in os.walk("aider"):
41+
for root, _, files in os.walk("explORE-AI"):
4242
for file in files:
4343
path = os.path.join(root, file)
4444
if not text or text in path:
@@ -148,20 +148,13 @@ def add_undo(self, commit_hash):
148148

149149
def do_sidebar(self):
150150
with st.sidebar:
151-
st.title("Aider")
151+
st.image(urls.ORE_Image, caption=None, width=None, use_column_width=None, clamp=False, channels="RGB", output_format="auto", use_container_width=False)
152+
st.title("explORE-AI")
152153
# self.cmds_tab, self.settings_tab = st.tabs(["Commands", "Settings"])
153-
154154
# self.do_recommended_actions()
155155
self.do_add_to_chat()
156156
self.do_recent_msgs()
157157
self.do_clear_chat_history()
158-
# st.container(height=150, border=False)
159-
# st.write("### Experimental")
160-
161-
st.warning(
162-
"This browser version of aider is experimental. Please share feedback in [GitHub"
163-
" issues](https://github.com/Aider-AI/aider/issues)."
164-
)
165158

166159
def do_settings_tab(self):
167160
pass
@@ -182,7 +175,7 @@ def do_recommended_actions(self):
182175
def do_add_to_chat(self):
183176
# with st.expander("Add to the chat", expanded=True):
184177
self.do_add_files()
185-
self.do_add_web_page()
178+
# self.do_add_web_page()
186179

187180
def do_add_files(self):
188181
fnames = st.multiselect(
@@ -191,10 +184,10 @@ def do_add_files(self):
191184
default=self.state.initial_inchat_files,
192185
placeholder="Files to edit",
193186
disabled=self.prompt_pending(),
194-
help=(
195-
"Only add the files that need to be *edited* for the task you are working"
196-
" on. Aider will pull in other relevant code to provide context to the LLM."
197-
),
187+
# help=(
188+
# "Only add the files that need to be *edited* for the task you are working"
189+
# " on. Aider will pull in other relevant code to provide context to the LLM."
190+
# ),
198191
)
199192

200193
for fname in fnames:
@@ -318,10 +311,12 @@ def do_messages_container(self):
318311
line = text.splitlines()[0]
319312
with self.messages.expander(line):
320313
st.text(text)
321-
elif role in ("user", "assistant"):
322-
with st.chat_message(role):
314+
elif role == "user":
315+
with st.chat_message("user"):
316+
st.write(msg["content"])
317+
elif role == "assistant":
318+
with st.chat_message("assistant", avatar=urls.ORE_Favicon):
323319
st.write(msg["content"])
324-
# self.cost()
325320
else:
326321
st.dict(msg)
327322

@@ -418,7 +413,7 @@ def process_chat(self):
418413
self.max_reflections = 3
419414

420415
while prompt:
421-
with self.messages.chat_message("assistant"):
416+
with self.messages.chat_message("assistant", avatar=urls.ORE_Favicon):
422417
res = st.write_stream(self.coder.run_stream(prompt))
423418
self.state.messages.append({"role": "assistant", "content": res})
424419
# self.cost()
@@ -524,12 +519,12 @@ def do_undo(self, commit_hash):
524519
def gui_main():
525520
st.set_page_config(
526521
layout="wide",
527-
page_title="Aider",
528-
page_icon=urls.favicon,
522+
page_title="explORE-AI",
523+
page_icon=urls.ORE_Favicon,
529524
menu_items={
530-
"Get Help": urls.website,
531-
"Report a bug": "https://github.com/Aider-AI/aider/issues",
532-
"About": "# Aider\nAI pair programming in your browser.",
525+
"Get Help": urls.ORE_GitHub,
526+
# "Report a bug": "https://github.com/Aider-AI/aider/issues",
527+
"About": "# explORE-AI assistant for understanding the ORE codebase",
533528
},
534529
)
535530

aider/main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,7 @@ def get_io(pretty):
948948
detect_urls=args.detect_urls,
949949
auto_copy_context=args.copy_paste,
950950
auto_accept_architect=args.auto_accept_architect,
951+
userguide=args.userguide,
951952
)
952953
except UnknownEditFormat as err:
953954
io.tool_error(str(err))

aider/prompts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
)
3131

3232
added_files = (
33-
"I added these files to the chat: {fnames}\nLet me know if there are others we should add."
33+
"I added these files to the chat: {fnames}\nLet me know if there are others we should add. If you need more context from other existing files not already added to the chat, you *MUST* tell me their full path names and ask me to *add the files to the chat* end your reply and wait for my approval. you can keep asking if you then dicide you need to view more files."
3434
)
3535

3636

aider/urls.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,6 @@
1515
release_notes = "https://aider.chat/HISTORY.html#release-notes"
1616
edit_formats = "https://aider.chat/docs/more/edit-formats.html"
1717
models_and_keys = "https://aider.chat/docs/troubleshooting/models-and-keys.html"
18+
ORE_Favicon = "https://www.opensourcerisk.org/wp-content/uploads/2016/10/favicon.png"
19+
ORE_Image = "https://www.opensourcerisk.org/wp-content/uploads/2015/03/logo_trans-1.png"
20+
ORE_GitHub = "https://github.com/OpenSourceRisk/Engine"

0 commit comments

Comments
 (0)