deepcode-hku 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cli/__init__.py +18 -0
- cli/cli_app.py +296 -0
- cli/cli_interface.py +744 -0
- cli/cli_launcher.py +155 -0
- cli/main_cli.py +243 -0
- cli/workflows/__init__.py +11 -0
- cli/workflows/cli_workflow_adapter.py +336 -0
- deepcode.py +219 -0
- deepcode_hku-1.0.1.dist-info/METADATA +695 -0
- deepcode_hku-1.0.1.dist-info/RECORD +44 -0
- deepcode_hku-1.0.1.dist-info/WHEEL +5 -0
- deepcode_hku-1.0.1.dist-info/entry_points.txt +2 -0
- deepcode_hku-1.0.1.dist-info/licenses/LICENSE +21 -0
- deepcode_hku-1.0.1.dist-info/top_level.txt +6 -0
- tools/__init__.py +0 -0
- tools/code_implementation_server.py +1045 -0
- tools/code_indexer.py +1657 -0
- tools/code_reference_indexer.py +486 -0
- tools/command_executor.py +324 -0
- tools/git_command.py +356 -0
- tools/pdf_converter.py +640 -0
- tools/pdf_downloader.py +1370 -0
- tools/pdf_utils.py +52 -0
- ui/__init__.py +43 -0
- ui/app.py +13 -0
- ui/components.py +1450 -0
- ui/handlers.py +773 -0
- ui/layout.py +106 -0
- ui/streamlit_app.py +38 -0
- ui/styles.py +2116 -0
- utils/__init__.py +17 -0
- utils/cli_interface.py +459 -0
- utils/dialogue_logger.py +671 -0
- utils/file_processor.py +426 -0
- utils/simple_llm_logger.py +198 -0
- workflows/__init__.py +31 -0
- workflows/agent_orchestration_engine.py +1371 -0
- workflows/agents/__init__.py +13 -0
- workflows/agents/code_implementation_agent.py +1093 -0
- workflows/agents/memory_agent_concise.py +923 -0
- workflows/agents/memory_agent_concise_index.py +935 -0
- workflows/code_implementation_workflow.py +924 -0
- workflows/code_implementation_workflow_index.py +931 -0
- workflows/codebase_index_workflow.py +726 -0
|
@@ -0,0 +1,923 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Concise Memory Agent for Code Implementation Workflow
|
|
3
|
+
简洁的代码实现工作流内存代理
|
|
4
|
+
|
|
5
|
+
This memory agent implements a focused approach:
|
|
6
|
+
1. Before first file: Normal conversation flow
|
|
7
|
+
2. After first file: Keep only system_prompt + initial_plan + current round tool results
|
|
8
|
+
3. Clean slate for each new code file generation
|
|
9
|
+
|
|
10
|
+
Key Features:
|
|
11
|
+
- Preserves system prompt and initial plan always
|
|
12
|
+
- After first file generation, discards previous conversation history
|
|
13
|
+
- Keeps only current round tool results from essential tools:
|
|
14
|
+
* read_code_mem, read_file, write_file
|
|
15
|
+
* execute_python, execute_bash
|
|
16
|
+
* search_code, search_reference_code, get_file_structure
|
|
17
|
+
- Provides clean, focused input for next write_file operation
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import json
|
|
21
|
+
import logging
|
|
22
|
+
import os
|
|
23
|
+
import time
|
|
24
|
+
from datetime import datetime
|
|
25
|
+
from typing import Dict, Any, List, Optional
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ConciseMemoryAgent:
|
|
29
|
+
"""
|
|
30
|
+
Concise Memory Agent - Focused Information Retention
|
|
31
|
+
|
|
32
|
+
Core Philosophy:
|
|
33
|
+
- Preserve essential context (system prompt + initial plan)
|
|
34
|
+
- After first file generation, use clean slate approach
|
|
35
|
+
- Keep only current round tool results from all essential MCP tools
|
|
36
|
+
- Remove conversational clutter and previous tool calls
|
|
37
|
+
|
|
38
|
+
Essential Tools Tracked:
|
|
39
|
+
- File Operations: read_code_mem, read_file, write_file
|
|
40
|
+
- Code Analysis: search_code, search_reference_code, get_file_structure
|
|
41
|
+
- Execution: execute_python, execute_bash
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
initial_plan_content: str,
|
|
47
|
+
logger: Optional[logging.Logger] = None,
|
|
48
|
+
target_directory: Optional[str] = None,
|
|
49
|
+
default_models: Optional[Dict[str, str]] = None,
|
|
50
|
+
):
|
|
51
|
+
"""
|
|
52
|
+
Initialize Concise Memory Agent
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
initial_plan_content: Content of initial_plan.txt
|
|
56
|
+
logger: Logger instance
|
|
57
|
+
target_directory: Target directory for saving summaries
|
|
58
|
+
default_models: Default models configuration from workflow
|
|
59
|
+
"""
|
|
60
|
+
self.logger = logger or self._create_default_logger()
|
|
61
|
+
self.initial_plan = initial_plan_content
|
|
62
|
+
|
|
63
|
+
# Store default models configuration
|
|
64
|
+
self.default_models = default_models or {
|
|
65
|
+
"anthropic": "claude-sonnet-4-20250514",
|
|
66
|
+
"openai": "gpt-4o",
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# Memory state tracking - new logic: trigger after each write_file
|
|
70
|
+
self.last_write_file_detected = (
|
|
71
|
+
False # Track if write_file was called in current iteration
|
|
72
|
+
)
|
|
73
|
+
self.should_clear_memory_next = False # Flag to clear memory in next round
|
|
74
|
+
self.current_round = 0
|
|
75
|
+
|
|
76
|
+
# Parse phase structure from initial plan
|
|
77
|
+
self.phase_structure = self._parse_phase_structure()
|
|
78
|
+
|
|
79
|
+
# Memory configuration
|
|
80
|
+
if target_directory:
|
|
81
|
+
self.save_path = target_directory
|
|
82
|
+
else:
|
|
83
|
+
self.save_path = "./deepcode_lab/papers/1/"
|
|
84
|
+
|
|
85
|
+
# Code summary file path
|
|
86
|
+
self.code_summary_path = os.path.join(
|
|
87
|
+
self.save_path, "implement_code_summary.md"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Current round tool results storage
|
|
91
|
+
self.current_round_tool_results = []
|
|
92
|
+
|
|
93
|
+
# Track all implemented files
|
|
94
|
+
self.implemented_files = []
|
|
95
|
+
|
|
96
|
+
self.logger.info(
|
|
97
|
+
f"Concise Memory Agent initialized with target directory: {self.save_path}"
|
|
98
|
+
)
|
|
99
|
+
self.logger.info(f"Code summary will be saved to: {self.code_summary_path}")
|
|
100
|
+
# self.logger.info(f"🤖 Using models - Anthropic: {self.default_models['anthropic']}, OpenAI: {self.default_models['openai']}")
|
|
101
|
+
self.logger.info(
|
|
102
|
+
"📝 NEW LOGIC: Memory clearing triggered after each write_file call"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def _create_default_logger(self) -> logging.Logger:
|
|
106
|
+
"""Create default logger"""
|
|
107
|
+
logger = logging.getLogger(f"{__name__}.ConciseMemoryAgent")
|
|
108
|
+
logger.setLevel(logging.INFO)
|
|
109
|
+
return logger
|
|
110
|
+
|
|
111
|
+
def _parse_phase_structure(self) -> Dict[str, List[str]]:
|
|
112
|
+
"""Parse implementation phases from initial plan"""
|
|
113
|
+
try:
|
|
114
|
+
phases = {}
|
|
115
|
+
lines = self.initial_plan.split("\n")
|
|
116
|
+
current_phase = None
|
|
117
|
+
|
|
118
|
+
for line in lines:
|
|
119
|
+
if "Phase" in line and ":" in line:
|
|
120
|
+
# Extract phase name
|
|
121
|
+
phase_parts = line.split(":")
|
|
122
|
+
if len(phase_parts) >= 2:
|
|
123
|
+
current_phase = phase_parts[0].strip()
|
|
124
|
+
phases[current_phase] = []
|
|
125
|
+
elif current_phase and line.strip().startswith("-"):
|
|
126
|
+
# This is a file in the current phase
|
|
127
|
+
file_line = line.strip()[1:].strip()
|
|
128
|
+
if file_line.startswith("`") and file_line.endswith("`"):
|
|
129
|
+
file_name = file_line[1:-1]
|
|
130
|
+
phases[current_phase].append(file_name)
|
|
131
|
+
elif current_phase and not line.strip():
|
|
132
|
+
# Empty line might indicate end of phase
|
|
133
|
+
continue
|
|
134
|
+
elif current_phase and line.strip().startswith("###"):
|
|
135
|
+
# New section, end current phase
|
|
136
|
+
current_phase = None
|
|
137
|
+
|
|
138
|
+
return phases
|
|
139
|
+
|
|
140
|
+
except Exception as e:
|
|
141
|
+
self.logger.warning(f"Failed to parse phase structure: {e}")
|
|
142
|
+
return {}
|
|
143
|
+
|
|
144
|
+
def record_file_implementation(
|
|
145
|
+
self, file_path: str, implementation_content: str = ""
|
|
146
|
+
):
|
|
147
|
+
"""
|
|
148
|
+
Record a newly implemented file (simplified version)
|
|
149
|
+
NEW LOGIC: File implementation is tracked via write_file tool detection
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
file_path: Path of the implemented file
|
|
153
|
+
implementation_content: Content of the implemented file
|
|
154
|
+
"""
|
|
155
|
+
# Add file to implemented files list if not already present
|
|
156
|
+
if file_path not in self.implemented_files:
|
|
157
|
+
self.implemented_files.append(file_path)
|
|
158
|
+
|
|
159
|
+
self.logger.info(f"📝 File implementation recorded: {file_path}")
|
|
160
|
+
|
|
161
|
+
async def create_code_implementation_summary(
|
|
162
|
+
self,
|
|
163
|
+
client,
|
|
164
|
+
client_type: str,
|
|
165
|
+
file_path: str,
|
|
166
|
+
implementation_content: str,
|
|
167
|
+
files_implemented: int,
|
|
168
|
+
) -> str:
|
|
169
|
+
"""
|
|
170
|
+
Create LLM-based code implementation summary after writing a file
|
|
171
|
+
Uses LLM to analyze and summarize the implemented code
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
client: LLM client instance
|
|
175
|
+
client_type: Type of LLM client ("anthropic" or "openai")
|
|
176
|
+
file_path: Path of the implemented file
|
|
177
|
+
implementation_content: Content of the implemented file
|
|
178
|
+
files_implemented: Number of files implemented so far
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
LLM-generated formatted code implementation summary
|
|
182
|
+
"""
|
|
183
|
+
try:
|
|
184
|
+
# Record the file implementation first
|
|
185
|
+
self.record_file_implementation(file_path, implementation_content)
|
|
186
|
+
|
|
187
|
+
# Create prompt for LLM summary
|
|
188
|
+
summary_prompt = self._create_code_summary_prompt(
|
|
189
|
+
file_path, implementation_content, files_implemented
|
|
190
|
+
)
|
|
191
|
+
summary_messages = [{"role": "user", "content": summary_prompt}]
|
|
192
|
+
|
|
193
|
+
# Get LLM-generated summary
|
|
194
|
+
llm_response = await self._call_llm_for_summary(
|
|
195
|
+
client, client_type, summary_messages
|
|
196
|
+
)
|
|
197
|
+
llm_summary = llm_response.get("content", "")
|
|
198
|
+
|
|
199
|
+
# Format the summary in the requested structure
|
|
200
|
+
formatted_summary = self._format_code_implementation_summary(
|
|
201
|
+
file_path, llm_summary, files_implemented
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
# Save to implement_code_summary.md (append mode)
|
|
205
|
+
await self._save_code_summary_to_file(formatted_summary, file_path)
|
|
206
|
+
|
|
207
|
+
self.logger.info(f"Created and saved code summary for: {file_path}")
|
|
208
|
+
return formatted_summary
|
|
209
|
+
|
|
210
|
+
except Exception as e:
|
|
211
|
+
self.logger.error(
|
|
212
|
+
f"Failed to create LLM-based code implementation summary: {e}"
|
|
213
|
+
)
|
|
214
|
+
# Fallback to simple summary
|
|
215
|
+
return self._create_fallback_code_summary(
|
|
216
|
+
file_path, implementation_content, files_implemented
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
def _create_code_summary_prompt(
|
|
220
|
+
self, file_path: str, implementation_content: str, files_implemented: int
|
|
221
|
+
) -> str:
|
|
222
|
+
"""
|
|
223
|
+
Create prompt for LLM to generate code implementation summary
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
file_path: Path of the implemented file
|
|
227
|
+
implementation_content: Content of the implemented file
|
|
228
|
+
files_implemented: Number of files implemented so far
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
Prompt for LLM summarization
|
|
232
|
+
"""
|
|
233
|
+
current_round = self.current_round
|
|
234
|
+
|
|
235
|
+
# Create formatted list of implemented files
|
|
236
|
+
implemented_files_list = (
|
|
237
|
+
"\n".join([f"- {file}" for file in self.implemented_files])
|
|
238
|
+
if self.implemented_files
|
|
239
|
+
else "- None yet"
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
prompt = f"""You are an expert code implementation summarizer. Analyze the implemented code file and create a structured summary.
|
|
243
|
+
|
|
244
|
+
**🚨 CRITICAL: The files listed below are ALREADY IMPLEMENTED - DO NOT suggest them in Next Steps! 🚨**
|
|
245
|
+
|
|
246
|
+
**All Previously Implemented Files:**
|
|
247
|
+
{implemented_files_list}
|
|
248
|
+
|
|
249
|
+
**Current Implementation Context:**
|
|
250
|
+
- **File Implemented**: {file_path}
|
|
251
|
+
- **Current Round**: {current_round}
|
|
252
|
+
- **Total Files Implemented**: {files_implemented}
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
**Initial Plan Reference:**
|
|
256
|
+
{self.initial_plan[:]}
|
|
257
|
+
|
|
258
|
+
**Implemented Code Content:**
|
|
259
|
+
```
|
|
260
|
+
{implementation_content[:]}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Required Summary Format:**
|
|
264
|
+
|
|
265
|
+
1. **Status Marker**: Mark the phase and round corresponding to this code file
|
|
266
|
+
Format: Phase {{phase_name}}, Round {{round_number}}
|
|
267
|
+
|
|
268
|
+
2. **Implementation Progress**: List the code file completed in current round and core implementation ideas
|
|
269
|
+
Format: {{file_path}}: {{core implementation ideas}}
|
|
270
|
+
|
|
271
|
+
3. **Dependencies**: According to the File Structure and initial plan, list functions that may be called by other files
|
|
272
|
+
Format: {{file_path}}: Function {{function_name}}: core ideas--{{ideas}}; Required parameters--{{params}}; Return parameters--{{returns}}
|
|
273
|
+
Required packages: {{packages}}
|
|
274
|
+
|
|
275
|
+
4. **Next Steps**: List code files that will be implemented in the next round (EXCLUDE already implemented files)
|
|
276
|
+
Format: Code will be implemented: {{file_path}}; will stay on Phase {{phase}}/ will go to Phase {{next_phase}}
|
|
277
|
+
**WARNING: Do NOT suggest any file from the "All Previously Implemented Files" list above!**
|
|
278
|
+
|
|
279
|
+
**Instructions:**
|
|
280
|
+
- Be precise and concise
|
|
281
|
+
- Focus on function interfaces that other files will need
|
|
282
|
+
- Extract actual function signatures from the code
|
|
283
|
+
- **CRITICAL: For Next Steps, ONLY suggest files that are NOT in the "All Previously Implemented Files" list above**
|
|
284
|
+
- **NEVER suggest implementing a file that is already in the implemented files list**
|
|
285
|
+
- Predict next implementation steps based on the initial plan but exclude already completed files
|
|
286
|
+
- Use the exact format specified above
|
|
287
|
+
|
|
288
|
+
**Summary:**"""
|
|
289
|
+
|
|
290
|
+
return prompt
|
|
291
|
+
|
|
292
|
+
def _format_code_implementation_summary(
|
|
293
|
+
self, file_path: str, llm_summary: str, files_implemented: int
|
|
294
|
+
) -> str:
|
|
295
|
+
"""
|
|
296
|
+
Format the LLM-generated summary into the final structure
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
file_path: Path of the implemented file
|
|
300
|
+
llm_summary: LLM-generated summary content
|
|
301
|
+
files_implemented: Number of files implemented so far
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
Formatted summary
|
|
305
|
+
"""
|
|
306
|
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
307
|
+
|
|
308
|
+
# Create formatted list of implemented files
|
|
309
|
+
implemented_files_list = (
|
|
310
|
+
"\n".join([f"- {file}" for file in self.implemented_files])
|
|
311
|
+
if self.implemented_files
|
|
312
|
+
else "- None yet"
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
formatted_summary = f"""# Code Implementation Summary
|
|
316
|
+
**All Previously Implemented Files:**
|
|
317
|
+
{implemented_files_list}
|
|
318
|
+
**Generated**: {timestamp}
|
|
319
|
+
**File Implemented**: {file_path}
|
|
320
|
+
**Total Files Implemented**: {files_implemented}
|
|
321
|
+
|
|
322
|
+
{llm_summary}
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
*Auto-generated by Memory Agent*
|
|
326
|
+
"""
|
|
327
|
+
return formatted_summary
|
|
328
|
+
|
|
329
|
+
def _create_fallback_code_summary(
|
|
330
|
+
self, file_path: str, implementation_content: str, files_implemented: int
|
|
331
|
+
) -> str:
|
|
332
|
+
"""
|
|
333
|
+
Create fallback summary when LLM is unavailable
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
file_path: Path of the implemented file
|
|
337
|
+
implementation_content: Content of the implemented file
|
|
338
|
+
files_implemented: Number of files implemented so far
|
|
339
|
+
|
|
340
|
+
Returns:
|
|
341
|
+
Fallback summary
|
|
342
|
+
"""
|
|
343
|
+
# Create formatted list of implemented files
|
|
344
|
+
implemented_files_list = (
|
|
345
|
+
"\n".join([f"- {file}" for file in self.implemented_files])
|
|
346
|
+
if self.implemented_files
|
|
347
|
+
else "- None yet"
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
summary = f"""# Code Implementation Summary
|
|
351
|
+
**All Previously Implemented Files:**
|
|
352
|
+
{implemented_files_list}
|
|
353
|
+
**Generated**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
|
354
|
+
**File Implemented**: {file_path}
|
|
355
|
+
**Total Files Implemented**: {files_implemented}
|
|
356
|
+
**Summary failed to generate.**
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
*Auto-generated by Concise Memory Agent (Fallback Mode)*
|
|
360
|
+
"""
|
|
361
|
+
return summary
|
|
362
|
+
|
|
363
|
+
async def _save_code_summary_to_file(self, new_summary: str, file_path: str):
|
|
364
|
+
"""
|
|
365
|
+
Append code implementation summary to implement_code_summary.md
|
|
366
|
+
Accumulates all implementations with clear separators
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
new_summary: New summary content to append
|
|
370
|
+
file_path: Path of the file for which the summary was generated
|
|
371
|
+
"""
|
|
372
|
+
try:
|
|
373
|
+
# Create directory if it doesn't exist
|
|
374
|
+
os.makedirs(os.path.dirname(self.code_summary_path), exist_ok=True)
|
|
375
|
+
|
|
376
|
+
# Check if file exists to determine if we need header
|
|
377
|
+
file_exists = os.path.exists(self.code_summary_path)
|
|
378
|
+
|
|
379
|
+
# Open in append mode to accumulate all implementations
|
|
380
|
+
with open(self.code_summary_path, "a", encoding="utf-8") as f:
|
|
381
|
+
if not file_exists:
|
|
382
|
+
# Write header for new file
|
|
383
|
+
f.write("# Code Implementation Progress Summary\n")
|
|
384
|
+
f.write("*Accumulated implementation progress for all files*\n\n")
|
|
385
|
+
|
|
386
|
+
# Add clear separator between implementations
|
|
387
|
+
f.write("\n" + "=" * 80 + "\n")
|
|
388
|
+
f.write(
|
|
389
|
+
f"## IMPLEMENTATION File {file_path}; ROUND {self.current_round} \n"
|
|
390
|
+
)
|
|
391
|
+
f.write("=" * 80 + "\n\n")
|
|
392
|
+
|
|
393
|
+
# Write the new summary
|
|
394
|
+
f.write(new_summary)
|
|
395
|
+
f.write("\n\n")
|
|
396
|
+
|
|
397
|
+
self.logger.info(
|
|
398
|
+
f"Appended LLM-based code implementation summary to: {self.code_summary_path}"
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
except Exception as e:
|
|
402
|
+
self.logger.error(f"Failed to save code implementation summary: {e}")
|
|
403
|
+
|
|
404
|
+
async def _call_llm_for_summary(
|
|
405
|
+
self, client, client_type: str, summary_messages: List[Dict]
|
|
406
|
+
) -> Dict[str, Any]:
|
|
407
|
+
"""
|
|
408
|
+
Call LLM for code implementation summary generation ONLY
|
|
409
|
+
调用LLM生成代码实现总结(仅用于代码总结)
|
|
410
|
+
|
|
411
|
+
This method is used only for creating code implementation summaries,
|
|
412
|
+
NOT for conversation summarization which has been removed.
|
|
413
|
+
"""
|
|
414
|
+
if client_type == "anthropic":
|
|
415
|
+
response = await client.messages.create(
|
|
416
|
+
model=self.default_models["anthropic"],
|
|
417
|
+
system="You are an expert code implementation summarizer. Create structured summaries of implemented code files that preserve essential information about functions, dependencies, and implementation approaches.",
|
|
418
|
+
messages=summary_messages,
|
|
419
|
+
max_tokens=5000,
|
|
420
|
+
temperature=0.2,
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
content = ""
|
|
424
|
+
for block in response.content:
|
|
425
|
+
if block.type == "text":
|
|
426
|
+
content += block.text
|
|
427
|
+
|
|
428
|
+
return {"content": content}
|
|
429
|
+
|
|
430
|
+
elif client_type == "openai":
|
|
431
|
+
openai_messages = [
|
|
432
|
+
{
|
|
433
|
+
"role": "system",
|
|
434
|
+
"content": "You are an expert code implementation summarizer. Create structured summaries of implemented code files that preserve essential information about functions, dependencies, and implementation approaches.",
|
|
435
|
+
}
|
|
436
|
+
]
|
|
437
|
+
openai_messages.extend(summary_messages)
|
|
438
|
+
|
|
439
|
+
response = await client.chat.completions.create(
|
|
440
|
+
model=self.default_models["openai"],
|
|
441
|
+
messages=openai_messages,
|
|
442
|
+
max_tokens=5000,
|
|
443
|
+
temperature=0.2,
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
return {"content": response.choices[0].message.content or ""}
|
|
447
|
+
|
|
448
|
+
else:
|
|
449
|
+
raise ValueError(f"Unsupported client type: {client_type}")
|
|
450
|
+
|
|
451
|
+
def start_new_round(self, iteration: Optional[int] = None):
|
|
452
|
+
"""Start a new dialogue round and reset tool results
|
|
453
|
+
|
|
454
|
+
Args:
|
|
455
|
+
iteration: Optional iteration number from workflow to sync with current_round
|
|
456
|
+
"""
|
|
457
|
+
if iteration is not None:
|
|
458
|
+
# Sync with workflow iteration
|
|
459
|
+
self.current_round = iteration
|
|
460
|
+
# self.logger.info(f"🔄 Synced round with workflow iteration {iteration}")
|
|
461
|
+
else:
|
|
462
|
+
# Default behavior: increment round counter
|
|
463
|
+
self.current_round += 1
|
|
464
|
+
self.logger.info(f"🔄 Started new round {self.current_round}")
|
|
465
|
+
|
|
466
|
+
self.current_round_tool_results = [] # Clear previous round results
|
|
467
|
+
# Note: Don't reset last_write_file_detected and should_clear_memory_next here
|
|
468
|
+
# These flags persist across rounds until memory optimization is applied
|
|
469
|
+
# self.logger.info(f"🔄 Round {self.current_round} - Tool results cleared, memory flags preserved")
|
|
470
|
+
|
|
471
|
+
def record_tool_result(
|
|
472
|
+
self, tool_name: str, tool_input: Dict[str, Any], tool_result: Any
|
|
473
|
+
):
|
|
474
|
+
"""
|
|
475
|
+
Record tool result for current round and detect write_file calls
|
|
476
|
+
|
|
477
|
+
Args:
|
|
478
|
+
tool_name: Name of the tool called
|
|
479
|
+
tool_input: Input parameters for the tool
|
|
480
|
+
tool_result: Result returned by the tool
|
|
481
|
+
"""
|
|
482
|
+
# Detect write_file calls to trigger memory clearing
|
|
483
|
+
if tool_name == "write_file":
|
|
484
|
+
self.last_write_file_detected = True
|
|
485
|
+
self.should_clear_memory_next = True
|
|
486
|
+
|
|
487
|
+
# self.logger.info(f"🔄 WRITE_FILE DETECTED: {file_path} - Memory will be cleared in next round")
|
|
488
|
+
|
|
489
|
+
# Only record specific tools that provide essential information
|
|
490
|
+
essential_tools = [
|
|
491
|
+
"read_code_mem", # Read code summary from implement_code_summary.md
|
|
492
|
+
"read_file", # Read file contents
|
|
493
|
+
"write_file", # Write file contents (important for tracking implementations)
|
|
494
|
+
"execute_python", # Execute Python code (for testing/validation)
|
|
495
|
+
"execute_bash", # Execute bash commands (for build/execution)
|
|
496
|
+
"search_code", # Search code patterns
|
|
497
|
+
"search_reference_code", # Search reference code (if available)
|
|
498
|
+
"get_file_structure", # Get file structure (for understanding project layout)
|
|
499
|
+
]
|
|
500
|
+
|
|
501
|
+
if tool_name in essential_tools:
|
|
502
|
+
tool_record = {
|
|
503
|
+
"tool_name": tool_name,
|
|
504
|
+
"tool_input": tool_input,
|
|
505
|
+
"tool_result": tool_result,
|
|
506
|
+
"timestamp": time.time(),
|
|
507
|
+
}
|
|
508
|
+
self.current_round_tool_results.append(tool_record)
|
|
509
|
+
# self.logger.info(f"📊 Essential tool result recorded: {tool_name} ({len(self.current_round_tool_results)} total)")
|
|
510
|
+
|
|
511
|
+
def should_use_concise_mode(self) -> bool:
|
|
512
|
+
"""
|
|
513
|
+
Check if concise memory mode should be used
|
|
514
|
+
|
|
515
|
+
Returns:
|
|
516
|
+
True if first file has been generated and concise mode should be active
|
|
517
|
+
"""
|
|
518
|
+
return self.last_write_file_detected
|
|
519
|
+
|
|
520
|
+
def create_concise_messages(
|
|
521
|
+
self, system_prompt: str, messages: List[Dict[str, Any]], files_implemented: int
|
|
522
|
+
) -> List[Dict[str, Any]]:
|
|
523
|
+
"""
|
|
524
|
+
Create concise message list for LLM input
|
|
525
|
+
NEW LOGIC: Always clear after write_file, keep system_prompt + initial_plan + current round tools
|
|
526
|
+
|
|
527
|
+
Args:
|
|
528
|
+
system_prompt: Current system prompt
|
|
529
|
+
messages: Original message list
|
|
530
|
+
files_implemented: Number of files implemented so far
|
|
531
|
+
|
|
532
|
+
Returns:
|
|
533
|
+
Concise message list containing only essential information
|
|
534
|
+
"""
|
|
535
|
+
if not self.last_write_file_detected:
|
|
536
|
+
# Before any write_file, use normal flow
|
|
537
|
+
self.logger.info(
|
|
538
|
+
"🔄 Using normal conversation flow (before any write_file)"
|
|
539
|
+
)
|
|
540
|
+
return messages
|
|
541
|
+
|
|
542
|
+
# After write_file detection, use concise approach with clean slate
|
|
543
|
+
self.logger.info(
|
|
544
|
+
f"🎯 Using CONCISE memory mode - Clear slate after write_file, Round {self.current_round}"
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
concise_messages = []
|
|
548
|
+
|
|
549
|
+
# 1. Add initial plan message (always preserved)
|
|
550
|
+
initial_plan_message = {
|
|
551
|
+
"role": "user",
|
|
552
|
+
"content": f"""**Task: Implement code based on the following reproduction plan**
|
|
553
|
+
|
|
554
|
+
**Code Reproduction Plan:**
|
|
555
|
+
{self.initial_plan}
|
|
556
|
+
|
|
557
|
+
**Working Directory:** Current workspace
|
|
558
|
+
|
|
559
|
+
**Current Status:** {files_implemented} files implemented
|
|
560
|
+
|
|
561
|
+
**Objective:** Continue implementation by analyzing dependencies and implementing the next required file according to the plan's priority order.""",
|
|
562
|
+
}
|
|
563
|
+
concise_messages.append(initial_plan_message)
|
|
564
|
+
|
|
565
|
+
# 2. Add Knowledge Base
|
|
566
|
+
knowledge_base_message = {
|
|
567
|
+
"role": "user",
|
|
568
|
+
"content": f"""**Below is the Knowledge Base of the LATEST implemented code file:**
|
|
569
|
+
{self._read_code_knowledge_base()}
|
|
570
|
+
|
|
571
|
+
**Development Cycle - START HERE:**
|
|
572
|
+
|
|
573
|
+
**For NEW file implementation:**
|
|
574
|
+
1. **You need to call read_code_mem(already_implemented_file_path)** to understand existing implementations and dependencies - agent should choose relevant ALREADY IMPLEMENTED file paths for reference, NOT the new file you want to create
|
|
575
|
+
2. Write_file can be used to implement the new component
|
|
576
|
+
3. Finally: Use execute_python or execute_bash for testing (if needed)
|
|
577
|
+
|
|
578
|
+
**When all files implemented:**
|
|
579
|
+
**Use execute_python or execute_bash** to test the complete implementation""",
|
|
580
|
+
}
|
|
581
|
+
concise_messages.append(knowledge_base_message)
|
|
582
|
+
|
|
583
|
+
# 3. Add current tool results (essential information for next file generation)
|
|
584
|
+
if self.current_round_tool_results:
|
|
585
|
+
tool_results_content = self._format_tool_results()
|
|
586
|
+
tool_results_message = {
|
|
587
|
+
"role": "user",
|
|
588
|
+
"content": f"""**Current Tool Results:**
|
|
589
|
+
{tool_results_content}""",
|
|
590
|
+
}
|
|
591
|
+
concise_messages.append(tool_results_message)
|
|
592
|
+
else:
|
|
593
|
+
# If no tool results yet, add guidance for next steps
|
|
594
|
+
guidance_message = {
|
|
595
|
+
"role": "user",
|
|
596
|
+
"content": f"""**Current Round:** {self.current_round}
|
|
597
|
+
|
|
598
|
+
**Development Cycle - START HERE:**
|
|
599
|
+
|
|
600
|
+
**For NEW file implementation:**
|
|
601
|
+
1. **You need to call read_code_mem(already_implemented_file_path)** to understand existing implementations and dependencies - agent should choose relevant ALREADY IMPLEMENTED file paths for reference, NOT the new file you want to create
|
|
602
|
+
2. Write_file can be used to implement the new component
|
|
603
|
+
3. Finally: Use execute_python or execute_bash for testing (if needed)
|
|
604
|
+
|
|
605
|
+
**When all files implemented:**
|
|
606
|
+
1. **Use execute_python or execute_bash** to test the complete implementation""",
|
|
607
|
+
}
|
|
608
|
+
concise_messages.append(guidance_message)
|
|
609
|
+
# **Available Essential Tools:** read_code_mem, write_file, execute_python, execute_bash
|
|
610
|
+
# **Remember:** Start with read_code_mem when implementing NEW files to understand existing code. When all files are implemented, focus on testing and completion. Implement according to the original paper's specifications - any reference code is for inspiration only."""
|
|
611
|
+
# self.logger.info(f"✅ Concise messages created: {len(concise_messages)} messages (original: {len(messages)})")
|
|
612
|
+
return concise_messages
|
|
613
|
+
|
|
614
|
+
def _read_code_knowledge_base(self) -> Optional[str]:
|
|
615
|
+
"""
|
|
616
|
+
Read the implement_code_summary.md file as code knowledge base
|
|
617
|
+
Returns only the final/latest implementation entry, not all historical entries
|
|
618
|
+
|
|
619
|
+
Returns:
|
|
620
|
+
Content of the latest implementation entry if it exists, None otherwise
|
|
621
|
+
"""
|
|
622
|
+
try:
|
|
623
|
+
if os.path.exists(self.code_summary_path):
|
|
624
|
+
with open(self.code_summary_path, "r", encoding="utf-8") as f:
|
|
625
|
+
content = f.read().strip()
|
|
626
|
+
|
|
627
|
+
if content:
|
|
628
|
+
# Extract only the final/latest implementation entry
|
|
629
|
+
return self._extract_latest_implementation_entry(content)
|
|
630
|
+
else:
|
|
631
|
+
return None
|
|
632
|
+
else:
|
|
633
|
+
return None
|
|
634
|
+
|
|
635
|
+
except Exception as e:
|
|
636
|
+
self.logger.error(f"Failed to read code knowledge base: {e}")
|
|
637
|
+
return None
|
|
638
|
+
|
|
639
|
+
def _extract_latest_implementation_entry(self, content: str) -> Optional[str]:
|
|
640
|
+
"""
|
|
641
|
+
Extract the latest/final implementation entry from the implement_code_summary.md content
|
|
642
|
+
Uses a simpler approach to find the last implementation section
|
|
643
|
+
|
|
644
|
+
Args:
|
|
645
|
+
content: Full content of implement_code_summary.md
|
|
646
|
+
|
|
647
|
+
Returns:
|
|
648
|
+
Latest implementation entry content, or None if not found
|
|
649
|
+
"""
|
|
650
|
+
try:
|
|
651
|
+
import re
|
|
652
|
+
|
|
653
|
+
# Pattern to match the start of implementation sections
|
|
654
|
+
section_pattern = (
|
|
655
|
+
r"={80}\s*\n## IMPLEMENTATION File .+?; ROUND \d+\s*\n={80}"
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
# Find all implementation section starts
|
|
659
|
+
matches = list(re.finditer(section_pattern, content))
|
|
660
|
+
|
|
661
|
+
if not matches:
|
|
662
|
+
# No implementation sections found
|
|
663
|
+
lines = content.split("\n")
|
|
664
|
+
fallback_content = (
|
|
665
|
+
"\n".join(lines[:10]) + "\n... (truncated for brevity)"
|
|
666
|
+
if len(lines) > 10
|
|
667
|
+
else content
|
|
668
|
+
)
|
|
669
|
+
self.logger.info(
|
|
670
|
+
"📖 No implementation sections found, using fallback content"
|
|
671
|
+
)
|
|
672
|
+
return fallback_content
|
|
673
|
+
|
|
674
|
+
# Get the start position of the last implementation section
|
|
675
|
+
last_match = matches[-1]
|
|
676
|
+
start_pos = last_match.start()
|
|
677
|
+
|
|
678
|
+
# Take everything from the last section start to the end of content
|
|
679
|
+
latest_entry = content[start_pos:].strip()
|
|
680
|
+
|
|
681
|
+
# self.logger.info(f"📖 Extracted latest implementation entry from knowledge base")
|
|
682
|
+
# print(f"DEBUG: Extracted content length: {len(latest_entry)}")
|
|
683
|
+
# print(f"DEBUG: First 200 chars: {latest_entry[:]}")
|
|
684
|
+
|
|
685
|
+
return latest_entry
|
|
686
|
+
|
|
687
|
+
except Exception as e:
|
|
688
|
+
self.logger.error(f"Failed to extract latest implementation entry: {e}")
|
|
689
|
+
# Return last 1000 characters as fallback
|
|
690
|
+
return content[-500:] if len(content) > 500 else content
|
|
691
|
+
|
|
692
|
+
def _format_tool_results(self) -> str:
|
|
693
|
+
"""
|
|
694
|
+
Format current round tool results for LLM input
|
|
695
|
+
|
|
696
|
+
Returns:
|
|
697
|
+
Formatted string of tool results
|
|
698
|
+
"""
|
|
699
|
+
if not self.current_round_tool_results:
|
|
700
|
+
return "No tool results in current round."
|
|
701
|
+
|
|
702
|
+
formatted_results = []
|
|
703
|
+
|
|
704
|
+
for result in self.current_round_tool_results:
|
|
705
|
+
tool_name = result["tool_name"]
|
|
706
|
+
tool_input = result["tool_input"]
|
|
707
|
+
tool_result = result["tool_result"]
|
|
708
|
+
|
|
709
|
+
# Format based on tool type
|
|
710
|
+
if tool_name == "read_code_mem":
|
|
711
|
+
file_path = tool_input.get("file_path", "unknown")
|
|
712
|
+
formatted_results.append(f"""
|
|
713
|
+
**read_code_mem Result for {file_path}:**
|
|
714
|
+
{self._format_tool_result_content(tool_result)}
|
|
715
|
+
""")
|
|
716
|
+
elif tool_name == "read_file":
|
|
717
|
+
file_path = tool_input.get("file_path", "unknown")
|
|
718
|
+
formatted_results.append(f"""
|
|
719
|
+
**read_file Result for {file_path}:**
|
|
720
|
+
{self._format_tool_result_content(tool_result)}
|
|
721
|
+
""")
|
|
722
|
+
elif tool_name == "write_file":
|
|
723
|
+
file_path = tool_input.get("file_path", "unknown")
|
|
724
|
+
formatted_results.append(f"""
|
|
725
|
+
**write_file Result for {file_path}:**
|
|
726
|
+
{self._format_tool_result_content(tool_result)}
|
|
727
|
+
""")
|
|
728
|
+
elif tool_name == "execute_python":
|
|
729
|
+
code_snippet = (
|
|
730
|
+
tool_input.get("code", "")[:50] + "..."
|
|
731
|
+
if len(tool_input.get("code", "")) > 50
|
|
732
|
+
else tool_input.get("code", "")
|
|
733
|
+
)
|
|
734
|
+
formatted_results.append(f"""
|
|
735
|
+
**execute_python Result (code: {code_snippet}):**
|
|
736
|
+
{self._format_tool_result_content(tool_result)}
|
|
737
|
+
""")
|
|
738
|
+
elif tool_name == "execute_bash":
|
|
739
|
+
command = tool_input.get("command", "unknown")
|
|
740
|
+
formatted_results.append(f"""
|
|
741
|
+
**execute_bash Result (command: {command}):**
|
|
742
|
+
{self._format_tool_result_content(tool_result)}
|
|
743
|
+
""")
|
|
744
|
+
elif tool_name == "search_code":
|
|
745
|
+
pattern = tool_input.get("pattern", "unknown")
|
|
746
|
+
file_pattern = tool_input.get("file_pattern", "")
|
|
747
|
+
formatted_results.append(f"""
|
|
748
|
+
**search_code Result (pattern: {pattern}, files: {file_pattern}):**
|
|
749
|
+
{self._format_tool_result_content(tool_result)}
|
|
750
|
+
""")
|
|
751
|
+
elif tool_name == "search_reference_code":
|
|
752
|
+
target_file = tool_input.get("target_file", "unknown")
|
|
753
|
+
keywords = tool_input.get("keywords", "")
|
|
754
|
+
formatted_results.append(f"""
|
|
755
|
+
**search_reference_code Result for {target_file} (keywords: {keywords}):**
|
|
756
|
+
{self._format_tool_result_content(tool_result)}
|
|
757
|
+
""")
|
|
758
|
+
elif tool_name == "get_file_structure":
|
|
759
|
+
directory = tool_input.get(
|
|
760
|
+
"directory_path", tool_input.get("path", "current")
|
|
761
|
+
)
|
|
762
|
+
formatted_results.append(f"""
|
|
763
|
+
**get_file_structure Result for {directory}:**
|
|
764
|
+
{self._format_tool_result_content(tool_result)}
|
|
765
|
+
""")
|
|
766
|
+
|
|
767
|
+
return "\n".join(formatted_results)
|
|
768
|
+
|
|
769
|
+
def _format_tool_result_content(self, tool_result: Any) -> str:
|
|
770
|
+
"""
|
|
771
|
+
Format tool result content for display
|
|
772
|
+
|
|
773
|
+
Args:
|
|
774
|
+
tool_result: Tool result to format
|
|
775
|
+
|
|
776
|
+
Returns:
|
|
777
|
+
Formatted string representation
|
|
778
|
+
"""
|
|
779
|
+
if isinstance(tool_result, str):
|
|
780
|
+
# Try to parse as JSON for better formatting
|
|
781
|
+
try:
|
|
782
|
+
result_data = json.loads(tool_result)
|
|
783
|
+
if isinstance(result_data, dict):
|
|
784
|
+
# Format key information
|
|
785
|
+
if result_data.get("status") == "summary_found":
|
|
786
|
+
return (
|
|
787
|
+
f"Summary found:\n{result_data.get('summary_content', '')}"
|
|
788
|
+
)
|
|
789
|
+
elif result_data.get("status") == "no_summary":
|
|
790
|
+
return "No summary available"
|
|
791
|
+
else:
|
|
792
|
+
return json.dumps(result_data, indent=2)
|
|
793
|
+
else:
|
|
794
|
+
return str(result_data)
|
|
795
|
+
except json.JSONDecodeError:
|
|
796
|
+
return tool_result
|
|
797
|
+
else:
|
|
798
|
+
return str(tool_result)
|
|
799
|
+
|
|
800
|
+
def get_memory_statistics(self, files_implemented: int = 0) -> Dict[str, Any]:
|
|
801
|
+
"""Get memory agent statistics"""
|
|
802
|
+
return {
|
|
803
|
+
"last_write_file_detected": self.last_write_file_detected,
|
|
804
|
+
"should_clear_memory_next": self.should_clear_memory_next,
|
|
805
|
+
"current_round": self.current_round,
|
|
806
|
+
"concise_mode_active": self.should_use_concise_mode(),
|
|
807
|
+
"current_round_tool_results": len(self.current_round_tool_results),
|
|
808
|
+
"essential_tools_recorded": [
|
|
809
|
+
r["tool_name"] for r in self.current_round_tool_results
|
|
810
|
+
],
|
|
811
|
+
"implemented_files_tracked": files_implemented,
|
|
812
|
+
"implemented_files_list": self.implemented_files.copy(),
|
|
813
|
+
"phases_parsed": len(self.phase_structure),
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
def get_implemented_files(self) -> List[str]:
|
|
817
|
+
"""Get list of all implemented files"""
|
|
818
|
+
return self.implemented_files.copy()
|
|
819
|
+
|
|
820
|
+
def should_trigger_memory_optimization(
|
|
821
|
+
self, messages: List[Dict[str, Any]], files_implemented: int = 0
|
|
822
|
+
) -> bool:
|
|
823
|
+
"""
|
|
824
|
+
Check if memory optimization should be triggered
|
|
825
|
+
NEW LOGIC: Trigger after write_file has been detected
|
|
826
|
+
|
|
827
|
+
Args:
|
|
828
|
+
messages: Current message list
|
|
829
|
+
files_implemented: Number of files implemented so far
|
|
830
|
+
|
|
831
|
+
Returns:
|
|
832
|
+
True if concise mode should be applied
|
|
833
|
+
"""
|
|
834
|
+
# Trigger if we detected write_file and should clear memory
|
|
835
|
+
if self.should_clear_memory_next:
|
|
836
|
+
# self.logger.info(f"🎯 Triggering CONCISE memory optimization (write_file detected, files: {files_implemented})")
|
|
837
|
+
return True
|
|
838
|
+
|
|
839
|
+
# No optimization before any write_file
|
|
840
|
+
return False
|
|
841
|
+
|
|
842
|
+
def apply_memory_optimization(
|
|
843
|
+
self, system_prompt: str, messages: List[Dict[str, Any]], files_implemented: int
|
|
844
|
+
) -> List[Dict[str, Any]]:
|
|
845
|
+
"""
|
|
846
|
+
Apply memory optimization using concise approach
|
|
847
|
+
NEW LOGIC: Clear all history after write_file, keep only system_prompt + initial_plan + current tools
|
|
848
|
+
|
|
849
|
+
Args:
|
|
850
|
+
system_prompt: Current system prompt
|
|
851
|
+
messages: Original message list
|
|
852
|
+
files_implemented: Number of files implemented so far
|
|
853
|
+
|
|
854
|
+
Returns:
|
|
855
|
+
Optimized message list
|
|
856
|
+
"""
|
|
857
|
+
if not self.should_clear_memory_next:
|
|
858
|
+
# Before any write_file, return original messages
|
|
859
|
+
return messages
|
|
860
|
+
|
|
861
|
+
# Apply concise memory optimization after write_file detection
|
|
862
|
+
# self.logger.info(f"🧹 CLEARING MEMORY after write_file - creating clean slate")
|
|
863
|
+
optimized_messages = self.create_concise_messages(
|
|
864
|
+
system_prompt, messages, files_implemented
|
|
865
|
+
)
|
|
866
|
+
|
|
867
|
+
# Clear the flag after applying optimization
|
|
868
|
+
self.should_clear_memory_next = False
|
|
869
|
+
|
|
870
|
+
compression_ratio = (
|
|
871
|
+
((len(messages) - len(optimized_messages)) / len(messages) * 100)
|
|
872
|
+
if messages
|
|
873
|
+
else 0
|
|
874
|
+
)
|
|
875
|
+
self.logger.info(
|
|
876
|
+
f"🎯 CONCISE optimization applied: {len(messages)} → {len(optimized_messages)} messages ({compression_ratio:.1f}% compression)"
|
|
877
|
+
)
|
|
878
|
+
|
|
879
|
+
return optimized_messages
|
|
880
|
+
|
|
881
|
+
def clear_current_round_tool_results(self):
|
|
882
|
+
"""Clear current round tool results (called when starting new round)"""
|
|
883
|
+
self.current_round_tool_results = []
|
|
884
|
+
self.logger.info("🧹 Current round tool results cleared")
|
|
885
|
+
|
|
886
|
+
def debug_concise_state(self, files_implemented: int = 0):
|
|
887
|
+
"""Debug method to show current concise memory state"""
|
|
888
|
+
stats = self.get_memory_statistics(files_implemented)
|
|
889
|
+
|
|
890
|
+
print("=" * 60)
|
|
891
|
+
print("🎯 CONCISE MEMORY AGENT STATE (Write-File-Based)")
|
|
892
|
+
print("=" * 60)
|
|
893
|
+
print(f"Last write_file detected: {stats['last_write_file_detected']}")
|
|
894
|
+
print(f"Should clear memory next: {stats['should_clear_memory_next']}")
|
|
895
|
+
print(f"Files implemented: {stats['implemented_files_tracked']}")
|
|
896
|
+
print(f"Current round: {stats['current_round']}")
|
|
897
|
+
print(f"Concise mode active: {stats['concise_mode_active']}")
|
|
898
|
+
print(f"Current round tool results: {stats['current_round_tool_results']}")
|
|
899
|
+
print(f"Essential tools recorded: {stats['essential_tools_recorded']}")
|
|
900
|
+
print(f"Implemented files tracked: {len(self.implemented_files)}")
|
|
901
|
+
print(f"Implemented files list: {self.implemented_files}")
|
|
902
|
+
print(f"Code summary file exists: {os.path.exists(self.code_summary_path)}")
|
|
903
|
+
print("")
|
|
904
|
+
print(
|
|
905
|
+
"📊 NEW LOGIC: write_file → clear memory → accumulate tools → next write_file"
|
|
906
|
+
)
|
|
907
|
+
print("📊 Essential Tools Tracked:")
|
|
908
|
+
essential_tools = [
|
|
909
|
+
"read_code_mem",
|
|
910
|
+
"read_file",
|
|
911
|
+
"write_file",
|
|
912
|
+
"execute_python",
|
|
913
|
+
"execute_bash",
|
|
914
|
+
"search_code",
|
|
915
|
+
"search_reference_code",
|
|
916
|
+
"get_file_structure",
|
|
917
|
+
]
|
|
918
|
+
for tool in essential_tools:
|
|
919
|
+
tool_count = sum(
|
|
920
|
+
1 for r in self.current_round_tool_results if r["tool_name"] == tool
|
|
921
|
+
)
|
|
922
|
+
print(f" - {tool}: {tool_count} calls")
|
|
923
|
+
print("=" * 60)
|