33 Commits

Author SHA1 Message Date
dapa46 f1b75a0f2a Обновить README.md 2026-06-18 16:35:22 +00:00
dapa46 0f38d8d588 Add Deep Agents UI, pipeline fixes, and agent improvements.
Includes deep-agents-ui integration, rework detection via Gitea,
tool-call sanitization fixes, and startup scripts.
2026-06-18 19:33:26 +03:00
Glevel ba83d0cfe4 feat: LLM-first architecture — agent orchestrates everything via solve_task tool
- cli.py: cmd_run() now uses agent.ainvoke() instead of pipeline
- ui.py: 'run all' button and chat use main agent; status tab fixed (thread + st.rerun)
- src/agent/runner_tools.py: new solve_task tool wrapping reliable single-task execution
- src/agent/agent.py: solve_task added to main agent tools
- src/agent/prompts.py: main_agent_instructions rewritten for LLM-first orchestration

LLM decides what to do and in what order; Python tools are just hands.
2026-06-11 18:43:40 +03:00
Glevel 0a2b139f9b fix: SyntaxError nonlocal — заменить на dict _pl_state 2026-06-05 17:32:45 +03:00
Glevel 101671ea6e feat: логи tool-calls для pipeline всех заданий
pipeline.py:
- _invoke_with_retry принимает callbacks и пробрасывает в agent.ainvoke()
- process_one_task принимает RunnableConfig и извлекает callbacks из него
- callbacks передаются при первой сдаче и при retry-исправлении

ui.py:
- Pipeline «все todo» запускается в потоке (не блокирует asyncio.run)
- AgentCallback собирает события и показывает их в реальном времени
- После завершения — раскрывающийся лог всего pipeline

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 17:31:05 +03:00
Glevel 2bfcf5f782 revert: вернуть ui.py к версии ee2c8de (до изменений rate limit) 2026-06-05 17:16:14 +03:00
Glevel b9b0f58de2 fix: переписать UI — убрать polling/threading, простой blocking spinner
Проблема: st.rerun() внутри with tab_*: блокировал выполнение других вкладок,
кнопки не работали, экран выглядел пустым.

Решение: простая синхронная архитектура:
- _invoke_agent() запускает агент в потоке и ждёт t.join()
- UI показывает st.spinner() пока агент работает
- События собираются через AgentEventCollector (список, не очередь)
- Показываются после завершения в раскрывающемся логе
- Нет polling, нет rerun-цикла, нет флагов chat_running/pipe_running

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 17:12:19 +03:00
Glevel 177dea2769 fix: переписать UI на st.rerun() polling — кнопки и события работают корректно
Проблема: blocking while-цикл блокировал Streamlit, кнопка «Стоп» не работала
(Streamlit не может обработать клик пока скрипт заблокирован), кнопка мигала
каждые 0.3с из-за динамического ключа.

Решение: rerun-based polling — каждая «итерация» это полный rerun скрипта:
- chat_running / pipe_running флаги в session_state
- thread + queue живут в session_state между рерандами
- time.sleep(0.5) → st.rerun() вместо while-цикла
- кнопка «Стоп» рендерится нормально и реагирует мгновенно
- « Агент работает... Nс» при простое >15с
- лог событий накапливается в session_state.chat_events

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 17:05:09 +03:00
Glevel cba8940005 fix: 429 rate limit виден в UI, добавлена кнопка Стоп
- RetryOnRateLimitMiddleware: при 429 шлёт события rate_limit_wait/retry
  в глобальный UI-канал (set_ui_event_queue) — без него не меняет поведение
- ui.py: рендерит  rate_limit_wait и 🔄 rate_limit_retry в лог событий
- ui.py: показывает «Агент работает... Nс» если нет событий >15с
- ui.py: кнопка «Стоп» прерывает ожидание в чате и pipeline

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 16:59:10 +03:00
Glevel ee2c8de372 fix: исправить поиск tasks_list — использовать полное имя с префиксом MCP
MCP-инструменты после загрузки получают префикс mcp__journal-bh-professor__.
tools.get("tasks_list") всегда возвращал None → статус не загружался.
Исправлено в ui.py (вкладка Статус) и cli.py (команда status).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 16:49:48 +03:00
Glevel 3ae3488691 refactor: добавить агентную архитектуру, UI и CLI
- src/agent/solve_tools.py: новые LLM-субагенты validate_teacher_comment и
  generate_code_solution — агент сам решает когда их вызывать
