- backend на fastapi
- mock mcp service на fastapi
- jwt auth для rest и websocket
- postgresql через sqlalchemy
- alembic миграции
- хранение чатов и сообщений
- file artifact через отдельное сообщение
- suggested actions через отдельное websocket событие
- trace_id на один agent flow
- простой websocket test client
- pytest тесты без реального llm
make docker-upbackend будет доступен на http://localhost:8000
swagger будет доступен на http://localhost:8000/docs
mock mcp будет доступен на http://localhost:8001
email: demo@example.test
password: demo12345
демо пользователь, демо чат и демо сообщение создаются в alembic миграции 202604290001_initial_schema_and_demo.py
создай базу postgresql и экспортируй переменные окружения
export DATABASE_URL=postgresql+psycopg://chat:chat@localhost:5432/chat_assistant
export JWT_SECRET=dev-secret-change-me
export MCP_BASE_URL=http://localhost:8001установи зависимости
make installпримени миграции
make migrateзапусти mock mcp
make run-mcpв другом терминале запусти backend
make run-backendmake install
make migrate
make run-backend
make run-mcp
make test
make up
make down
make docker-wspost /api/auth/register
post /api/auth/login
get /api/chats
post /api/chats
get /api/chats/{chat_id}
get /api/chats/{chat_id}/messages
get /api/chats/{chat_id}/messages/{message_id}/download
для rest ручек кроме register и login нужен header
authorization: bearer <token>
ws /api/chats/{chat_id}/ws?token=<jwt>
сообщение клиента
{
"content": "привет",
"scenario": "get_case_summary"
}события сервера
user_message
assistant_message
tool_message
file_message
suggested
system_event
plain
get_case_summary
calculate_case_score
generate_case_file
suggest_next_steps
unknown_tool
timeout_tool_call
invalid_file_artifact
too_long_tool_loop
регистрация
curl -s -X POST http://localhost:8000/api/auth/register \
-H 'content-type: application/json' \
-d '{"email":"student@example.test","password":"secret123","name":"студент"}'логин демо пользователя
curl -s -X POST http://localhost:8000/api/auth/login \
-H 'content-type: application/json' \
-d '{"email":"demo@example.test","password":"demo12345"}'создание чата
curl -s -X POST http://localhost:8000/api/chats \
-H 'authorization: bearer <token>' \
-H 'content-type: application/json' \
-d '{"title":"проверка","scenario":"generate_case_file"}'получение сообщений
curl -s http://localhost:8000/api/chats/<chat_id>/messages \
-H 'authorization: bearer <token>'python scripts/ws_client.py --scenario get_case_summary
python scripts/ws_client.py --scenario generate_case_file
python scripts/ws_client.py --scenario suggest_next_stepsклиент логинится демо пользователем, создает чат если --chat-id не передан и печатает события до assistant_message
- register нового пользователя через
/api/auth/register - login созданного пользователя через
/api/auth/login - создать чат со сценарием
plain - открыть websocket и получить
user_messageплюсassistant_message - создать чат со сценарием
get_case_summaryи получитьtool_message - создать чат со сценарием
generate_case_fileи получитьfile_message - скачать file artifact через
/download - создать чат со сценарием
suggest_next_stepsи получить отдельное событиеsuggested - подключиться к websocket без token и получить отказ подключения
- создать чат одним пользователем и попробовать прочитать его вторым пользователем, должен вернуться
404
user -> websocket /api/chats/{chat_id}/ws -> agent-service -> fake llm -> mock mcp /tools -> mock mcp /call_tool -> messages table -> websocket events -> frontend client
- websocket проверяет jwt token и владельца чата
- user message сохраняется в
messages - agent-service создает
trace_id - agent-service загружает tools из mock mcp service
- fake llm выбирает обычный ответ или tool call
- agent-service вызывает mock mcp через
/call_tool - результат tool сохраняется как
tool,fileили используется для событияsuggested - assistant message сохраняется в историю
- websocket отправляет события клиенту
- tool loop останавливается по
MAX_TOOL_ITERATIONS
make testпокрыты auth, chats, websocket, tool call, file artifact, suggested actions, чужие чаты, отсутствие websocket token, unknown tool, timeout tool call, invalid file artifact и слишком длинный tool loop