diff --git a/openspec/changes/local-extractor/.openspec.yaml b/openspec/changes/local-extractor/.openspec.yaml deleted file mode 100644 index 1a62d62..0000000 --- a/openspec/changes/local-extractor/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-09-06 diff --git a/openspec/changes/local-extractor/design.md b/openspec/changes/local-extractor/design.md deleted file mode 100644 index 47da356..0000000 --- a/openspec/changes/local-extractor/design.md +++ /dev/null @@ -1,46 +0,0 @@ -# Design: local-extractor - -## Approach - -Расширить существующий `/opt/hermes/.hermes/scripts/tavily_extract_proxy.py`: - -- В local-режиме (нет `--socks`) сервер НЕ проксирует в Tavily, а сам извлекает: для каждого URL делает HTTP-запрос (`httpx`, при `--local-socks` через SOCKS5-туннель) и конвертирует HTML → Markdown через `trafilatura` (включён в venv). -- Формат ответа в точности повторяет Tavily `/extract`: `{"results":[{url,title,raw_content,metadata}], "failed_results":[{url,error}], "failed_urls":[...]}` — Hermes-провайдер (`plugins/web/tavily/provider.py:_normalize_tavily_documents`) обрабатывает его без изменений. -- Режимы взаимозаменяемы через аргументы CLI: - - `--socks 127.0.0.1:1080` — forward в Tavily (как сейчас в systemd) - - `--local` или ничего — локальная экстракция - - `--local-socks 127.0.0.1:1080` — локальная, но страницы через туннель -- systemd-юнит указать на tavily_extract_proxy.py (уже сделано, forward-режим). - -## Files - -- `/opt/hermes/.hermes/scripts/tavily_extract_proxy.py` — добавлены `_fetch_page`, `_extract_local`, `_extract_local_batch`, `--local-socks` -- `/opt/hermes/.hermes/hermes-agent/venv/` — установлен trafilatura 2.2.0 -- `/etc/systemd/system/tavily-proxy.service` — ExecStart → tavily_extract_proxy.py (forward), `--socks 127.0.0.1:1080` - -## Commands - -```bash -# Локальный режим (тест) -python3 /opt/hermes/.hermes/scripts/tavily_extract_proxy.py --port 8972 --local -curl -s -X POST http://127.0.0.1:8972/extract -H 'Content-Type: application/json' \ - -d '{"urls":["https://example.com"]}' # → {"results":[...]} - -# Переключение systemd на local (когда решено отказаться от облака) -# в /etc/systemd/system/tavily-proxy.service: ExecStart → ... --port 8971 --local -# sudo systemctl daemon-reload && sudo systemctl restart tavily-proxy -``` - -## Rollback - -```bash -# Вернуть forward-режим: -# ExecStart → ... --socks 127.0.0.1:1080 --upstream https://api.tavily.com -sudo systemctl daemon-reload && sudo systemctl restart tavily-proxy -``` - -## Risks - -- trafilatura хуже Tavily на JS-heavy страницах (нет headless-браузера) — приемлемо для типовых статей/доков. -- Локальная экстракция не обходит блокировки РФ сама по себе — нужен `--local-socks` через туннель для таких сайтов. -- Fetch без туннеля из РФ на github может висеть — ограничение сети, не кода. \ No newline at end of file diff --git a/openspec/changes/local-extractor/proposal.md b/openspec/changes/local-extractor/proposal.md deleted file mode 100644 index 8f9b732..0000000 --- a/openspec/changes/local-extractor/proposal.md +++ /dev/null @@ -1,23 +0,0 @@ -## Why - -Облачная веб-экстракция (Tavily API) зависит от внешнего сервиса и туннеля: если Tavily вводит планы, меняет лимиты или туннель падает — Hermes теряет web_extract. Нужен полностью локальный экстрактор страниц, который работает без облачного API и без туннеля, с тем же интерфейсом для Hermes. - -## What Changes - -- Добавляется локальная экстракция в tavily_extract_proxy.py: режим `--local` (trafilatura) / `--local-socks` -- Один и тот же эндпоинт POST /extract отдаёт контент локально, сохраняя Tavily-совместимый JSON (results[].url/title/raw_content) -- Устанавливается библиотека trafilatura в venv Hermes -- (пока) сохраняется forward-режим как основной; local-режим — как опция переключения - -## Capabilities - -### New Capabilities -- `web-extract-local`: Локальная экстракция страниц через trafilatura с Tavily-совместимым интерфейсом - -### Modified Capabilities -- `web-extract-tavily` — добавляется реализация local-режима (не меняет требования: прокси-режим остаётся) - -## Impact - -- /opt/hermes/.hermes/scripts/tavily_extract_proxy.py — добавлен local-режим -- venv Hermes — установлен trafilatura (2.2.0) \ No newline at end of file diff --git a/openspec/changes/local-extractor/specs/web-extract-local/spec.md b/openspec/changes/local-extractor/specs/web-extract-local/spec.md deleted file mode 100644 index 403cf13..0000000 --- a/openspec/changes/local-extractor/specs/web-extract-local/spec.md +++ /dev/null @@ -1,34 +0,0 @@ -# Delta for web-extract-local - -## ADDED Requirements - -### Requirement: Local Extraction Mode -The system MUST support extracting page content fully locally (no cloud API) from the same HTTP endpoint used by the Tavily provider. - -#### Scenario: Extract page locally -- GIVEN tavily_extract_proxy.py runs with --local (or --local-socks) -- WHEN a POST /extract with {"urls":["https://..."]} is sent -- THEN the server fetches each URL, converts to markdown with trafilatura -- AND returns Tavily-shaped JSON: {"results":[{"url","title","raw_content","metadata"}], "failed_results":[], "failed_urls":[]} - -#### Scenario: Page fails to fetch -- GIVEN a URL is unreachable or returns HTTP >= 400 -- WHEN extraction is attempted -- THEN the URL lands in failed_results with an error message -- AND other URLs still process normally - -### Requirement: SOCKS Support for Local Fetches -The local extractor MUST be able to fetch through the SOCKS5 tunnel (--local-socks 127.0.0.1:1080) for sites blocked from RU IPs. - -#### Scenario: Fetch through tunnel -- GIVEN --local-socks 127.0.0.1:1080 is set -- WHEN page fetch happens -- THEN the request is routed through the SOCKS5 tunnel - -### Requirement: Backward Compatible Interface -The local mode MUST NOT break the existing Tavily forward mode: the same port/endpoint keeps working for both. - -#### Scenario: Forward still works -- GIVEN the service runs with --socks (forward mode) -- WHEN POST /extract is sent -- THEN the request is forwarded to api.tavily.com as before \ No newline at end of file