add rework detection to solve_task: read teacher comments, pass to LLM
- _get_task_meta(): calls task_get MCP to check existing repo URL and comments - solve(): detects rework (repo_url exists) vs fresh submission - generate(): accepts rework_comments, injects into prompt as separate section - _REWORK_SECTION: prompt block with teacher feedback for rework cases - commit prefix: "fix:" for rework, "add" for fresh submissions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+57
-9
@@ -118,6 +118,28 @@ def _gh():
|
|||||||
return {"Authorization": f"token {GITEA_TOKEN}", "Content-Type": "application/json"}
|
return {"Authorization": f"token {GITEA_TOKEN}", "Content-Type": "application/json"}
|
||||||
|
|
||||||
|
|
||||||
|
async def _get_task_meta(task_id: str) -> dict:
|
||||||
|
"""Возвращает существующий repo_url и комментарии преподавателя (если есть).
|
||||||
|
|
||||||
|
Используется для определения: первая сдача или пересдача после отклонения.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
raw = await mcp_call("task_get", {"taskId": task_id})
|
||||||
|
data = json.loads(raw)
|
||||||
|
url = (data.get("answer") or {}).get("content", "")
|
||||||
|
repo_url = url if url.startswith(f"{GITEA_BASE_URL}/{GITEA_OWNER}/") else None
|
||||||
|
comments = data.get("comments") or data.get("feedback", "") or ""
|
||||||
|
# comments может быть списком объектов
|
||||||
|
if isinstance(comments, list):
|
||||||
|
comments = "\n".join(
|
||||||
|
c.get("text", c.get("content", str(c))) for c in comments if c
|
||||||
|
)
|
||||||
|
return {"repo_url": repo_url, "comments": str(comments).strip()}
|
||||||
|
except Exception as e:
|
||||||
|
print(f" [meta] Не удалось получить метаданные задания: {e}")
|
||||||
|
return {"repo_url": None, "comments": ""}
|
||||||
|
|
||||||
|
|
||||||
def gitea_create_repo(name: str) -> str:
|
def gitea_create_repo(name: str) -> str:
|
||||||
with httpx.Client(timeout=30) as c:
|
with httpx.Client(timeout=30) as c:
|
||||||
r = c.post(f"{GITEA_BASE_URL}/api/v1/user/repos", headers=_gh(),
|
r = c.post(f"{GITEA_BASE_URL}/api/v1/user/repos", headers=_gh(),
|
||||||
@@ -281,15 +303,28 @@ parser = PydanticOutputParser(pydantic_object=MyOutput)
|
|||||||
- ОБЯЗАТЕЛЬНО использовать create_deep_agent из deepagents
|
- ОБЯЗАТЕЛЬНО использовать create_deep_agent из deepagents
|
||||||
- requirements.txt: deepagents, langchain>=1.2.10, langchain-openai>=0.3.0, langgraph>=0.2.0 + нужные доп. зависимости
|
- requirements.txt: deepagents, langchain>=1.2.10, langchain-openai>=0.3.0, langgraph>=0.2.0 + нужные доп. зависимости
|
||||||
|
|
||||||
|
{rework_section}
|
||||||
## Ответ — ТОЛЬКО JSON без markdown:
|
## Ответ — ТОЛЬКО JSON без markdown:
|
||||||
{{"main_py": "...", "requirements_txt": "...", "extra_files": {{}}}}
|
{{"main_py": "...", "requirements_txt": "...", "extra_files": {{}}}}
|
||||||
|
|
||||||
extra_files — только если нужны доп. файлы, иначе пустой объект.
|
extra_files — только если нужны доп. файлы, иначе пустой объект.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
_REWORK_SECTION = '''\
|
||||||
|
## ПЕРЕСДАЧА — комментарии преподавателя
|
||||||
|
Предыдущее решение было отклонено. Обязательно учти замечания:
|
||||||
|
|
||||||
async def generate(task_text: str, retries=5) -> dict:
|
{comments}
|
||||||
prompt = _PROMPT.format(task_text=task_text)
|
|
||||||
|
Исправь именно то, что указано выше. Не меняй то, что работало правильно.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
async def generate(task_text: str, rework_comments: str = "", retries=5) -> dict:
|
||||||
|
rework_section = (
|
||||||
|
_REWORK_SECTION.format(comments=rework_comments) if rework_comments else ""
|
||||||
|
)
|
||||||
|
prompt = _PROMPT.format(task_text=task_text, rework_section=rework_section)
|
||||||
for attempt in range(1, retries + 1):
|
for attempt in range(1, retries + 1):
|
||||||
try:
|
try:
|
||||||
print(f" [llm] Генерирую решение (попытка {attempt})...")
|
print(f" [llm] Генерирую решение (попытка {attempt})...")
|
||||||
@@ -402,33 +437,46 @@ async def solve(task_id: str):
|
|||||||
print(f"Задание: {task_id}")
|
print(f"Задание: {task_id}")
|
||||||
print('='*60)
|
print('='*60)
|
||||||
|
|
||||||
|
# 0. Проверяем: первая сдача или пересдача
|
||||||
|
print("[0/5] Проверяем статус задания...")
|
||||||
|
meta = await _get_task_meta(task_id)
|
||||||
|
is_rework = meta["repo_url"] is not None
|
||||||
|
comments = meta["comments"]
|
||||||
|
if is_rework:
|
||||||
|
print(f" ⟳ ПЕРЕСДАЧА (репо уже есть: {meta['repo_url']})")
|
||||||
|
if comments:
|
||||||
|
print(f" Комментарии преподавателя: {comments[:200]}")
|
||||||
|
else:
|
||||||
|
print(" ✦ Первая сдача")
|
||||||
|
|
||||||
# 1. Читаем текст задания
|
# 1. Читаем текст задания
|
||||||
print("[1/5] Читаем текст задания...")
|
print("[1/5] Читаем текст задания...")
|
||||||
task_text = await mcp_call("task_text", {"taskId": task_id})
|
task_text = await mcp_call("task_text", {"taskId": task_id})
|
||||||
print(f" Получено {len(task_text)} символов")
|
print(f" Получено {len(task_text)} символов")
|
||||||
|
|
||||||
# 2. Генерируем код
|
# 2. Генерируем код (с учётом комментариев если пересдача)
|
||||||
print("[2/5] Генерируем код (1 LLM-вызов)...")
|
print("[2/5] Генерируем код (1 LLM-вызов)...")
|
||||||
solution = await generate(task_text)
|
solution = await generate(task_text, rework_comments=comments if is_rework else "")
|
||||||
main_py = solution.get("main_py", "")
|
main_py = solution.get("main_py", "")
|
||||||
requirements = solution.get("requirements_txt", "")
|
requirements = solution.get("requirements_txt", "")
|
||||||
extra = solution.get("extra_files", {})
|
extra = solution.get("extra_files", {})
|
||||||
print(f" main.py: {len(main_py)} символов, requirements.txt: {len(requirements)} символов")
|
print(f" main.py: {len(main_py)} символов, requirements.txt: {len(requirements)} символов")
|
||||||
|
|
||||||
# 3. Создаём репо
|
# 3. Создаём репо (при пересдаче — 409, вернёт существующий URL)
|
||||||
repo = f"task-{task_id}"
|
repo = f"task-{task_id}"
|
||||||
print(f"[3/5] Создаём репозиторий {repo}...")
|
print(f"[3/5] {'Обновляем' if is_rework else 'Создаём'} репозиторий {repo}...")
|
||||||
repo_url = gitea_create_repo(repo)
|
repo_url = gitea_create_repo(repo)
|
||||||
print(f" {repo_url}")
|
print(f" {repo_url}")
|
||||||
|
|
||||||
# 4. Пушим файлы
|
# 4. Пушим файлы
|
||||||
|
commit_prefix = "fix:" if is_rework else "add"
|
||||||
print("[4/5] Пушим файлы...")
|
print("[4/5] Пушим файлы...")
|
||||||
gitea_write(repo, "main.py", main_py, "add main.py")
|
gitea_write(repo, "main.py", main_py, f"{commit_prefix} main.py")
|
||||||
print(" main.py ✓")
|
print(" main.py ✓")
|
||||||
gitea_write(repo, "requirements.txt", requirements, "add requirements.txt")
|
gitea_write(repo, "requirements.txt", requirements, f"{commit_prefix} requirements.txt")
|
||||||
print(" requirements.txt ✓")
|
print(" requirements.txt ✓")
|
||||||
for fname, fcontent in extra.items():
|
for fname, fcontent in extra.items():
|
||||||
gitea_write(repo, fname, fcontent, f"add {fname}")
|
gitea_write(repo, fname, fcontent, f"{commit_prefix} {fname}")
|
||||||
print(f" {fname} ✓")
|
print(f" {fname} ✓")
|
||||||
|
|
||||||
# 5. Сабмитим
|
# 5. Сабмитим
|
||||||
|
|||||||
Reference in New Issue
Block a user