DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

svoemesto /

svoemesto/dsh-web-search-searxng

Verified

Поиск в интернете через SearXNG для DeepSeek Harness: плагин сам поднимает контейнер и даёт агенту web_search без ключей вендора. · SearXNG-backed web search for the DeepSeek Harness, with its own container and no vendor key.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@14c5d050

dsh-web-search-searxng

ci Русский | English

Бандл для DeepSeek Harness, который даёт агенту работающий web_search без ключа вендора. Он подключает провайдера поиска на базе SearXNG к шву веб-доступа харнесса (ctx.web) и по умолчанию поднимает собственный контейнер SearXNG — то есть установка бандла и есть вся настройка.

Принцип работы и отличие от «голого» SearXNG

«Голый» подход — это адаптер на тридцать строк: взять {base}/search?format=json и вернуть results[]. Он исходит из того, что SearXNG у вас уже поднят, JSON в нём включён, порт свободен, образ свежий, а контейнер жив. И он не отличает «ничего не нашлось» от «движки внутри отказали»: в обоих случаях приходит HTTP 200 с пустым списком.

Наш плагин встраивает в пакет сам инстанс и надёжность:

  1. Установка = рабочий инстанс. Плагин тянет searxng/searxng, берёт первый свободный порт, генерирует settings.yml (JSON включён, лимитер выключен, секрет создаётся один раз), ждёт /healthz и останавливает контейнер при выгрузке. Отдельного шага «сначала подними SearXNG» нет; если инстанс уже есть — один параметр baseURL, и контейнер не создаётся.
  2. Отказ движков — это ошибка, а не пустой ответ. SearXNG отдаёт unresponsive_engines; плагин делает второй проход (по fallbackEngines или без сужающих фильтров) и только потом сообщает, какие движки отказали.
  3. Временные сбои переживаются. Сеть, таймаут попытки, 429/5xx повторяются; отмена вызывающим — никогда; худшая задержка (retries + 1) × timeoutMs.
  4. Повторный запрос ничего не стоит. TTL-кэш на 60 секунд: агент часто повторяет один и тот же поиск, второй раз ответ приходит из памяти.
  5. Результат пригоден для цитирования. Только http(s), сниппет ≤ 800 символов, publishedAt, ответ движка (answers) как content — без придуманного текста.

Движки — это источники, которые SearXNG опрашивает параллельно. В сгенерированных настройках стоит use_default_settings: true, поэтому включён набор по умолчанию текущей версии: в категории general это brave, duckduckgo, google cse, wikipedia и wikidata (плюс вспомогательные вроде currency, dictzone и lingva); google, bing, qwant и yandex в конфиге присутствуют, но выключены — им нужны ключи или они нестабильны, и включаются они в settings.yml. Полный список включённых движков своего инстанса:

curl -s http://127.0.0.1:8888/config | jq -r '.engines[] | select(.enabled) | .name'

Чего мы не делаем: не зовём внешний API, не требуем ключей, не платим за поиск и не сочиняем сводок — content приходит от движка. Провайдер регистрируется как searxng, инструмент web_search остаётся штатным; пакет — обычный ESM без зависимостей и сборки.

Требования

Требование Зачем
Демон Docker, доступный пользователю, который запускает dsh (docker version) плагин сам запускает и останавливает контейнер
~400 МБ диска и сеть при первом запуске однократная загрузка образа
Node 22+ (харнесс и так его требует) fetch, AbortSignal.timeout
DSH с швом ctx.web (текущие 0.2.x) провайдер регистрируется в этот шов; на старых сборках ряд просто ждёт сервис и ничего не делает
pnpm и git, доступные команде dsh dsh plugin ставит пакет через pnpm, спецификация github: требует git

Нет Docker? Укажите baseURL на существующий инстанс SearXNG — тогда ничего не запускается (см. Использовать существующий инстанс).

Установка

Пакет объявляет dsh.bundle, поэтому установка одновременно и активирует его:

# из GitHub (поддерживаемый способ)
dsh plugin --profile web add github:svoemesto/dsh-web-search-searxng

# из локальной копии (для разработки)
dsh plugin --profile web add /path/to/dsh-web-search-searxng

Внутри уже запущенного харнесса то же самое делает plugin_manager → install_bundle с каталогом пакета в качестве target. После этого спросите агента о чём-нибудь актуальном: web_search отвечает через ваш инстанс.

Первый запуск медленный — один раз. Плагин загружает образ, создаёт контейнер и ждёт /healthz (до startupTimeoutMs, по умолчанию 90 с). Пока инстанс не готов, поиск завершается ошибкой «SearXNG instance is not ready: …»; загрузка при этом продолжается в фоне, и следующий поиск уже проходит.