- src/agent/solve_prompts.py: централизованные промпты для субагентов решения
- src/agent/gitea_tools.py: добавлен gitea_list_files для чтения файлов репо
- src/agent/agent.py: SOLVE_TOOLS подключены к homework_direct_agent и rework_agent
- src/agent/prompts.py: промпты переработаны в capability-based формат (без жёстких шагов)
- cli.py: единая точка входа (solve / run / status)
- ui.py: Streamlit UI с реал-тайм отображением вызовов инструментов
- requirements.txt: добавлен streamlit>=1.35.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 16:43:00 +03:00
Glevel bb1aedfe2a fix: read teacher feedback from submission.grade.feedback
BroJS stores teacher comments in submission.grade.feedback, not in
the top-level comments array (which is always empty). Fixed priority:
submission.grade.feedback -> submission.feedback -> data.feedback -> data.comments

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-04 20:22:23 +03:00
Glevel da40caa637 feat: trap detection - validate teacher comment before rework
New flow for rework with comments:
1. Read current code files from Gitea
2. LLM validates if comment is justified or a trap
3a. TRAP (invalid): add objection to README.md, submit without code changes
3b. VALID: analyze fixes/defenses, regenerate code

Added: _VALIDATE_PROMPT, _OBJECTION_TEMPLATE, validate_comment(),
gitea_read(), gitea_list_files()

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-04 19:52:36 +03:00
Glevel 7faae42204 feat: stronger defense arguments in rework analysis
Analyze prompt now asks for 4-part structured argument per defense:
  ZAMECHANIE / NEOBKHODIMOST / OPTIMALNOST / ALTERNATIVY

Generated code gets DESIGN DECISION / NECESSITY / OPTIMALITY /
ALTERNATIVES CONSIDERED comment blocks instead of bare NOTE.

Agent argues that choices were deliberate, necessary and optimal -
not just correct.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-04 19:41:17 +03:00
Glevel 02ed3aa99f fix: detect rework via Gitea repo existence, not BroJS answer field
BroJS clears the answer field when rejecting a task, so repo_url was
always None on rework. Now we check Gitea API directly — if the repo
exists, it's a rework regardless of BroJS answer state.
Comments are still read from BroJS task_get.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-04 19:30:30 +03:00
Glevel 39019e2574 feat: analyze teacher comments before rework (defend solution)
Add analyze_comments() that calls LLM to evaluate each teacher comment:
- valid criticism -> fixes list (LLM will fix these)
- incorrect/misunderstood -> defenses list (LLM adds NOTE: comments in code)
Verdict: needs_fixes | already_correct | mixed

