old intents

This commit is contained in:
2026-09-19 13:18:49 +00:00
parent 37ce2da6a1
commit eb84fb96af
5 changed files with 1054 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
class CoderAgent:
"""Агент-исполнитель: выполняет подзадачу, генерирует код и применяет изменения."""
@staticmethod
def execute(project: Project, subtask: str, files: List[str], error_feedback: str = "") -> bool:
print(f"💻 Кодер выполняет: {subtask}")
# 1. Начинаем с переданных файлов
context_files = set(files)
# 2. Извлекаем пути из error_feedback (если есть)
if error_feedback:
import re
# Ищем пути к файлам (с расширениями .ts, .tsx, .js, .jsx, .html, .css, .py)
# Паттерн ищет строки, содержащие путь с расширением, например "src/App.tsx"
path_pattern = r'[^\s"\']+\.(tsx?|jsx?|html|css|py)\b'
found_paths = re.findall(path_pattern, error_feedback, re.IGNORECASE)
# Также ищем полные URL типа file:// или http:// с путем
url_pattern = r'(?:file://|https?://[^\s]+)(/[^\s"\']+)'
url_matches = re.findall(url_pattern, error_feedback)
for match in url_matches:
# обрезаем до относительного пути относительно корня проекта?
# Пока просто добавляем как есть, но лучше нормализовать
found_paths.append(match)
# Добавляем найденные пути, если они не в списке
for p in found_paths:
# Удаляем лишние символы, например, :line:col или суффиксы
# Часто путь может быть вида "file:///home/project/src/App.tsx:12:34"
# или просто "src/App.tsx:12:34"
p = p.split(':')[0] # отбрасываем строку/колонку, если есть
p = p.strip()
# Если путь начинается с /, то это абсолютный путь, пытаемся сделать относительным
if p.startswith('/'):
p = p.lstrip('/')
# Если это абсолютный путь внутри проекта, то можно обрезать корень
# Упрощённо: ищем вхождение папки проекта
proj_root = str(project.path.resolve())
if p.startswith(proj_root):
p = os.path.relpath(p, proj_root)
else:
# иначе оставляем как есть (может не сработать)
pass
if p and p not in context_files:
context_files.add(p)
# 3. Читаем содержимое всех файлов
file_context = []
for rel_path in context_files:
full_path = project.path / rel_path
if not full_path.exists():
print(f" ⚠️ Файл не найден: {rel_path}")
continue
content = project.read_file_content(full_path)
if content:
file_context.append(f"=== {rel_path} ===\n{content}")
else:
print(f" ⚠️ Не удалось прочитать {rel_path}")
context = "\n".join(file_context) if file_context else "(нет файлов для контекста)"
# 4. Формируем промпт
system_prompt = "Ты — опытный разработчик. Отвечай только кодом, без лишнего текста. Если нужно изменить несколько файлов, выдавай блоки вида: [filename]\n```language\nкод\n```"
user_prompt = f"""
Текущая задача: {subtask}
{f"При предыдущей попытке возникли ошибки: {error_feedback}" if error_feedback else ""}
Текущий код указанных файлов:
{context}
Внеси изменения в соответствующие файлы. Если создаёшь новый файл — укажи его путь относительно корня проекта.
Выдай изменения в формате:
[путь/к/файлу1]
```язык
код
```
[путь/к/файлу2]
```язык
код
```
"""
messages = [{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}]
response = project.ollama_client.chat(messages, temperature=0.2)
if not response:
print("⚠️ Ответ от Ollama пустой.")
return False
try:
pattern = r'\[(.*?)\]\s*```(?:\w+)?\s*(.*?)```'
matches = re.findall(pattern, response, re.DOTALL)
if not matches:
print("⚠️ Не удалось распарсить ответ, пытаемся сохранить как один файл")
if context_files:
first_file = next(iter(context_files))
full_path = project.path / first_file
project.write_file(full_path, response)
print(f" Записан {first_file} (весь ответ)")
return True
if files:
first_file = files[0]
full_path = project.path / first_file
project.write_file(full_path, response)
print(f" Записан {first_file} (весь ответ)")
return True
return False
for file_path_str, content in matches:
file_path_str = file_path_str.strip().strip('"').strip("'")
target_path = project.path / file_path_str
project.write_file(target_path, content.strip())
print(f" Обновлён {target_path.relative_to(project.path)}")
return True
except Exception as e:
print(f" Ошибка при парсинге ответа кодера: {e}")
return False