Что создаётся

Что Где
Контейнер dsh-searxng (имя настраивается), --restart unless-stopped, публикация только на 127.0.0.1:<свободный порт>:8080
Настройки $DSH_HOME/searxng/settings.yml (по умолчанию ~/.dsh/searxng/), пишутся один раз и никогда не перезаписываются
Секрет генерируется в эти настройки; сохраняется между перезапусками и обновлениями
Порт первый свободный порт начиная с port (8888), просматривается до 50 портов — машина, где SearXNG уже занят, продолжает работать

Контейнер запускается при активации плагина и останавливается при его выгрузке (завершение харнесса, HMR-перезагрузка, удаление плагина). Сам контейнер сохраняется, поэтому следующий старт занимает секунды; данные и секрет остаются в $DSH_HOME/searxng.

Что меняется в вашем профиле

Две строки патча, обе видны в dsh --profile <имя> --dump-config:

  • ряд web-search-searxng — сам провайдер (по умолчанию port: 8888);
  • переопределение ряда web: searchProvider: searxng и fetchProvider: http. Патч заменяет config целиком, поэтому fetchProvider указан явно — иначе после установки у web_fetch не осталось бы провайдера. Если в профиле уже сохранён оверрайд из Settings → Plugins → Web search, он сильнее патча: поиск останется за DeepSeek, хотя плагин установлен.

Контейнер с именем dsh-searxng, созданный не этим плагином, не переиспользуется и не останавливается: плагин проверяет метку dsh.plugin=dsh-web-search-searxng, а в чужом случае отказывается работать с понятным сообщением (задайте другой containerName).

Настройка

Все поля необязательны, у всех есть рабочие значения по умолчанию.

Поле По умолчанию Смысл
baseURL (не задано) Использовать этот существующий инстанс и ничего не запускать. Не задано → свой контейнер.
port 8888 Первый порт-кандидат для контейнера; занятые пропускаются.
image searxng/searxng:latest Любой совместимый образ SearXNG (зеркало, закреплённый тег).
containerName dsh-searxng Контейнер, которым владеет плагин.
dataDir $DSH_HOME/searxng Каталог на хосте с settings.yml.
instanceName DSH web search Подпись в собственном интерфейсе инстанса.
startupTimeoutMs 90000 Бюджет ожидания готовности (1000–600000).
timeoutMs 20000 Бюджет одного поиска.
language (не задано) Передаётся как language; не задано = значение инстанса.
categories (не задано) general, news, …
safesearch (не задано) 0, 1, 2.
timeRange (не задано) day, week, month, year.
numResults (не задано) Обрезка только когда вызывающий не передал maxResults; реальную границу держит шов.
apiKey (не задано) Передаётся как preference[api_key] для инстансов за ключом.
retries 1 Дополнительные попытки после первой, если ошибка повторяемая (0–5).
retryDelayMs 300 Пауза между попытками.
fallbackEngines [] Движки, на которые сужается повторная попытка, например ["brave", "duckduckgo", "google cse"]; пусто — повтор идёт без language, categories, time_range.
cacheTtlMs 60000 Время жизни закэшированного результата; 0 отключает кэш.
cacheMaxEntries 200 Сколько поисков держать в кэше, прежде чем вытеснить самый старый.

Неверные значения останавливают активацию с сообщением, называющим поле — опечатка никогда не превращается в молча неработающий поиск.

Пример строки (в патче бандла или профиля):

- insert:
    - id: web-search-searxng
      name: dsh-web-search-searxng
      config:
        port: 8888
        language: ru

Использовать существующий инстанс

config:
  baseURL: http://127.0.0.1:8888

Тогда контейнер не создаётся и Docker не нужен. Полезно, когда на машине уже работает SearXNG для других задач или инстанс живёт на другом хосте.

Как отображаются результаты

  • results[] → {url, title?, snippet?, publishedAt?}; записи без абсолютного http(s)-URL отбрасываются, пустые сниппеты опускаются (не выдумываются), сниппеты ограничены 800 символами;
  • первый непустой ответ движка (answers[]) становится content — это реальный вывод движка, а не текст, сочинённый здесь;
  • нет результатов и непустой список unresponsive_engines → WEB_PROVIDER_ERROR с именами движков, чтобы «полусломанный» инстанс был виден, а не выглядел как честный пустой ответ.

Ошибки несут коды шва: WEB_PROVIDER_ERROR (HTTP-ошибка, неразбираемое тело, таймаут, сеть, неготовность) и WEB_ABORTED (отмена вызывающим).