solve() now prints analysis verdict and counts before generation.
Commit message on rework includes verdict + fix/defense counts.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-04 19:21:39 +03:00
Glevel 07d7d01996 fix: ban Ollama in prompt, use OpenAIEmbeddings for ChromaDB RAG
Explicitly forbid langchain_ollama/OllamaEmbeddings in _PROMPT.
ChromaDB template now uses OpenAIEmbeddings via OpenRouter.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-04 19:18:43 +03:00
Glevel ec197b7e98 docs: explain OpenRouter vs Ollama choice
README: add comparison table section
solve_task.py: add comment in LLM template explaining model choice

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-04 19:13:54 +03:00
Glevel 863ea54eaf fix: безопасная перекодировка stdout/stderr и рекурсивная проверка 429
- reconfigure() вместо нового TextIOWrapper — не ломается при редиректе
- _is_429() с рекурсивным обходом ExceptionGroup (anyio оборачивает 429)
- except BaseException в _load_mcp / mcp_call для перехвата ExceptionGroup

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-04 19:00:14 +03:00
Glevel 9cb3731dda fix tasks command: show all tasks with statuses, not only todo
- solve_task: add fetch_all_tasks() for monitoring all task statuses
- console.py: tasks command now uses fetch_all_tasks with formatted table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 13:52:34 +03:00
Glevel 943609f370 add console.py: interactive CLI for managing BroJS tasks
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 13:50:47 +03:00
Glevel 65fe475e42 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>
2026-06-04 12:49:59 +03:00
Glevel 928dabe10e integrate fast solver into pipeline: run_pipeline.py now fully automated
- solve_task.py: add fetch_todo_tasks(), _parse_todo_tasks(), run_all()
- run_all() auto-fetches all todo tasks from BroJS and solves each one
- run_pipeline.py: rewrite to just call run_all() from solve_task
- supports: python run_pipeline.py (auto), run_pipeline.py <id...> (targeted)
- TARGET_IDS list for hardcoded targets without CLI args
- no deepagents imports = no double MCP load on startup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 12:44:07 +03:00
Glevel bd7580c4bc optimize solve_task.py: persistent MCP client, exponential backoff, inter-call delay
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 12:38:23 +03:00
Glevel 420543c89e optimize mcp_client: persistent client, exponential backoff, inter-call delay
- Switch transport to streamable_http (matches solve_task.py)
- Add _persistent_client global to reuse MultiServerMCPClient across calls
- Add exponential backoff 15→30→60→120→240s on 429 responses
- Add _INTER_CALL_DELAY=1.5s between consecutive MCP calls to prevent burst
- Add _is_429() helper for clean 429 detection
- Recreate client on non-429 errors to recover from stale sessions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 12:36:46 +03:00
Glevel 7804122b7e feat: add solve_task.py direct solver and fix MCP rate limit issues
- Add solve_task.py: fast direct solver (1 LLM call per task, no deepagents overhead)
- Add RetryOnRateLimitMiddleware: auto-retry on 429 from any tool
- Fix double MCP load: __init__.py cleared, pipeline reuses agent.py journal tools
- Fix proxy: add NO_PROXY for openrouter.ai, platform.brojs.ru, git.brojs.ru
- Add utility scripts: get_task_ids.py, read_tasks.py
- Update run_pipeline.py: TARGET_IDS support, unbuffered output

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 12:30:05 +03:00
Glevel 5f8b5b9144 add run/check scripts and revert llm to OpenRouter
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 18:47:05 +03:00
Glevel 1d73c5e439 feat: pipeline guarantees task submission regardless of LLM tool calling
Added _force_submit() and _is_submitted() helpers. After the agent
finishes writing code, the pipeline checks if the task was actually
submitted. If not (LLM failed to call tools), the pipeline submits
directly via MCP — no LLM involved in the critical submit step.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 22:57:24 +03:00
Glevel 7744a97012 chore: switch LLM from OpenRouter to BroJS Inference API
Token usage is now tracked on platform.brojs.ru.
Uses the same JOURNAL_TOKEN (jrnl_...) for both MCP and inference.
Removed OPENAI_API_KEY from .env.example.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 18:58:41 +03:00
Glevel 5f4737ce12 fix: syntax error in prompts.py (triple quotes inside triple quotes)
Changed homework_doing_instructions delimiter from """ to ''' to avoid
SyntaxError caused by docstrings inside code examples within the string.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 00:43:47 +03:00
Glevel 698ba21cfd improve: better prompts and rate-limit retry in pipeline
prompts.py:
- Added detailed technical patterns for deepagents, FastMCP, LangGraph,
  HumanInTheLoop, RAG with Qdrant, stream mode, text game
- LLM always via OpenRouter (never hub.pull/Ollama/hardcode)
- FastMCP correct pattern (module-level, NOT inside class)
- create_agent not compatible with AgentExecutor - documented
- DuckDuckGo search pattern (no API key needed)

pipeline.py:
- Added _invoke_with_retry: auto-retry on 429 rate limit (up to 5x, 90s backoff)
- Added TASK_PAUSE (15s) between tasks to reduce rate limit pressure
- Progress logging: per-task status messages
- Imported asyncio and re

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 00:35:02 +03:00
Glevel da0facfd4d fix: add __init__ to SanitizeToolCallsMiddleware
AgentMiddleware is a plain Generic class, not a Pydantic BaseModel,
so class-level field declarations don't work. Explicit __init__ required.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 23:27:25 +03:00
Glevel c95d7375cc feat: initial brojs-agent implementation
AI-агент для автоматического выполнения заданий курса KFU-26-1.
Стек: deepagents + LangGraph + LangChain + OpenRouter (gpt-oss-20b:free).

- Главный агент-оркестратор с субагентами
- homework_direct_agent и rework_agent для сдачи/пересдачи
- Gitea REST API инструменты (git.brojs.ru/glevelll)
- BroJS Journal MCP клиент (platform.brojs.ru)
- LangGraph pipeline: последовательное выполнение всех заданий
- Middleware: SanitizeToolCalls + ValidateJournalWorkflow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 23:08:14 +03:00