feat: интеллектуальная cron-система с AI-агентом
Основные изменения: - CronJob теперь хранит prompt для ИИ вместо команды - Добавлены поля: user_id, notify, log_results - Задачи выполняются через AI-агент (автономный выбор инструмента) - Планировщик проверяет задачи каждую минуту - Уведомления отправляются в Telegram (если notify=True) - Результаты сохраняются в cron_logs/ (если log_results=True) - Добавлена команда /cron для управления задачами - Обновлена БД и модель данных Новые файлы: - bot/services/cron_scheduler.py - планировщик задач - CRON_SYSTEM.md - документация Изменённые файлы: - bot/tools/cron_tool.py - обновлён для работы с промптами - bot/handlers/commands.py - добавлена cron_command - bot.py - интеграция планировщика, регистрация команды - .gitignore - исключение cron_logs/ Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
bff74741a6
commit
f559c83baa
|
|
@ -22,6 +22,7 @@ bot_config.json
|
|||
|
||||
# Logs
|
||||
*.log
|
||||
cron_logs/
|
||||
|
||||
# Cache
|
||||
.cache/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,219 @@
|
|||
# 🕐 Интеллектуальная Cron-система
|
||||
|
||||
Интеллектуальная система планирования задач для Telegram CLI Bot.
|
||||
|
||||
## 📋 Особенности
|
||||
|
||||
В отличие от классического cron, задачи выполняются не как команды, а как **промпты для ИИ-агента**.
|
||||
|
||||
### Структура задачи
|
||||
|
||||
```python
|
||||
CronJob:
|
||||
- id: int # Уникальный ID
|
||||
- name: str # Название задачи
|
||||
- prompt: str # Промпт для ИИ-агента
|
||||
- schedule: str # Расписание (@hourly, @daily, */5 * * * *)
|
||||
- user_id: int # ID пользователя Telegram
|
||||
- enabled: bool # Включена ли задача
|
||||
- notify: bool # Уведомлять пользователя в Telegram
|
||||
- log_results: bool # Сохранять результат в лог-файл
|
||||
- last_run: datetime # Последнее выполнение
|
||||
- next_run: datetime # Следующее выполнение
|
||||
- created_at: datetime # Дата создания
|
||||
```
|
||||
|
||||
## 🔄 Процесс выполнения
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Cron Scheduler (проверяет каждую минуту) │
|
||||
│ ↓ (если время пришло) │
|
||||
│ Отправляет промпт ИИ-агенту │
|
||||
│ ↓ │
|
||||
│ ИИ-агент (Рик) анализирует промпт: │
|
||||
│ - Решает какой инструмент использовать │
|
||||
│ - Выполняет инструмент (поиск, SSH, RSS) │
|
||||
│ ↓ │
|
||||
│ Если notify=True → отправка уведомления в Telegram │
|
||||
│ Если log_results=True → сохранение в лог-файл │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 📝 Команды управления
|
||||
|
||||
### `/cron list` - Показать все задачи
|
||||
|
||||
```
|
||||
/cron list
|
||||
```
|
||||
|
||||
**Пример вывода:**
|
||||
```
|
||||
⏰ Ваши задачи:
|
||||
|
||||
✅ Проверка диска (ID: 1)
|
||||
🔔📝 Промпт: Проверить свободное место на сервере...
|
||||
Расписание: @daily
|
||||
Следующий запуск: 2026-02-26 00:00:00
|
||||
Последний запуск: 2026-02-25 00:00:00
|
||||
```
|
||||
|
||||
### `/cron add` - Добавить задачу
|
||||
|
||||
```
|
||||
/cron add <name> <schedule> <prompt>
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `name` - название задачи
|
||||
- `schedule` - расписание:
|
||||
- `@hourly` - каждый час
|
||||
- `@daily` - каждый день
|
||||
- `@weekly` - каждую неделю
|
||||
- `*/5 * * * *` - каждые 5 минут (cron format)
|
||||
- `prompt` - промпт для ИИ-агента
|
||||
|
||||
**Примеры:**
|
||||
|
||||
```bash
|
||||
# Ежедневная проверка диска
|
||||
/cron add check_disk @daily Проверить свободное место на сервере home
|
||||
|
||||
# Ежечасные новости
|
||||
/cron add tech_news @hourly Что нового в Linux сегодня
|
||||
|
||||
# Каждые 5 минут мониторинг
|
||||
/cron add monitor */5 * * * * Проверить нагрузку на сервер
|
||||
```
|
||||
|
||||
### `/cron run` - Выполнить задачу немедленно
|
||||
|
||||
```
|
||||
/cron run <id>
|
||||
```
|
||||
|
||||
**Пример:**
|
||||
```
|
||||
/cron run 1
|
||||
```
|
||||
|
||||
### `/cron remove` - Удалить задачу
|
||||
|
||||
```
|
||||
/cron remove <id>
|
||||
```
|
||||
|
||||
### `/cron toggle` - Включить/выключить задачу
|
||||
|
||||
```
|
||||
/cron toggle <id>
|
||||
```
|
||||
|
||||
## 🛠️ Инструменты ИИ-агента
|
||||
|
||||
При выполнении задачи ИИ-агент может использовать:
|
||||
|
||||
| Инструмент | Назначение | Триггеры |
|
||||
|------------|------------|----------|
|
||||
| `ddgs_tool` | Поиск в интернете | "найди", "поиск", "узнай" |
|
||||
| `rss_tool` | Чтение RSS лент | "новости", "почитай", "лента" |
|
||||
| `ssh_tool` | SSH-команды | "проверь сервер", "выполни команду" |
|
||||
| `cron_tool` | Управление задачами | "напомни", "запланируй" |
|
||||
|
||||
## 📂 Логирование
|
||||
|
||||
Результаты выполнения задач сохраняются в:
|
||||
```
|
||||
cron_logs/
|
||||
cron_job_1_check_disk.log
|
||||
cron_job_2_tech_news.log
|
||||
...
|
||||
```
|
||||
|
||||
**Формат лога:**
|
||||
```
|
||||
============================================================
|
||||
[2026-02-25 10:30:00] Задача: Проверка диска (ID: 1)
|
||||
============================================================
|
||||
Промпт:
|
||||
Проверить свободное место на сервере home
|
||||
|
||||
Результат:
|
||||
Задача 'Проверка диска' выполнена.
|
||||
|
||||
Использован инструмент: ssh_tool
|
||||
Результат: Filesystem Size Used Avail Use% Mounted on
|
||||
...
|
||||
|
||||
```
|
||||
|
||||
## 🔔 Уведомления
|
||||
|
||||
Если `notify=True`, бот отправляет уведомление в Telegram:
|
||||
|
||||
```
|
||||
✅ Задача 'Проверка диска' выполнена.
|
||||
|
||||
Использован инструмент: ssh_tool
|
||||
Результат: Свободно 45GB на /dev/sda1
|
||||
```
|
||||
|
||||
## 💡 Примеры использования
|
||||
|
||||
### 1. Ежедневный мониторинг диска
|
||||
|
||||
```bash
|
||||
/cron add disk_daily @daily Проверить свободное место на сервере home. Если меньше 10GB - предупредить
|
||||
```
|
||||
|
||||
### 2. Ежечасные новости IT
|
||||
|
||||
```bash
|
||||
/cron add it_news @hourly Найти свежие новости про Python и Linux за последний час
|
||||
```
|
||||
|
||||
### 3. Мониторинг нагрузки каждые 5 минут
|
||||
|
||||
```bash
|
||||
/cron add load_monitor */5 * * * * Проверить нагрузку CPU и RAM на сервере
|
||||
```
|
||||
|
||||
### 4. Еженедельный поиск уязвимостей
|
||||
|
||||
```bash
|
||||
/cron add security_scan @weekly Найти информацию о новых уязвимостях в Linux за неделю
|
||||
```
|
||||
|
||||
## 🚀 Архитектура
|
||||
|
||||
```
|
||||
bot/
|
||||
tools/
|
||||
cron_tool.py # Инструмент управления задачами
|
||||
services/
|
||||
cron_scheduler.py # Планировщик (проверка каждую минуту)
|
||||
handlers/
|
||||
commands.py # Обработчик команды /cron
|
||||
```
|
||||
|
||||
## ⚙️ Технические детали
|
||||
|
||||
- **Проверка задач:** каждую минуту (60 секунд)
|
||||
- **Хранение:** SQLite (`cron.db`)
|
||||
- **Логи:** текстовые файлы (`cron_logs/`)
|
||||
- **Формат расписания:** cron format или специальные (@hourly, @daily, @weekly)
|
||||
|
||||
## 🎯 Отличия от классического cron
|
||||
|
||||
| Классический cron | Интеллектуальный cron |
|
||||
|-------------------|----------------------|
|
||||
| Выполняет команды | Выполняет промпты для ИИ |
|
||||
| Жёсткая логика | Гибкое решение через ИИ |
|
||||
| Вывод в stdout/email | Уведомления в Telegram + логи |
|
||||
| Нет контекста | ИИ использует контекст и память |
|
||||
|
||||
---
|
||||
|
||||
*Версия: 0.5.3*
|
||||
*Интеллектуальная cron-система с AI-агентом*
|
||||
63
bot.py
63
bot.py
|
|
@ -77,13 +77,14 @@ from bot.utils.decorators import check_access
|
|||
from bot.keyboards.menus import MenuItem, init_menus
|
||||
|
||||
# Импорты хендлеров из модулей
|
||||
from bot.handlers.commands import start_command, menu_command, help_command, settings_command
|
||||
from bot.handlers.commands import start_command, menu_command, help_command, settings_command, cron_command
|
||||
from bot.handlers.callbacks import menu_callback
|
||||
from bot.services.command_executor import execute_cli_command
|
||||
|
||||
# Импорты инструментов и AI агента
|
||||
from bot.ai_agent import ai_agent
|
||||
from bot.tools import tools_registry
|
||||
from bot.services.cron_scheduler import init_scheduler, get_scheduler
|
||||
|
||||
# Глобальные менеджеры сессий
|
||||
ssh_session_manager = SSHSessionManager()
|
||||
|
|
@ -371,30 +372,41 @@ def format_tool_result(tool_name: str, result: 'ToolResult') -> str:
|
|||
|
||||
return output
|
||||
|
||||
elif tool_name == 'cron_manager':
|
||||
elif tool_name == 'cron_tool':
|
||||
action = result.metadata.get('action', 'list')
|
||||
|
||||
if action == 'list' and result.data:
|
||||
output = "⏰ **Ваши задачи:**\n\n"
|
||||
for job in result.data:
|
||||
status = "✅" if job.get('enabled') else "❌"
|
||||
output += f"{status} **{job.get('name', 'Без названия')}**\n"
|
||||
output += f" Команда: `{job.get('command', '')}`\n"
|
||||
output += f" Расписание: {job.get('schedule', '')}\n"
|
||||
notify_icon = "🔔" if job.get('notify') else "🔕"
|
||||
log_icon = "📝" if job.get('log_results') else "🚫"
|
||||
output += f"{status} **{job.get('name', 'Без названия')}** (ID: {job.get('id')})\n"
|
||||
output += f" {notify_icon}{log_icon} Промпт: _{job.get('prompt', '')[:100]}_{'...' if len(job.get('prompt', '')) > 100 else ''}\n"
|
||||
output += f" Расписание: `{job.get('schedule', '')}`\n"
|
||||
if job.get('next_run'):
|
||||
output += f" Следующий запуск: {job.get('next_run')}\n"
|
||||
if job.get('last_run'):
|
||||
output += f" Последний запуск: {job.get('last_run')}\n"
|
||||
output += "\n"
|
||||
return output
|
||||
|
||||
elif action == 'add' and result.success:
|
||||
data = result.data
|
||||
return f"✅ **Задача добавлена:**\n• ID: {data.get('id')}\n• Название: {data.get('name')}\n• Расписание: {data.get('schedule')}\n• Следующий запуск: {data.get('next_run', 'N/A')}"
|
||||
notify_status = "🔔 Уведомлять" if result.metadata.get('notify') else "🔕 Без уведомлений"
|
||||
log_status = "📝 Логировать" if result.metadata.get('log_results') else "🚫 Без логов"
|
||||
return f"✅ **Задача добавлена:**\n• ID: {data.get('id')}\n• Название: {data.get('name')}\n• Расписание: {data.get('schedule')}\n• {notify_status}, {log_status}\n• Следующий запуск: {data.get('next_run', 'N/A')}"
|
||||
|
||||
elif action == 'remove' and result.success:
|
||||
return f"✅ **Задача удалена:** ID {result.data.get('id')}"
|
||||
|
||||
elif action == 'run' and result.success:
|
||||
return f"✅ **Задача выполнена:** {result.data.get('message', '')}"
|
||||
result_text = result.metadata.get('result_text', 'Задача выполнена')
|
||||
tool_used = result.data.get('tool_used', 'не указан')
|
||||
return f"✅ **Задача выполнена:**\n\n{result_text}\n\n🔧 Инструмент: {tool_used}"
|
||||
|
||||
elif action == 'run' and not result.success:
|
||||
return f"❌ **Ошибка выполнения задачи:**\n{result.error}"
|
||||
|
||||
return f"Cron: {result.data}"
|
||||
|
||||
|
|
@ -1277,6 +1289,7 @@ async def post_init(application: Application):
|
|||
BotCommand("menu", "Главное меню с кнопками"),
|
||||
BotCommand("help", "Справка"),
|
||||
BotCommand("settings", "Настройки"),
|
||||
BotCommand("cron", "Управление задачами"),
|
||||
BotCommand("stop", "Прервать SSH-сессию"),
|
||||
BotCommand("ai", "Задача для Qwen Code AI"),
|
||||
BotCommand("memory", "Статистика памяти ИИ"),
|
||||
|
|
@ -1285,9 +1298,44 @@ async def post_init(application: Application):
|
|||
]
|
||||
await application.bot.set_my_commands(commands)
|
||||
|
||||
# Инициализация планировщика cron-задач
|
||||
cron_tool = tools_registry.get_tool('cron_tool')
|
||||
if cron_tool:
|
||||
scheduler = init_scheduler(cron_tool, ai_agent, send_notification=send_cron_notification)
|
||||
await scheduler.start()
|
||||
logger.info("🕐 Планировщик cron-задач инициализирован")
|
||||
else:
|
||||
logger.warning("⚠️ Cron инструмент не найден, планировщик не запущен")
|
||||
|
||||
logger.info("Бот инициализирован")
|
||||
|
||||
|
||||
async def send_cron_notification(user_id: int, message: str):
|
||||
"""
|
||||
Отправить уведомление пользователю о результате cron-задачи.
|
||||
|
||||
Args:
|
||||
user_id: ID пользователя в Telegram
|
||||
message: Текст уведомления
|
||||
"""
|
||||
try:
|
||||
# Получаем application из контекста
|
||||
from telegram.ext import Application
|
||||
app = Application.get_instance()
|
||||
|
||||
if app:
|
||||
await app.bot.send_message(
|
||||
chat_id=user_id,
|
||||
text=message,
|
||||
parse_mode="Markdown"
|
||||
)
|
||||
logger.info(f"🔔 Уведомление отправлено пользователю {user_id}")
|
||||
else:
|
||||
logger.warning("Application не инициализирован, уведомление не отправлено")
|
||||
except Exception as e:
|
||||
logger.exception(f"Ошибка отправки уведомления: {e}")
|
||||
|
||||
|
||||
@check_access
|
||||
async def stop_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""Обработка команды /stop - прерывание активной SSH-сессии."""
|
||||
|
|
@ -1629,6 +1677,7 @@ def main():
|
|||
application.add_handler(CommandHandler("start", start_command))
|
||||
application.add_handler(CommandHandler("help", help_command))
|
||||
application.add_handler(CommandHandler("settings", settings_command))
|
||||
application.add_handler(CommandHandler("cron", cron_command))
|
||||
application.add_handler(CommandHandler("menu", menu_command))
|
||||
application.add_handler(CommandHandler("stop", stop_command))
|
||||
application.add_handler(CommandHandler("memory", memory_command))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Обработчики команд бота (/start, /menu, /help, /settings)."""
|
||||
"""Обработчики команд бота (/start, /menu, /help, /settings, /cron)."""
|
||||
|
||||
import logging
|
||||
from telegram import Update
|
||||
|
|
@ -8,6 +8,8 @@ from telegram.ext import ContextTypes
|
|||
# Импорты из модулей bot/
|
||||
from bot.config import config, state_manager, server_manager, menu_builder
|
||||
from bot.utils.decorators import check_access
|
||||
from bot.tools import tools_registry
|
||||
from bot.ai_agent import ai_agent
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -114,3 +116,207 @@ async def settings_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||
parse_mode="Markdown",
|
||||
reply_markup=menu_builder.get_keyboard("settings")
|
||||
)
|
||||
|
||||
|
||||
@check_access
|
||||
async def cron_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""
|
||||
Обработка команды /cron - управление задачами.
|
||||
|
||||
Использование:
|
||||
/cron list - показать все задачи
|
||||
/cron add <name> <schedule> <prompt> - добавить задачу
|
||||
/cron run <id> - выполнить задачу немедленно
|
||||
/cron remove <id> - удалить задачу
|
||||
/cron toggle <id> - включить/выключить задачу
|
||||
"""
|
||||
user_id = update.effective_user.id
|
||||
args = context.args
|
||||
|
||||
# Получаем cron инструмент
|
||||
cron_tool = tools_registry.get_tool('cron_tool')
|
||||
if not cron_tool:
|
||||
await update.message.reply_text("❌ Ошибка: cron инструмент не найден")
|
||||
return
|
||||
|
||||
# Парсим команду
|
||||
if not args:
|
||||
# По умолчанию показываем список задач
|
||||
action = 'list'
|
||||
else:
|
||||
action = args[0].lower()
|
||||
|
||||
try:
|
||||
if action == 'list':
|
||||
# Показать все задачи пользователя
|
||||
result = await cron_tool.execute(action='list', user_id=user_id)
|
||||
|
||||
if result.success and result.data:
|
||||
output = "⏰ **Ваши задачи:**\n\n"
|
||||
for job in result.data:
|
||||
status = "✅" if job.get('enabled') else "❌"
|
||||
notify_icon = "🔔" if job.get('notify') else "🔕"
|
||||
log_icon = "📝" if job.get('log_results') else "🚫"
|
||||
output += f"{status} **{job.get('name', 'Без названия')}** (ID: {job.get('id')})\n"
|
||||
output += f" {notify_icon}{log_icon} Промпт: _{job.get('prompt', '')[:100]}_{'...' if len(job.get('prompt', '')) > 100 else ''}\n"
|
||||
output += f" Расписание: `{job.get('schedule', '')}`\n"
|
||||
if job.get('next_run'):
|
||||
output += f" Следующий запуск: {job.get('next_run')}\n"
|
||||
if job.get('last_run'):
|
||||
output += f" Последний запуск: {job.get('last_run')}\n"
|
||||
output += "\n"
|
||||
|
||||
if not output.strip():
|
||||
output = "📭 У вас пока нет задач.\n\nДобавьте задачу командой:\n`/cron add <name> <schedule> <prompt>`"
|
||||
|
||||
await update.message.reply_text(output, parse_mode="Markdown")
|
||||
else:
|
||||
await update.message.reply_text("📭 У вас пока нет задач.")
|
||||
|
||||
elif action == 'add':
|
||||
if len(args) < 4:
|
||||
await update.message.reply_text(
|
||||
"❌ **Недостаточно аргументов**\n\n"
|
||||
"**Использование:**\n"
|
||||
"`/cron add <name> <schedule> <prompt> [notify] [log]`\n\n"
|
||||
"**Примеры:**\n"
|
||||
"`/cron check_disk Ежедневно проверять диск на сервере`\n"
|
||||
"`/cron news hourly Что нового в Linux сегодня`\n\n"
|
||||
"**Расписание:**\n"
|
||||
"• `@hourly` - каждый час\n"
|
||||
"• `@daily` - каждый день\n"
|
||||
"• `@weekly` - каждую неделю\n"
|
||||
"• `*/5 * * * *` - каждые 5 минут",
|
||||
parse_mode="Markdown"
|
||||
)
|
||||
return
|
||||
|
||||
name = args[1]
|
||||
schedule = args[2]
|
||||
# Промпт может содержать пробелы - берём всё после schedule
|
||||
prompt = ' '.join(args[3:])
|
||||
|
||||
# Парсим опциональные параметры
|
||||
notify = 'notify' in prompt.lower()
|
||||
log_results = 'no_log' not in prompt.lower() and 'без_лога' not in prompt.lower()
|
||||
|
||||
result = await cron_tool.execute(
|
||||
action='add',
|
||||
name=name,
|
||||
prompt=prompt,
|
||||
schedule=schedule,
|
||||
user_id=user_id,
|
||||
notify=notify,
|
||||
log_results=log_results
|
||||
)
|
||||
|
||||
if result.success:
|
||||
notify_status = "🔔 Уведомлять" if notify else "🔕 Без уведомлений"
|
||||
log_status = "📝 Логировать" if log_results else "🚫 Без логов"
|
||||
await update.message.reply_text(
|
||||
f"✅ **Задача добавлена:**\n"
|
||||
f"• ID: {result.data.get('id')}\n"
|
||||
f"• Название: {name}\n"
|
||||
f"• Промпт: _{prompt}_\n"
|
||||
f"• Расписание: `{schedule}`\n"
|
||||
f"• {notify_status}, {log_status}\n"
|
||||
f"• Следующий запуск: {result.data.get('next_run', 'N/A')}",
|
||||
parse_mode="Markdown"
|
||||
)
|
||||
else:
|
||||
await update.message.reply_text(f"❌ Ошибка: {result.error}")
|
||||
|
||||
elif action == 'run':
|
||||
if len(args) < 2:
|
||||
await update.message.reply_text("❌ Укажите ID задачи: `/cron run <id>`")
|
||||
return
|
||||
|
||||
try:
|
||||
job_id = int(args[1])
|
||||
except ValueError:
|
||||
await update.message.reply_text("❌ ID должен быть числом")
|
||||
return
|
||||
|
||||
status_msg = await update.message.reply_text("⏳ Выполняю задачу...")
|
||||
|
||||
# Выполняем задачу через AI-агент
|
||||
result = await cron_tool.execute(
|
||||
action='run',
|
||||
job_id=job_id,
|
||||
ai_agent=ai_agent,
|
||||
user_id=user_id
|
||||
)
|
||||
|
||||
await status_msg.delete()
|
||||
|
||||
if result.success:
|
||||
result_text = result.metadata.get('result_text', 'Задача выполнена')
|
||||
tool_used = result.data.get('tool_used', 'не указан')
|
||||
await update.message.reply_text(
|
||||
f"✅ **Задача выполнена:**\n\n{result_text}\n\n🔧 Инструмент: {tool_used}",
|
||||
parse_mode="Markdown"
|
||||
)
|
||||
else:
|
||||
await update.message.reply_text(f"❌ Ошибка: {result.error}")
|
||||
|
||||
elif action == 'remove':
|
||||
if len(args) < 2:
|
||||
await update.message.reply_text("❌ Укажите ID задачи: `/cron remove <id>`")
|
||||
return
|
||||
|
||||
try:
|
||||
job_id = int(args[1])
|
||||
except ValueError:
|
||||
await update.message.reply_text("❌ ID должен быть числом")
|
||||
return
|
||||
|
||||
result = await cron_tool.execute(action='remove', job_id=job_id)
|
||||
|
||||
if result.success:
|
||||
await update.message.reply_text(f"✅ Задача удалена: ID {job_id}")
|
||||
else:
|
||||
await update.message.reply_text(f"❌ Ошибка: {result.error}")
|
||||
|
||||
elif action == 'toggle':
|
||||
if len(args) < 2:
|
||||
await update.message.reply_text("❌ Укажите ID задачи: `/cron toggle <id>`")
|
||||
return
|
||||
|
||||
try:
|
||||
job_id = int(args[1])
|
||||
except ValueError:
|
||||
await update.message.reply_text("❌ ID должен быть числом")
|
||||
return
|
||||
|
||||
# Получаем текущее состояние задачи
|
||||
list_result = await cron_tool.execute(action='list', user_id=user_id)
|
||||
current_state = True
|
||||
for job in list_result.data:
|
||||
if job['id'] == job_id:
|
||||
current_state = job.get('enabled', True)
|
||||
break
|
||||
|
||||
new_state = not current_state
|
||||
result = await cron_tool.execute(action='toggle', job_id=job_id, enabled=new_state)
|
||||
|
||||
if result.success:
|
||||
state_text = "включена" if new_state else "выключена"
|
||||
await update.message.reply_text(f"✅ Задача ID {job_id} {state_text}")
|
||||
else:
|
||||
await update.message.reply_text(f"❌ Ошибка: {result.error}")
|
||||
|
||||
else:
|
||||
await update.message.reply_text(
|
||||
"❌ Неизвестная команда.\n\n"
|
||||
"**Доступные команды:**\n"
|
||||
"• `/cron list` - показать все задачи\n"
|
||||
"• `/cron add <name> <schedule> <prompt>` - добавить задачу\n"
|
||||
"• `/cron run <id>` - выполнить задачу\n"
|
||||
"• `/cron remove <id>` - удалить задачу\n"
|
||||
"• `/cron toggle <id>` - включить/выключить задачу",
|
||||
parse_mode="Markdown"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Ошибка в команде /cron: {e}")
|
||||
await update.message.reply_text(f"❌ Ошибка: {e}")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,168 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Cron Scheduler - планировщик задач для автоматического выполнения.
|
||||
|
||||
Проверяет задачи каждую минуту и выполняет те, у которых наступило время.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from typing import Optional, Callable, Awaitable
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CronScheduler:
|
||||
"""
|
||||
Планировщик cron-задач.
|
||||
|
||||
Автоматически проверяет задачи и выполняет их через AI-агент.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
cron_tool,
|
||||
ai_agent,
|
||||
send_notification: Optional[Callable[[int, str], Awaitable[None]]] = None
|
||||
):
|
||||
"""
|
||||
Инициализировать планировщик.
|
||||
|
||||
Args:
|
||||
cron_tool: Экземпляр CronTool
|
||||
ai_agent: Экземпляр AI-агента для выполнения задач
|
||||
send_notification: Асинхронная функция для отправки уведомлений (user_id, message)
|
||||
"""
|
||||
self.cron_tool = cron_tool
|
||||
self.ai_agent = ai_agent
|
||||
self.send_notification = send_notification
|
||||
self._running = False
|
||||
self._task: Optional[asyncio.Task] = None
|
||||
self._check_interval = 60 # Проверка каждую минуту
|
||||
|
||||
async def start(self):
|
||||
"""Запустить планировщик в фоновом режиме."""
|
||||
if self._running:
|
||||
logger.warning("Планировщик уже запущен")
|
||||
return
|
||||
|
||||
self._running = True
|
||||
self._task = asyncio.create_task(self._run_loop())
|
||||
logger.info("🕐 Планировщик cron-задач запущен")
|
||||
|
||||
async def stop(self):
|
||||
"""Остановить планировщик."""
|
||||
self._running = False
|
||||
if self._task:
|
||||
self._task.cancel()
|
||||
try:
|
||||
await self._task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
logger.info("🕐 Планировщик cron-задач остановлен")
|
||||
|
||||
async def _run_loop(self):
|
||||
"""Основной цикл планировщика."""
|
||||
while self._running:
|
||||
try:
|
||||
await self._check_and_run_tasks()
|
||||
except Exception as e:
|
||||
logger.exception(f"Ошибка в цикле планировщика: {e}")
|
||||
|
||||
await asyncio.sleep(self._check_interval)
|
||||
|
||||
async def _check_and_run_tasks(self):
|
||||
"""Проверить задачи и выполнить те, у которых наступило время."""
|
||||
now = datetime.now()
|
||||
logger.debug(f"🕐 Проверка задач на {now.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
|
||||
# Получаем список всех задач
|
||||
result = await self.cron_tool.list_jobs()
|
||||
|
||||
if not result.success:
|
||||
logger.error(f"Ошибка получения списка задач: {result.error}")
|
||||
return
|
||||
|
||||
jobs = result.data
|
||||
executed_count = 0
|
||||
|
||||
for job in jobs:
|
||||
if not job.get('enabled'):
|
||||
continue
|
||||
|
||||
next_run_str = job.get('next_run')
|
||||
if not next_run_str:
|
||||
continue
|
||||
|
||||
try:
|
||||
next_run = datetime.strptime(next_run_str, '%Y-%m-%d %H:%M:%S')
|
||||
except ValueError:
|
||||
logger.error(f"Ошибка парсинга next_run для задачи {job['id']}: {next_run_str}")
|
||||
continue
|
||||
|
||||
# Если время пришло
|
||||
if now >= next_run:
|
||||
logger.info(f"⏰ Время задачи #{job['id']}: {job['name']}")
|
||||
await self._execute_job(job)
|
||||
executed_count += 1
|
||||
|
||||
if executed_count > 0:
|
||||
logger.info(f"✅ Выполнено задач: {executed_count}")
|
||||
|
||||
async def _execute_job(self, job: dict):
|
||||
"""
|
||||
Выполнить задачу.
|
||||
|
||||
Args:
|
||||
job: Словарь с данными задачи
|
||||
"""
|
||||
job_id = job['id']
|
||||
job_name = job['name']
|
||||
notify = job.get('notify', False)
|
||||
log_results = job.get('log_results', True)
|
||||
user_id = job.get('user_id') # ID пользователя который создал задачу
|
||||
|
||||
# Выполняем задачу через AI-агент
|
||||
result = await self.cron_tool.run_job(
|
||||
job_id=job_id,
|
||||
ai_agent=self.ai_agent,
|
||||
user_id=user_id
|
||||
)
|
||||
|
||||
if result.success:
|
||||
logger.info(f"✅ Задача '{job_name}' выполнена успешно")
|
||||
|
||||
# Отправляем уведомление если нужно
|
||||
if notify and self.send_notification and user_id:
|
||||
result_text = result.metadata.get('result_text', 'Задача выполнена')
|
||||
await self.send_notification(user_id, result_text)
|
||||
else:
|
||||
logger.error(f"❌ Задача '{job_name}' не выполнена: {result.error}")
|
||||
|
||||
if notify and self.send_notification and user_id:
|
||||
await self.send_notification(
|
||||
user_id,
|
||||
f"❌ **Ошибка задачи '{job_name}':**\n{result.error}"
|
||||
)
|
||||
|
||||
def set_notification_callback(self, callback: Callable[[int, str], Awaitable[None]]):
|
||||
"""Установить callback для отправки уведомлений."""
|
||||
self.send_notification = callback
|
||||
|
||||
|
||||
# Глобальный планировщик
|
||||
scheduler: Optional[CronScheduler] = None
|
||||
|
||||
|
||||
def init_scheduler(cron_tool, ai_agent, send_notification=None) -> CronScheduler:
|
||||
"""Инициализировать глобальный планировщик."""
|
||||
global scheduler
|
||||
scheduler = CronScheduler(cron_tool, ai_agent, send_notification)
|
||||
return scheduler
|
||||
|
||||
|
||||
def get_scheduler() -> Optional[CronScheduler]:
|
||||
"""Получить глобальный планировщик."""
|
||||
return scheduler
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Cron Tool - инструмент для управления задачами пользователя.
|
||||
Cron Tool - инструмент для управления интеллектуальными задачами.
|
||||
|
||||
Позволяет создавать, планировать и выполнять периодические задачи.
|
||||
Позволяет создавать, планировать и выполнять периодические задачи через AI-агент.
|
||||
Задачи хранятся как промпты для ИИ, а не как команды.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
|
@ -20,26 +21,46 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
@dataclass
|
||||
class CronJob:
|
||||
"""Задача cron."""
|
||||
"""
|
||||
Интеллектуальная задача cron.
|
||||
|
||||
Attributes:
|
||||
id: ID задачи
|
||||
name: Название задачи
|
||||
prompt: Промпт для ИИ-агента (вместо команды)
|
||||
schedule: Расписание (cron format: "*/5 * * * *" или "@daily", "@hourly")
|
||||
enabled: Включена ли задача
|
||||
user_id: ID пользователя Telegram
|
||||
notify: Уведомлять ли пользователя в Telegram о результате
|
||||
log_results: Сохранять ли результат в лог-файл
|
||||
last_run: Время последнего выполнения
|
||||
next_run: Время следующего выполнения
|
||||
created_at: Время создания
|
||||
"""
|
||||
id: Optional[int]
|
||||
name: str
|
||||
command: str
|
||||
schedule: str # cron format: "*/5 * * * *" или "daily", "hourly"
|
||||
prompt: str # Промпт для ИИ вместо команды
|
||||
schedule: str
|
||||
user_id: Optional[int] = None # ID пользователя Telegram
|
||||
enabled: bool = True
|
||||
notify: bool = False # Уведомлять пользователя в Telegram
|
||||
log_results: bool = True # Сохранять в лог
|
||||
last_run: Optional[datetime] = None
|
||||
next_run: Optional[datetime] = None
|
||||
created_at: datetime = field(default_factory=datetime.now)
|
||||
|
||||
|
||||
class CronTool(BaseTool):
|
||||
"""Инструмент для управления задачами пользователя."""
|
||||
"""Инструмент для управления интеллектуальными задачами пользователя."""
|
||||
|
||||
name = "cron_tool"
|
||||
description = "Управление периодическими задачами пользователя. Создание, планирование и выполнение задач по расписанию."
|
||||
description = "Управление периодическими задачами через AI-агент. Создание, планирование и выполнение задач по расписанию."
|
||||
category = "automation"
|
||||
|
||||
def __init__(self, db_path: str = None):
|
||||
def __init__(self, db_path: str = None, log_dir: str = None):
|
||||
self.db_path = Path(db_path) if db_path else Path(__file__).parent.parent.parent / "cron.db"
|
||||
self.log_dir = Path(log_dir) if log_dir else Path(__file__).parent.parent.parent / "cron_logs"
|
||||
self.log_dir.mkdir(parents=True, exist_ok=True)
|
||||
self._jobs: Dict[int, CronJob] = {}
|
||||
self._init_db()
|
||||
|
||||
|
|
@ -47,18 +68,32 @@ class CronTool(BaseTool):
|
|||
"""Инициализировать БД."""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
|
||||
# Создаём таблицу с user_id
|
||||
c.execute('''
|
||||
CREATE TABLE IF NOT EXISTS cron_jobs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
command TEXT NOT NULL,
|
||||
prompt TEXT NOT NULL,
|
||||
schedule TEXT NOT NULL,
|
||||
user_id INTEGER,
|
||||
enabled INTEGER DEFAULT 1,
|
||||
notify INTEGER DEFAULT 0,
|
||||
log_results INTEGER DEFAULT 1,
|
||||
last_run DATETIME,
|
||||
next_run DATETIME,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
''')
|
||||
|
||||
# Проверяем есть ли колонка user_id (для обратной совместимости)
|
||||
c.execute("PRAGMA table_info(cron_jobs)")
|
||||
columns = [col[1] for col in c.fetchall()]
|
||||
|
||||
if 'user_id' not in columns:
|
||||
logger.info("Добавление колонки user_id в таблицу cron_jobs")
|
||||
c.execute('ALTER TABLE cron_jobs ADD COLUMN user_id INTEGER')
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
|
@ -93,8 +128,18 @@ class CronTool(BaseTool):
|
|||
|
||||
return None
|
||||
|
||||
async def add_job(self, name: str, command: str, schedule: str) -> ToolResult:
|
||||
"""Добавить задачу."""
|
||||
async def add_job(self, name: str, prompt: str, schedule: str, user_id: int = None, notify: bool = False, log_results: bool = True) -> ToolResult:
|
||||
"""
|
||||
Добавить интеллектуальную задачу.
|
||||
|
||||
Args:
|
||||
name: Название задачи
|
||||
prompt: Промпт для ИИ-агента
|
||||
schedule: Расписание (cron format или @daily, @hourly, @weekly)
|
||||
user_id: ID пользователя Telegram
|
||||
notify: Уведомлять ли пользователя в Telegram
|
||||
log_results: Сохранять ли результат в лог
|
||||
"""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
|
||||
|
|
@ -103,9 +148,9 @@ class CronTool(BaseTool):
|
|||
next_run_str = next_run.strftime('%Y-%m-%d %H:%M:%S') if next_run else None
|
||||
|
||||
c.execute('''
|
||||
INSERT INTO cron_jobs (name, command, schedule, next_run)
|
||||
VALUES (?, ?, ?, ?)
|
||||
''', (name, command, schedule, next_run_str))
|
||||
INSERT INTO cron_jobs (name, prompt, schedule, user_id, notify, log_results, next_run)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
''', (name, prompt, schedule, user_id, 1 if notify else 0, 1 if log_results else 0, next_run_str))
|
||||
|
||||
job_id = c.lastrowid
|
||||
conn.commit()
|
||||
|
|
@ -113,15 +158,18 @@ class CronTool(BaseTool):
|
|||
self._jobs[job_id] = CronJob(
|
||||
id=job_id,
|
||||
name=name,
|
||||
command=command,
|
||||
prompt=prompt,
|
||||
schedule=schedule,
|
||||
user_id=user_id,
|
||||
notify=notify,
|
||||
log_results=log_results,
|
||||
next_run=next_run
|
||||
)
|
||||
|
||||
return ToolResult(
|
||||
success=True,
|
||||
data={'id': job_id, 'name': name, 'schedule': schedule, 'next_run': next_run_str},
|
||||
metadata={'status': 'added'}
|
||||
data={'id': job_id, 'name': name, 'prompt': prompt, 'schedule': schedule, 'user_id': user_id, 'next_run': next_run_str},
|
||||
metadata={'status': 'added', 'notify': notify, 'log_results': log_results}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -133,14 +181,27 @@ class CronTool(BaseTool):
|
|||
finally:
|
||||
conn.close()
|
||||
|
||||
async def list_jobs(self) -> ToolResult:
|
||||
"""Получить список всех задач."""
|
||||
async def list_jobs(self, user_id: int = None) -> ToolResult:
|
||||
"""
|
||||
Получить список всех задач.
|
||||
|
||||
Args:
|
||||
user_id: ID пользователя для фильтрации (если None - все задачи)
|
||||
"""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
c.execute('''
|
||||
SELECT id, name, command, schedule, enabled, last_run, next_run, created_at
|
||||
FROM cron_jobs ORDER BY id
|
||||
''')
|
||||
|
||||
if user_id:
|
||||
c.execute('''
|
||||
SELECT id, name, prompt, schedule, user_id, enabled, notify, log_results, last_run, next_run, created_at
|
||||
FROM cron_jobs WHERE user_id = ? ORDER BY id
|
||||
''', (user_id,))
|
||||
else:
|
||||
c.execute('''
|
||||
SELECT id, name, prompt, schedule, user_id, enabled, notify, log_results, last_run, next_run, created_at
|
||||
FROM cron_jobs ORDER BY id
|
||||
''')
|
||||
|
||||
rows = c.fetchall()
|
||||
conn.close()
|
||||
|
||||
|
|
@ -149,12 +210,15 @@ class CronTool(BaseTool):
|
|||
jobs.append({
|
||||
'id': row[0],
|
||||
'name': row[1],
|
||||
'command': row[2],
|
||||
'prompt': row[2],
|
||||
'schedule': row[3],
|
||||
'enabled': bool(row[4]),
|
||||
'last_run': row[5],
|
||||
'next_run': row[6],
|
||||
'created_at': row[7]
|
||||
'user_id': row[4],
|
||||
'enabled': bool(row[5]),
|
||||
'notify': bool(row[6]),
|
||||
'log_results': bool(row[7]),
|
||||
'last_run': row[8],
|
||||
'next_run': row[9],
|
||||
'created_at': row[10]
|
||||
})
|
||||
|
||||
return ToolResult(
|
||||
|
|
@ -206,11 +270,21 @@ class CronTool(BaseTool):
|
|||
metadata={'status': 'toggled'}
|
||||
)
|
||||
|
||||
async def run_job(self, job_id: int) -> ToolResult:
|
||||
"""Выполнить задачу немедленно."""
|
||||
async def run_job(self, job_id: int, ai_agent=None, user_id: int = None) -> ToolResult:
|
||||
"""
|
||||
Выполнить интеллектуальную задачу через AI-агент.
|
||||
|
||||
Args:
|
||||
job_id: ID задачи
|
||||
ai_agent: Экземпляр AI-агента для выполнения промпта
|
||||
user_id: ID пользователя для контекста
|
||||
|
||||
Returns:
|
||||
ToolResult с результатом выполнения
|
||||
"""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT command FROM cron_jobs WHERE id = ?", (job_id,))
|
||||
c.execute("SELECT name, prompt, notify, log_results FROM cron_jobs WHERE id = ?", (job_id,))
|
||||
row = c.fetchone()
|
||||
|
||||
if not row:
|
||||
|
|
@ -220,47 +294,145 @@ class CronTool(BaseTool):
|
|||
error=f"Задача не найдена: {job_id}"
|
||||
)
|
||||
|
||||
command = row[0]
|
||||
name, prompt, notify, log_results = row
|
||||
conn.close()
|
||||
|
||||
# Здесь должна быть логика выполнения команды
|
||||
# Для демонстрации возвращаем заглушку
|
||||
logger.info(f"Выполнение задачи {job_id}: {command}")
|
||||
logger.info(f"🕐 Выполнение задачи #{job_id}: {name}")
|
||||
logger.info(f" Промпт: {prompt}")
|
||||
|
||||
# Обновляем last_run
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("UPDATE cron_jobs SET last_run = datetime('now') WHERE id = ?", (job_id,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
result_data = {
|
||||
'id': job_id,
|
||||
'name': name,
|
||||
'prompt': prompt,
|
||||
'executed_at': datetime.now().isoformat()
|
||||
}
|
||||
|
||||
return ToolResult(
|
||||
success=True,
|
||||
data={'id': job_id, 'command': command, 'message': 'Задача выполнена'},
|
||||
metadata={'status': 'executed'}
|
||||
)
|
||||
# Выполняем задачу через AI-агент
|
||||
if ai_agent:
|
||||
try:
|
||||
# Отправляем промпт ИИ-агенту
|
||||
logger.info(f"🤖 Отправка промпта AI-агенту для задачи {name}")
|
||||
|
||||
async def execute(self, action: str = "list", **kwargs) -> ToolResult:
|
||||
# ИИ-агент анализирует промпт и решает какой инструмент использовать
|
||||
decision = await ai_agent.decide(prompt, context={'user_id': user_id})
|
||||
|
||||
if decision.should_use_tool:
|
||||
logger.info(f"🔧 AI-агент решил использовать инструмент: {decision.tool_name}")
|
||||
tool_result = await ai_agent.execute_tool(decision.tool_name, **decision.tool_args)
|
||||
|
||||
result_data['tool_used'] = decision.tool_name
|
||||
result_data['tool_result'] = tool_result.to_dict() if hasattr(tool_result, 'to_dict') else str(tool_result)
|
||||
result_data['success'] = tool_result.success
|
||||
|
||||
# Формируем результат
|
||||
result_text = f"Задача '{name}' выполнена.\n\n"
|
||||
result_text += f"Использован инструмент: {decision.tool_name}\n"
|
||||
if tool_result.success:
|
||||
result_text += f"Результат: {tool_result.data or 'Успешно'}"
|
||||
else:
|
||||
result_text += f"Ошибка: {tool_result.error}"
|
||||
|
||||
else:
|
||||
# ИИ решил что инструмент не нужен - выполняем промпт напрямую
|
||||
logger.info(f"ℹ️ AI-агент решил что инструмент не требуется")
|
||||
result_text = f"Задача '{name}' выполнена (без инструментов).\nПромпт: {prompt}"
|
||||
result_data['success'] = True
|
||||
result_data['ai_reasoning'] = decision.reasoning
|
||||
|
||||
# Сохраняем в лог если нужно
|
||||
if log_results:
|
||||
self._save_to_log(job_id, name, prompt, result_text)
|
||||
|
||||
# Обновляем last_run
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("UPDATE cron_jobs SET last_run = datetime('now') WHERE id = ?", (job_id,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return ToolResult(
|
||||
success=True,
|
||||
data=result_data,
|
||||
metadata={
|
||||
'status': 'executed',
|
||||
'notify': notify,
|
||||
'log_results': log_results,
|
||||
'result_text': result_text
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Ошибка выполнения задачи через AI-агент: {e}")
|
||||
|
||||
if log_results:
|
||||
self._save_to_log(job_id, name, prompt, f"Ошибка: {e}")
|
||||
|
||||
return ToolResult(
|
||||
success=False,
|
||||
error=str(e),
|
||||
data=result_data
|
||||
)
|
||||
else:
|
||||
# AI-агент не предоставлен - просто логируем
|
||||
logger.warning(f"AI-агент не предоставлен, задача {name} не выполнена")
|
||||
|
||||
if log_results:
|
||||
self._save_to_log(job_id, name, prompt, "Ошибка: AI-агент не предоставлен")
|
||||
|
||||
return ToolResult(
|
||||
success=False,
|
||||
error="AI-агент не предоставлен",
|
||||
data=result_data
|
||||
)
|
||||
|
||||
def _save_to_log(self, job_id: int, job_name: str, prompt: str, result: str):
|
||||
"""Сохранить результат выполнения задачи в лог-файл."""
|
||||
log_file = self.log_dir / f"cron_job_{job_id}_{job_name}.log"
|
||||
|
||||
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
log_entry = f"""
|
||||
{'='*60}
|
||||
[{timestamp}] Задача: {job_name} (ID: {job_id})
|
||||
{'='*60}
|
||||
Промпт:
|
||||
{prompt}
|
||||
|
||||
Результат:
|
||||
{result}
|
||||
|
||||
"""
|
||||
|
||||
with open(log_file, 'a', encoding='utf-8') as f:
|
||||
f.write(log_entry)
|
||||
|
||||
logger.debug(f"Результат задачи {job_name} сохранён в лог: {log_file}")
|
||||
|
||||
async def execute(self, action: str = "list", ai_agent=None, user_id: int = None, **kwargs) -> ToolResult:
|
||||
"""
|
||||
Выполнить действие с cron задачами.
|
||||
|
||||
Args:
|
||||
action: Действие - list, add, remove, toggle, run
|
||||
ai_agent: Экземпляр AI-агента (для run)
|
||||
user_id: ID пользователя (для add, run, list)
|
||||
kwargs: Дополнительные аргументы
|
||||
"""
|
||||
actions = {
|
||||
'list': self.list_jobs,
|
||||
'list': lambda: self.list_jobs(user_id=user_id),
|
||||
'add': lambda: self.add_job(
|
||||
name=kwargs.get('name'),
|
||||
command=kwargs.get('command'),
|
||||
schedule=kwargs.get('schedule')
|
||||
prompt=kwargs.get('prompt'),
|
||||
schedule=kwargs.get('schedule'),
|
||||
user_id=user_id,
|
||||
notify=kwargs.get('notify', False),
|
||||
log_results=kwargs.get('log_results', True)
|
||||
),
|
||||
'remove': lambda: self.remove_job(job_id=kwargs.get('job_id')),
|
||||
'toggle': lambda: self.toggle_job(
|
||||
job_id=kwargs.get('job_id'),
|
||||
enabled=kwargs.get('enabled', True)
|
||||
),
|
||||
'run': lambda: self.run_job(job_id=kwargs.get('job_id'))
|
||||
'run': lambda: self.run_job(job_id=kwargs.get('job_id'), ai_agent=ai_agent, user_id=user_id)
|
||||
}
|
||||
|
||||
if action not in actions:
|
||||
|
|
|
|||
Loading…
Reference in New Issue