Повторы и кэш

Попытка повторяется, когда сбой временный: сетевая ошибка, таймаут попытки, HTTP 429/5xx или — случай, которому научил поиск текстов в Караоке — HTTP 200 с нулём результатов и непустым списком unresponsive_engines. Повтор — это не тот же самый запрос:

  • если задан fallbackEngines, поиск сужается до этих движков (engines=bing,brave,…), а фильтры сохраняются;
  • иначе запрос повторяется без language, categories, time_range — именно эти сужения способны обнулить в остальном отвечаемый запрос.

Худшая задержка — (retries + 1) × timeoutMs; с умолчаниями это 40 с, что укладывается в 60-секундный бюджет инструмента. Отмена вызывающим не повторяется.

Одинаковые поиски кэшируются в памяти процесса: ключ включает запрос, границу результатов, language, categories, safesearch, timeRange, список резервных движков и адрес инстанса. Запись живёт cacheTtlMs (по умолчанию 60 с), кэш держит cacheMaxEntries поисков. Он локальный для процесса — без файлов и без общего состояния между разными хостами Harness — и хранит только успехи, поэтому сбой не прячет более поздний удачный поиск.

Диагностика

Симптом Причина и что делать
docker is not available on this machine Запустите Docker или задайте baseURL.
SearXNG instance is not ready: … did not become healthy Смотрите docker logs dsh-searxng; возможно, ещё идёт первая загрузка образа.
no free port in 8888..8937 Уменьшите port или освободите порт; каждый контейнер занимает один.
Поиск даёт странные или скудные результаты SearXNG агрегирует сторонние движки; docker logs показывает, какие отказали (unresponsive_engines).
Два харнесса на одной машине Они делят имя контейнера и порт; второй переиспользует запущенный. Для изоляции задайте разные containerName + port.
container "dsh-searxng" exists but was not created by this plugin На машине уже есть контейнер с этим именем, но без нашей метки. Задайте другой containerName в конфиге или удалите тот контейнер.
Удаление Снятие бандла останавливает контейнер; чтобы вернуть диск — docker rm -f dsh-searxng и удалить $DSH_HOME/searxng.

Безопасность

  • Контейнер публикуется только на 127.0.0.1; из локальной сети он недоступен.
  • JSON-вывод включён, а ограничитель частоты выключен — это безопасно только благодаря привязке к loopback. Если открываете инстанс наружу, включите ограничитель в settings.yml и поставьте его за прокси.
  • Секретный ключ генерируется локально и хранится только в settings.yml.

Разработка

Зависимостей и сборки нет: исходники и есть артефакт.

index.js              точка входа плагина (apply, жизненный цикл, выбор режима)
src/config.js         валидация и значения по умолчанию
src/container.js      жизненный цикл docker: inspect / start / pull+create / health / stop
src/settings.js       генерация settings.yml (+ одноразовый секрет)
src/provider.js       клиент JSON-API SearXNG и маппинг результатов
test/unit.test.mjs    юнит-набор (фейковый docker, без сети)
test/docker.smoke.mjs живой контейнер: ensure → search → stop → rm

Текст карточки плагина в DSH — по-русски: харнесс поставляет только локали zh/en, поэтому русский текст лежит в locale/en.json (и в locale/ru.json), чтобы отображаться в интерфейсе; английская документация — в README.en.md.

node --test test/unit.test.mjs   # конфиг, настройки, жизненный цикл контейнера, маппинг, ошибки
node test/docker.smoke.mjs       # настоящий контейнер; нужны Docker и сеть, поднимает dsh-searxng-smoke

CI гоняет юнит-набор на Node 22 и 24 на каждый push (.github/workflows/ci.yml); проверка с контейнером — ручная (.github/workflows/docker-smoke.yml).

Релиз

Репозиторий и есть канал распространения: шага «публикация в реестр» нет.

  1. Поднимите version в package.json и добавьте запись в CHANGELOG.md.
  2. Закоммитьте, поставьте тег v<version> и запушьте тег.
  3. Создайте GitHub-релиз на этот тег (gh release create v<version> или через веб-интерфейс).

Ставят — и закрепляют версию — прямо из GitHub:

dsh plugin --profile web add github:svoemesto/dsh-web-search-searxng
dsh plugin --profile web add github:svoemesto/dsh-web-search-searxng#v2.0.1

Чтобы плагин находили в списках сообщества, публикуйте репозиторий с темой dsh-plugin на GitHub.

Лицензия

MIT — см. LICENSE.

—/ 5

No ratings yet

Verified DSH bundle

Commit 14c5d050919d

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout