Skip to content

Commit 0bea506

Browse files
improving researcher
1 parent f503f34 commit 0bea506

File tree

5 files changed

+45
-18
lines changed

5 files changed

+45
-18
lines changed

manager.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from src.tools.tools_project_manager import add_task, modify_task, finish_project_planning, reorder_tasks
2020
from src.tools.tools_coder_pipeline import prepare_list_dir_tool, prepare_see_file_tool, ask_human_tool, retrieve_files_by_semantic_query
2121
from src.tools.rag.index_file_descriptions import prompt_index_project_files
22-
from src.utilities.util_functions import save_state_history_to_disk
22+
from src.utilities.util_functions import save_state_history_to_disk, join_paths
2323
from src.utilities.manager_utils import (
2424
actualize_tasks_list_and_progress_description,
2525
setup_todoist_project_if_needed,
@@ -32,7 +32,6 @@
3232
no_tools_msg,
3333
)
3434
from src.utilities.start_project_functions import set_up_dot_clean_coder_dir
35-
from src.utilities.util_functions import join_paths
3635
from src.utilities.llms import init_llms_medium_intelligence
3736
from src.utilities.print_formatters import print_formatted
3837
from src.tools.rag.retrieval import vdb_available

single_task_coder.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,11 @@
2626
use_frontend_feedback = bool(os.getenv("FRONTEND_URL"))
2727

2828

29-
def run_clean_coder_pipeline(task: str, work_dir: str, doc_harvest: bool = False):
30-
researcher = Researcher()
29+
def run_clean_coder_pipeline(task: str, work_dir: str, task_id: str=None):
30+
researcher = Researcher(task_id=task_id)
3131
files, image_paths = researcher.research_task(task)
32-
# documentation = None
33-
# if doc_harvest:
34-
# harvester = Doc_harvester()
35-
# documentation = harvester.find_documentation(task, work_dir)
3632

37-
plan = planning(task, files, image_paths, work_dir) #, documentation=documentation)
33+
plan = planning(task, files, image_paths, work_dir)
3834

3935
executor = Executor(files, work_dir)
4036

src/agents/researcher_agent.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@
1111
retrieve_files_by_semantic_query,
1212
)
1313
from src.tools.rag.retrieval import vdb_available
14-
from src.utilities.util_functions import list_directory_tree, read_coderrules, load_prompt
14+
from src.utilities.util_functions import (
15+
list_directory_tree,
16+
read_coderrules,
17+
load_prompt,
18+
save_state_history_to_disk,
19+
load_state_history_from_disk,
20+
join_paths,
21+
)
1522
from src.utilities.langgraph_common_functions import (
1623
call_model,
1724
call_tool,
@@ -21,7 +28,7 @@
2128
)
2229
from src.utilities.print_formatters import print_formatted
2330
from src.utilities.llms import init_llms_medium_intelligence
24-
from src.utilities.util_functions import save_state_history_to_disk
31+
2532
import os
2633

2734

@@ -63,6 +70,12 @@ def __init__(self, silent=False, task_id=None):
6370
if vdb_available():
6471
self.tools.append(retrieve_files_by_semantic_query)
6572
self.llms = init_llms_medium_intelligence(self.tools, "Researcher")
73+
# Try to load previous research session for this task (if any)
74+
self.prev_messages: List[BaseMessage] = []
75+
if task_id:
76+
history_file = join_paths(work_dir, ".clean_coder", f"research_history_task_{task_id}.json")
77+
if os.path.exists(history_file):
78+
self.prev_messages = load_state_history_from_disk(history_file)
6679

6780
# workflow definition
6881
researcher_workflow = StateGraph(AgentState)
@@ -117,10 +130,16 @@ def research_task(self, task):
117130
print_formatted("👋 Hey! I'm looking for files on which we will work on together!", color="light_blue")
118131

119132
system_prompt_template = load_prompt("researcher_system")
120-
system_message = system_prompt_template.format(task=task, project_rules=read_coderrules())
121-
inputs = {
122-
"messages": [SystemMessage(content=system_message), HumanMessage(content=list_directory_tree(work_dir))]
123-
}
133+
system_message = SystemMessage(
134+
content=system_prompt_template.format(task=task, project_rules=read_coderrules())
135+
)
136+
137+
# Continue previous dialogue if available; otherwise start fresh
138+
if self.prev_messages:
139+
messages = [system_message] + self.prev_messages
140+
else:
141+
messages = [system_message, HumanMessage(content=list_directory_tree(work_dir))]
142+
inputs = {"messages": messages}
124143
researcher_response = self.researcher.invoke(inputs, {"recursion_limit": 100})["messages"][-3]
125144
response_args = researcher_response.tool_calls[0]["args"]
126145
text_files = set(CodeFile(f) for f in response_args["files_to_work_on"] + response_args["reference_files"])

src/tools/tools_project_manager.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,14 @@ def finish_project_planning(dummy: Annotated[str, "Type 'ok' to proceed."]):
135135
# Start background research of second task if available and not researched yet
136136
if len(tasks) >= 2:
137137
second_task = tasks[1]
138-
if "<researched_files>" not in second_task.description:
138+
history_file = join_paths(work_dir, ".clean_coder", f"research_history_task_{second_task.id}.json")
139+
if not os.path.exists(history_file):
139140
background_executor.submit(research_second_task, second_task)
140141

141142
# Execute the main pipeline to implement the task
142143
print_formatted("Asked programmer to execute task:", color="light_blue")
143144
print_text_snippet(first_task.description, title=first_task.content)
144-
run_clean_coder_pipeline(task_name_description, work_dir)
145+
run_clean_coder_pipeline(task_name_description, work_dir, task_id=first_task.id)
145146

146147
actualize_progress_description_file(task_name_description)
147148

src/utilities/util_functions.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from dotenv import load_dotenv, find_dotenv
77
from todoist_api_python.api import TodoistAPI
88
from langchain_core.messages import HumanMessage, ToolMessage
9-
from langchain_core.load import dumps
9+
from langchain_core.load import dumps, loads
1010
import json
1111
import click
1212

@@ -257,5 +257,17 @@ def save_state_history_to_disk(state, messages_path):
257257
json.dump(messages_string, f)
258258

259259

260+
def load_state_history_from_disk(messages_path):
261+
"""Read messages saved by `save_state_history_to_disk` and recreate them.
262+
263+
Returns an empty list when file does not exist.
264+
"""
265+
if not os.path.exists(messages_path):
266+
return []
267+
with open(messages_path, "r") as f:
268+
messages_string = json.load(f)
269+
return loads(messages_string)
270+
271+
260272
if __name__ == "__main__":
261273
print(list_directory_tree(Work.dir()))

0 commit comments

Comments
 (0)