中文翻译暂不可用,显示俄语原文。
Агент с внешними API (Slack, Gmail, Calendar)
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Агент с внешними API (Slack, Gmail, Calendar)
1. Цель задачи
Создать программного агента, который интегрируется с тремя внешними сервисами — Slack, Gmail и Google Calendar — для автоматизации типового рабочего сценария: получение запроса на встречу из Slack, создание события в календаре и отправка подтверждения по электронной почте. Задача направлена на отработку навыков работы с REST API, OAuth-аутентификацией, обработки данных в реальном времени и написания изолированных юнит-тестов для каждого интеграционного модуля.
Ключевой результат полностью рабочий агент, запускаемый командой python main.py --scenario "meeting_request", который успешно выполняет E2E-сценарий, а также набор юнит-тестов с покрытием каждого модуля не менее 80%.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Учётная запись Slack и workspace | Slack API (https://api.[slack](/wiki/Slack).com/apps) — создать приложение с правами channels:history, chat:write, users:read |
| Учётная запись Google (Gmail, Calendar) | Google Cloud Console (https://console.cloud.google.com) — включить Gmail API и Google Calendar API, создать OAuth 2.0 Client ID (desktop application) |
| Доступ к API через токены/креды | Slack: Bot Token (xoxb-...); Google: credentials.json для OAuth, получить token.json после первой авторизации |
| Среда разработки | Python 3.11+, любой текстовый редактор / IDE, Git |
| Дополнительные данные | Тестовые каналы Slack (#test-bot), тестовые email (you+test@gmail.com), тестовый календарь Google (можно основной) |
Если нет реального инструмента — симулируем:
- Вместо реального Slack можно написать фейковый HTTP-сервер (Flask) на порту 5050, который эмулирует ответы Slack API (list conversations, post message, get user info).
- Для Gmail/Calendar — использовать библиотеку unittest.mock для подмены всех HTTP-запросов внутри google-api-python-client.
- Для локального тестирования OAuth — создать mock_credentials.json и заглушку google.oauth2.credentials.Credentials, которая возвращает статичный token.json.
- Все моки описаны в файле
tests/mocks.pyи переиспользуются в тестах.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Язык программирования | Python 3.11+ | Основной язык разработки |
| Управление зависимостями | Poetry (или pip + virtualenv) | Изолированное окружение |
| Slack API | slack_sdk (>=3.27) | Взаимодействие с Slack (чтение каналов, отправка сообщений) |
| Google APIs | google-api-python-client, google-auth-httplib2, google-auth-oauthlib | Работа с Gmail и Calendar |
| HTTP-клиент | requests (>=2.31) | Альтернативный прямой вызов REST (если нужно) |
| Тестирование | pytest (>=7.4), pytest-mock (>=3.12), pytest-cov | Юнит-тесты и измерение покрытия |
| Форматирование и линтинг | black, ruff | Единый стиль кода |
| CI (опционально) | GitHub Actions | Запуск тестов при пуше |
| Хранение секретов | .env (python-dotenv) | Токены и credentials |
4. Этапы выполнения
Этап 1: Подготовка окружения и получение доступов (оценка времени: 1.5 часа)
Действия
- Создать репозиторий и структуру папок:
project-root/ ├── src/ │ ├── __init__.py │ ├── slack_client.py │ ├── gmail_client.py │ ├── calendar_client.py │ ├── agent.py │ └── utils.py ├── tests/ │ ├── __init__.py │ ├── mocks.py │ ├── test_slack_client.py │ ├── test_gmail_client.py │ ├── test_calendar_client.py │ └── test_agent.py ├── .env.example ├── pyproject.toml └── README.md - Инициализировать Poetry: poetry new agent_integrations или poetry init.
- Установить зависимости:
poetry add slack_sdk google-api-python-client google-auth-httplib2 google-auth-oauthlib requests python-dotenv poetry add --dev pytest pytest-mock pytest-cov black ruff - Зарегистрировать Slack App на api.slack.com:
- Создать приложение, бот-токен, добавить бота в тестовый канал.
- Сохранить токен в .env как
SLACK_BOT_TOKEN.
- В Google Cloud Console:
- Включить Gmail API и Google Calendar API.
- Создать OAuth 2.0 Client ID (тип Desktop), скачать credentials.json, поместить в корень.
- Выполнить первый запуск (ручная авторизация) для получения
token.json(заглушка на этапе тестов).
- Создать файл
.envс переменными:SLACK_BOT_TOKEN=xoxb-... GOOGLE_CREDENTIALS_PATH=credentials.json GOOGLE_TOKEN_PATH=token.json SLACK_TEST_CHANNEL=C123456 - Настроить линтеры (pyproject.toml):
[tool.black] line-length = 100 [tool.ruff] target-version = "py311"
Ожидаемый результат этапа
- Рабочее Python-окружение,
.envс токенами,credentials.jsonиtoken.json(если реальный доступ). - Структура папок с пустыми модулями.
Этап 2: Реализация модуля Slack (оценка времени: 2 часа)
Действия
- В
src/slack_client.pyсоздать классSlackClient:- init принимает токен и имя тестового канала.
- Метод
get_latest_message(channel_id: str, limit: int = 1)— возвращает последнее сообщение из канала. - Метод
post_message(channel_id: str, text: str)— отправляет сообщение. - Метод
get_user_email(user_id: str)— получает email пользователя Slack (для интеграции с Gmail).
- Использовать
slack_sdk.WebClient, обернуть все вызовы в try-except, логировать ошибки. - Добавить простую обработку rate limit (retry с экспоненциальной задержкой).
- Написать тестовую заглушку в
tests/mocks.py:class MockWebClient: def __init__(self): self.conversations_history = lambda channel, limit: {"ok": True, "messages": [{"text": "meeting tomorrow 3pm", "user": "U123"}]} self.chat_postMessage = lambda channel, text: {"ok": True, "ts": "12345"} self.users_info = lambda user: {"ok": True, "user": {"profile": {"email": "test@example.com"}}} - Проверить импорт:
from src.slack_client import SlackClientбез ошибок.
Ожидаемый результат этапа
- Рабочий класс
SlackClientс тремя методами. - Моки для тестов.
Этап 3: Реализация модулей Gmail и Calendar (оценка времени: 2.5 часа)
Действия
- В
src/gmail_client.py— классGmailClient:- init принимает путь к
credentials.jsonиtoken.json. send_email(to: str, subject: str, body: str)— отправляет письмо через Gmail API.- Использовать
googleapiclient.discovery.buildдля сервисаgmailv1. - Обработка ошибок (квоты, неверный адрес).
- init принимает путь к
- В
src/calendar_client.py— классCalendarClient:create_event(summary: str, start_time: datetime, duration_minutes: int, attendees: list[str])— создаёт событие в Google Calendar.- Использовать сервис
calendarv3. - Формат события (RFC 3339), напоминания (email, popup).
- Для локального тестирования в
tests/mocks.pyсоздать:MockGmailService— заглушка дляusers.messages.send.MockCalendarService— заглушка дляevents.insert.
- В
src/utils.pyнаписать функциюparse_meeting_request(text: str) -> dict:- Из текста выделить тему встречи, время (использовать библиотеку
dateparserили регулярки). - Пример:
"meeting tomorrow 3pm"→{"summary": "meeting", "start": datetime.now()+timedelta(days=1, hours=15), "duration": 60}. - (Опционально) Упрощённый парсер без NLP.
- Из текста выделить тему встречи, время (использовать библиотеку
Ожидаемый результат этапа
- Классы
GmailClientиCalendarClientс методами. - Функция парсинга запросов.
- Моки для Gmail и Calendar.
Этап 4: Сборка агента и E2E сценарий (оценка времени: 1.5 часа)
Действия
- В
src/agent.pyсоздать классMeetingAgent:- init принимает экземпляры трёх клиентов.
- Метод
run(channel_id: str):- Получить последнее сообщение из Slack (
slack.get_latest_message). - Извлечь email пользователя из Slack (
slack.get_user_email). - Распарсить запрос (
parse_meeting_request). - Создать событие в календаре (
calendar.create_event). - Отправить подтверждение по email (
gmail.send_email). - Ответить в Slack, что всё завершено (
slack.post_message).
- Получить последнее сообщение из Slack (
- Обработка исключений: логирование, ретраи, fallback (например, если нет email — не создавать событие).
- Написать точку входа
main.py:import argparse, os from dotenv import load_dotenv from src.slack_client import SlackClient from src.gmail_client import GmailClient from src.calendar_client import CalendarClient from src.agent import MeetingAgent load_dotenv() parser = argparse.ArgumentParser() parser.add_argument("--scenario", default="meeting_request") args = parser.parse_args() if args.scenario == "meeting_request": slack = SlackClient(os.getenv("SLACK_BOT_TOKEN"), os.getenv("SLACK_TEST_CHANNEL")) gmail = GmailClient(os.getenv("GOOGLE_CREDENTIALS_PATH"), os.getenv("GOOGLE_TOKEN_PATH")) calendar = CalendarClient(os.getenv("GOOGLE_CREDENTIALS_PATH"), os.getenv("GOOGLE_TOKEN_PATH")) agent = MeetingAgent(slack, gmail, calendar) agent.run(os.getenv("SLACK_TEST_CHANNEL")) - Проверить локальный запуск (с реальными API или заглушками):
- Переключение между реальным и mock-режимом через переменную окружения
USE_MOCK=1.
- Переключение между реальным и mock-режимом через переменную окружения
- Опционально: добавить возможность запускать другие сценарии (аргумент
--scenario).
Ожидаемый результат этапа
- Центральный класс
MeetingAgent, файлmain.py. - Агент корректно выполняет сценарий при реальном доступе или при подмене моков.
Этап 5: Юнит-тесты (оценка времени: 2 часа)
Действия
- В
tests/test_slack_client.py— тесты дляSlackClient:test_get_latest_message_returns_text— подменяемWebClientчерез mock, проверяем, что возвращается текст.test_post_message_calls_api— проверяем, что вызываетсяchat.postMessageс нужными параметрами.test_get_user_email_returns_email— проверяем извлечение email.test_handles_rate_limit— имитируем HTTP-ошибку 429, проверяем ретрай.
- В
tests/test_gmail_client.py:test_send_email_calls_api— mock сервиса Gmail, проверка вызова.test_send_email_invalid_recipient— обработка ошибки 400.
- В
tests/test_calendar_client.py:test_create_event_returns_event_id— mock сервиса Calendar.test_create_event_requires_valid_time— проверка валидации.
- В
tests/test_agent.py— интеграционные тесты с моками всех трёх клиентов:test_meeting_request_happy_path— полный сценарий.test_meeting_request_missing_email— сценарий, когда email не найден (агент не создаёт событие, но отправляет сообщение об ошибке в Slack).
- В
tests/test_utils.py:test_parse_meeting_request_basic— парсинг строки "meeting tomorrow 3pm".test_parse_meeting_request_no_time— возврат дефолтного времени.
- Все тесты запускать с опцией
--cov=src, требовать покрытие >= 80%. - Создать
pytest.ini:[pytest] testpaths = tests addopts = --cov=src --cov-report=term-missing -v
Ожидаемый результат этапа
- Набор из минимум 10 юнит-тестов.
- Покрытие исходного кода тестами > 80%.
- Возможность прогона одной командой
pytest.
5. Критерии приемки (Definition of Done)
- Репозиторий содержит полный код модулей
slack_client,gmail_client,calendar_client,agent,utils. - Реализован сценарий "meeting_request": получение сообщения из Slack → создание события в Calendar → отправка email → ответ в Slack.
- Все три интеграции имеют юнит-тесты, покрывающие как успешный путь, так и основные ошибки (rate limit, отсутствие прав, неверные данные).
- Общее покрытие кода тестами (измеренное
pytest-cov) составляет не менее 80 %. -
main.pyзапускается с аргументом--scenario meeting_request(или без аргумента) без ошибок (режим mock или real). - В проекте есть README.md с описанием архитектуры, инструкцией по настройке (регистрация приложений, .env) и запуску.
- Код отформатирован Black, линтинг Ruff без ошибок.
- CI (GitHub Actions) успешно прогоняет тесты (опционально: настроен .github/workflows/tests.yml).
6. Ожидаемый результат
На выходе — директория agent-integrations (или название на усмотрение студента) со следующим содержимым:
src/— исходный код (модули Slack, Gmail, Calendar, Agent, утилиты).tests/— юнит-тесты для каждого модуля.main.py— точка входа для запуска агента..env.example— шаблон с переменными (без реальных токенов).pyproject.toml(илиrequirements.txt) — список зависимостей.README.md— описание задачи, настройка, запуск, результаты тестов.
Опциональные дополнительные результаты:
docs/ARCHITECTURE.md— диаграмма взаимодействия компонентов.scripts/demo.sh— скрипт демонстрации сценария (создание тестового сообщения в Slack, прогон, проверка календаря).
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| OAuth 2.0 для Google требует браузерного подтверждения при первом запуске | Для тестов использовать заранее сохранённый token.json (один раз получить вручную). В CI использовать service account (GSuite) или мок-credentials. |
Slack API не возвращает email пользователя без прав users:read.email | Убедиться, что при регистрации приложения включён скоуп users:read.email. В тестах возвращать email из mock. |
| Rate limit у Google Calendar (100 событий в час) | Ввести очередь с задержкой (time.sleep(0.1) перед вызовом). В тестах не проверять лимиты. |
| Синтаксис парсинга времени из сообщения может быть ненадёжным | Использовать dateparser с поддержкой русского и английского. Для простоты задать фиксированный формат: "встреча завтра в 15:00". |
| Разные форматы времени в Gmail/Calendar (RFC 3339) | Конвертировать через datetime.isoformat() и передавать строку. |
8. Бюджет времени (оценка)
| Этап | Время (часы) |
|---|---|
| 1. Подготовка окружения и получение доступов | 1.5 |
| 2. Реализация модуля Slack | 2.0 |
| 3. Реализация модулей Gmail и Calendar | 2.5 |
| 4. Сборка агента и E2E сценарий | 1.5 |
| 5. Юнит-тесты | 2.0 |
| Итого | 9.5 |
Примечание: при первом выполнении рекомендуется заложить +1.5 часа на регистрацию приложений и решение неожиданных ошибок OAuth.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 42 | Работа с REST API и HTTP-сетевые запросы |
| 115 | Библиотека для работы со Slack API (slack_sdk) |
| 203 | Модульное тестирование с pytest и mock |
| 314 | OAuth 2.0 аутентификация в Google APIs |
| 456 | Обработка ошибок и исключений при вызове внешних сервисов |
| 523 | Создание и управление событиями Google Calendar |
| 678 | Автоматизация сценариев с помощью event-driven архитектуры |
| 789 | CI/CD с GitHub Actions: настройка прогона тестов |
| 821 | Форматирование кода и линтинг в Python-проектах |
| 900 | Работа с переменными окружения и конфиденциальными данными |
10. Чек-лист самопроверки
- Я зарегистрировал(а) Slack App и указал(а) правильный бот-токен.
- Я создал(а) OAuth 2.0 Client ID в Google Cloud Console и скачал(а)
credentials.json. - Я выполнил(а) первый ручной запуск для получения
token.json(или настроил(а) мок для тестов). - Все три интеграции работают изолированно: я запускал(а)
python src/slack_client.py(тестовый прогон) и получил(а) данные. - Я написал(а) тесты для каждого клиента и агента, и покрытие кода не меньше 80% по отчёту
pytest --cov. - Я проверил(а) сценарий "meeting_request" в mock-режиме: агент создаёт событие, отправляет email и сообщение в Slack.
- Я удалил(а) реальные токены из репозитория и убедился(ась), что
.envдобавлен в.gitignore. - README содержит понятную инструкцию по настройке и запуску проекта.