Написал скилл

This commit is contained in:
ProgramX 2026-03-28 12:58:16 +03:00
parent 2fb00ed2bc
commit cd736d5a38
9 changed files with 5577 additions and 0 deletions

1
.python-version Normal file
View file

@ -0,0 +1 @@
3.12

View file

@ -0,0 +1,44 @@
# Secure SBP Bridge
Инструментарий для обеспечения безопасности финансовых транзакций в рамках работы ИИ-агентов. Проект реализует механизм передачи платежной сессии пользователю через протокол СБП (Система Быстрых Платежей).
## Описание
Навык предназначен для интеграции в ИИ-агенты на базе фреймворка OpenClaw. Основная задача — исключить прямой доступ модели к платежным картам и автоматизировать процесс извлечения данных для ручной оплаты человеком (Human-in-the-Loop).
## Принципы безопасности
* Изоляция данных: Агент не имеет доступа к реквизитам банковских карт.
* Программная экстракция: Платежные ссылки извлекаются напрямую из контекста браузера, минуя текстовую обработку моделью, что предотвращает подмену URL при инъекциях промпта.
* Внеполосная верификация: Оплата происходит во внешней защищенной среде (банковское приложение на устройстве пользователя).
## Структура проекта
* `src/sbp_bridge/extractor.py`: Логика взаимодействия с Playwright, поиск ссылок и создание скриншотов.
* `src/sbp_bridge/formatter.py`: Формирование структурированного отчета для пользователя.
* `src/sbp_bridge/tool.py`: Интеграционный слой для подключения функции к ИИ-агенту.
* `src/sbp_bridge/SKILL.md`: Системные инструкции, определяющие правила поведения модели.
## Установка и настройка
Для управления зависимостями используется менеджер пакетов `uv`.
1. Установка зависимостей:
```bash
uv sync
```
2. Установка браузеров Playwright:
```bash
uv run playwright install chromium
```
## Алгоритм использования
1. Агент доходит до этапа выбора оплаты в интернет-магазине.
2. При обнаружении интерфейса СБП вызывается инструмент `secure_sbp_handover`.
3. Пользователь получает в мессенджер ссылку на корзину и прямую ссылку на оплату СБП.
4. Агент переходит в режим ожидания.
5. После совершения платежа пользователь отправляет сигнал подтверждения («Готово»), после чего агент завершает задачу.

12
pyproject.toml Normal file
View file

@ -0,0 +1,12 @@
[project]
name = "secure-transactions"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"browser-use>=0.12.5",
"langchain-core>=1.2.23",
"loguru>=0.7.3",
"playwright>=1.58.0",
]

35
src/sbp_bridge/SKILL.md Normal file
View file

@ -0,0 +1,35 @@
# Skill: Secure SBP Payment Bridge (v1.0.0)
## 1. Назначение
Навык предназначен для безопасного завершения процесса покупки в интернет-магазинах и маркетплейсах через Систему Быстрых Платежей (СБП). Реализует протокол "Human-in-the-Loop", исключая прямой доступ ИИ к платежным средствам (картам).
## 2. Глобальные ограничения (Security Policy)
1. **ZERO_CARD_POLICY:** Тебе КАТЕГОРИЧЕСКИ ЗАПРЕЩЕНО запрашивать данные банковских карт у пользователя, сохранять их или пытаться ввести их в формы на сайтах.
2. **NO_AUTO_PAY:** Тебе запрещено нажимать кнопки типа "Оплатить привязанной картой" или использовать любые методы автоплатежа без подтверждения через СБП.
3. **ONLY_SBP:** Единственный разрешенный метод оплаты — СБП (QR-код или платежная ссылка).
## 3. Условия вызова (Triggers)
Вызывай инструмент `secure_sbp_handover` немедленно, если на текущей странице браузера обнаружен один из следующих признаков:
- Кнопка или ссылка с текстом "СБП" или "Система быстрых платежей".
- Графический QR-код в контексте оплаты.
- Переход на домен платежного шлюза (например, `qr.nspk.ru`, `sbp.nspk.ru`).
- Финальная страница оформления заказа (Checkout), требующая выбора метода оплаты.
## 4. Алгоритм действий
1. Дойди до этапа выбора оплаты в магазине.
2. Если доступен выбор методов, выбери "СБП".
3. Как только на экране появилась информация для оплаты (ссылка/QR), вызови инструмент `secure_sbp_handover`.
4. Полученный от инструмента текст (отчет) отправь пользователю БЕЗ изменений и дополнений.
5. **SUSPEND (Остановка):** После отправки отчета прекрати любые активные действия. Не закрывай вкладку с оплатой и не переходи на другие страницы.
## 5. Возобновление и завершение
- Перейди в режим ожидания (Waiting state).
- Твоя задача считается активной, пока пользователь не пришлет сигнал подтверждения (например: "Готово", "Оплатил", "Ок").
- После получения сигнала:
1. Обнови текущую страницу в браузере.
2. Проверь наличие подтверждения заказа (текст "Заказ оформлен", "Спасибо за покупку" или номер заказа).
3. Сообщи пользователю финальный статус задачи и заверши сессию.
- Если пользователь прислал сигнал "Отмена": закрой вкладку оплаты и прекрати выполнение задачи.
## 6. Инструменты
- `secure_sbp_handover`: Программный захват платежных ссылок и создание скриншота верификации.

View file

View file

@ -0,0 +1,88 @@
import os
import time
from loguru import logger
async def capture_payment_data(page):
"""
Основная логика извлечения платежных данных из текущей страницы браузера.
"""
logger.info("Начинаю поиск платежных данных СБП...")
# 1. Даем странице немного времени на подгрузку динамических элементов (QR, кнопки)
await page.wait_for_timeout(2000)
# 2. Пытаемся найти ссылку на оплату СБП
# Мы используем каскадный поиск (от самого точного к общему)
sbp_link = await _find_sbp_link(page)
# 3. Определяем ссылку на корзину (для проверки пользователем)
# Универсальный метод: берем домен текущего сайта
cart_url = _generate_cart_url(page.url)
# 4. Делаем скриншот страницы
# Сохраняем в папку воркспейса бота, чтобы он мог отправить файл
screenshot_path = await _take_screenshot(page)
return {
"sbp_link": sbp_link,
"cart_url": cart_url,
"screenshot_path": screenshot_path,
"domain": cart_url.split("//")[1].split("/")[0],
}
async def _find_sbp_link(page):
"""Внутренняя функция для поиска URL СБП."""
# Случай А: Бот уже перенаправлен на шлюз (например, qr.nspk.ru)
current_url = page.url
if "qr.nspk.ru" in current_url or "sbp.nspk.ru" in current_url:
logger.info("Найден прямой URL платежного шлюза.")
return current_url
# Случай Б: Ссылка спрятана в кнопке на странице магазина
# Ищем любые ссылки или кнопки, содержащие домен СБП или протокол sbp://
selectors = [
'a[href*="qr.nspk.ru"]',
'a[href^="sbp://"]',
'button[data-url*="qr.nspk.ru"]',
]
for selector in selectors:
element = await page.query_selector(selector)
if element:
link = await element.get_attribute("href") or await element.get_attribute(
"data-url"
)
if link:
logger.info(f"Ссылка найдена через селектор: {selector}")
return link
logger.warning("Текстовая ссылка СБП не найдена (возможно, только графический QR).")
return None
def _generate_cart_url(current_url):
"""Формирует стандартную ссылку на корзину для текущего домена."""
try:
from urllib.parse import urlparse
parsed = urlparse(current_url)
return f"{parsed.scheme}://{parsed.netloc}/cart"
except Exception:
return current_url
async def _take_screenshot(page):
"""Делает скриншот и возвращает абсолютный путь к файлу."""
# Создаем папку для скриншотов, если её нет
output_dir = os.path.join(os.getcwd(), "screenshots")
os.makedirs(output_dir, exist_ok=True)
file_name = f"sbp_payment_{int(time.time())}.png"
file_path = os.path.join(output_dir, file_name)
await page.screenshot(path=file_path, full_page=False)
logger.info(f"Скриншот сохранен: {file_path}")
return file_path

View file

@ -0,0 +1,34 @@
def format_payment_report(data):
"""
Формирует нейтральный и структурированный отчет для пользователя.
"""
sbp_link = data.get("sbp_link")
cart_url = data.get("cart_url")
domain = data.get("domain", "не определен")
screenshot_path = data.get("screenshot_path")
# Формируем блок со ссылками
# Если ссылка СБП не найдена, пишем об этом прямо
if sbp_link:
payment_info = f"[Нажмите для оплаты через СБП]({sbp_link})"
else:
payment_info = (
"Текстовая ссылка СБП не обнаружена. Используйте QR-код со скриншота."
)
report = [
"### Запрос на подтверждение транзакции",
f"**Источник:** {domain}",
"",
"Для завершения покупки необходимо выполнить проверку:",
f"1. **Состав заказа:** [Открыть корзину]({cart_url})",
f"2. **Оплата:** {payment_info}",
"",
"**Визуальное подтверждение:** Скриншот страницы оплаты сохранен.",
f"Путь: `{screenshot_path}`",
"",
"---",
"**Инструкция:** Проверьте данные. После оплаты в приложении банка напишите 'Готово' для финализации задачи. Для отмены напишите 'Отмена'.",
]
return "\n".join(report)

40
src/sbp_bridge/tool.py Normal file
View file

@ -0,0 +1,40 @@
from typing import Any
from langchain_core.tools import tool
from loguru import logger
# Мы убираем проблемный импорт BrowserContext
# и импортируем только логику
from .extractor import capture_payment_data
from .formatter import format_payment_report
@tool
async def secure_sbp_handover(context: Any):
"""
Инструмент для безопасной передачи платежной сессии СБП человеку.
Используй этот инструмент ТОЛЬКО когда на экране появился выбор оплаты СБП,
QR-код или ссылка nspk.ru.
Инструмент извлечет ссылки, сделает скриншот и передаст управление пользователю.
"""
logger.info("Вызван инструмент secure_sbp_handover")
try:
# 1. Получаем активную страницу.
# В browser-use это стандартный метод для объекта контекста.
page = await context.get_current_page()
# 2. Извлекаем технические данные
data = await capture_payment_data(page)
# 3. Формируем текст отчета
report_text = format_payment_report(data)
logger.success("Данные подготовлены. Ждем действий пользователя.")
return report_text
except Exception as e:
error_msg = f"Ошибка в sbp_bridge: {str(e)}"
logger.error(error_msg)
return error_msg

5323
uv.lock generated Normal file

File diff suppressed because it is too large Load diff