koliy82/dsh-rustvy ↗★ 0

dsh-rustvy

Rustvy for DeepSeek Harness: vendor marks in the model picker, and a model list kept in step with what the provider actually serves — the host half mirrors the catalog and logos to loopback and regenerates the pi-ai route's models from the route's own endpoint, showing the drift before anything is written. 适合需要直观识别模型厂商并保持模型列表与服务端同步的用户。

Package
dsh-rustvy
Compatibility
Unverified
Version
1.0.0
License
MIT
Last updated
Oct 19, 2026

Install

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:koliy82/dsh-rustvy

Регистрация на Rustvy по реферальной ссылке автора: При регистрации по этой ссылке вы получаете скидку 10% и бонусные токены. Подробные условия акции:

Rustvy (dsh-rustvy)

Русский | English

npm загрузки лицензия dsh-plugin

Значки производителей в списке моделей DeepSeek Harness и список моделей, который остаётся настолько же актуальным, насколько актуален сам провайдер. Один плагин, одно зеркало, без перезапусков.

Что он делает

У плагина две задачи, и обе работают от одного зеркала публичного каталога провайдера.

Значки. Один монохромный значок производителя перед каждой строкой модели в списке выбора — нарисованный так же, как его рисует собственная панель провайдера: CSS-маска, заливаемая currentColor, поэтому один файл на производителя обслуживает обе темы оформления и все состояния строки — наведение, выбор, отключение — без цветовых вариантов.

ГдеЧто появляется
Меню моделей в композеремонохромный значок 16 px перед каждой строкой модели
Кнопка модели в композерезначок выбранной модели перед её названием (14 px)
Всплывающее окно команды /modelтот же значок на каждой строке
Скины, перерисовывающие список (dsh-claude-style)тот же значок; собственная плашка скина в этой строке прячется, чтобы две плашки не встретились

Список моделей. Профиль подключается к стороннему провайдеру через вручную объявленный маршрут @deepseek-ai/dsh-llm-pi-ai, и именно список models этого маршрута определяет, что вообще можно выбрать в интерфейсе: harness предлагает модель только тогда, когда её отдаёт маршрут. Список, написанный вручную, устаревает в тот день, когда провайдер выпускает новую модель — новая невидима, а снятая с публикации остаётся выбираемой и падает уже на запросе. Плагин читает, что отдаёт собственный эндпоинт маршрута, превращает это в точный формат записей адаптера, показывает расхождение с установленным списком и по команде записывает его обратно через ctx.configEditor.

Зачем это нужно

Потому что обе поломки маршрута, который поддерживают вручную, — тихие. Модель, которую провайдер добавил, не появляется, и никто не говорит почему: ошибки нет, есть только отсутствие. Модель, которую провайдер снял, по-прежнему видна, и её выбор даёт сетевую ошибку, которая выглядит как проблема со связью, а не как устаревшая строка в YAML-файле.

И то и другое лечится чтением данных у провайдера вместо их переписывания. Список, который записывает этот плагин, несёт настоящие размер окна контекста, лимит вывода, входные модальности и уровни рассуждения, поэтому модель, получившая поддержку изображений или новый уровень мышления, описана верно в тот же день, а не наследует запасное значение, которое кто-то когда-то угадал.

А поскольку значки берутся из того же зеркала, совершенно новая модель приходит уже с кешированным значком своего производителя: зеркало перечитывает каталог в тот момент, когда эндпоинт называет модель, которой оно раньше не видело, — то есть ровно тогда, когда выходит релиз.

Ничего из этого не привязано к одному провайдеру. Сайт-источник, маршрут и строка профиля — настройки; https://rustvy.xyz и rustvy являются значениями по умолчанию.

Установка

dsh plugin --profile web add dsh-rustvy

Либо прямо с GitHub, если нужна самая свежая ревизия, а не опубликованная версия:

dsh plugin --profile web add github:koliy82/dsh-rustvy

Голый koliy82/dsh-rustvy без схемы не принимается: разбор источника установки знает имя в реестре, git-спецификацию, tarball и абсолютный локальный путь, а git-спецификации нужна схема либо сокращение github:.

Подтверждение сборки не запрашивается ни в том ни в другом случае: у пакета нет ни install-скрипта, ни зависимостей, поэтому pnpm нечего собирать.

Из локальной копии этого репозитория:

pwsh -File .\install.ps1

install.ps1 копирует пакет в \node_modules\dsh-rustvy как настоящий каталог и дописывает имя в dsh.profile.bundles манифеста профиля. Работающий harness подхватывает строку по изменению манифеста.

После этого один раз перезапустите harness или обновите страницу: значки и страница настроек появляются на лету, а строка загрузчика читается на композиции.

Маршрут, в который пишется список моделей

Значки работают без всего остального. Половине со списком моделей нужен маршрут @deepseek-ai/dsh-llm-pi-ai, в который можно писать. Добавьте в cordis.patch.yml профиля — или отредактируйте в Настройки → Плагины → Конфигурация плагинов:

- id: llm-pi-ai
  name: "@deepseek-ai/dsh-llm-pi-ai"
  config:
    providers:
      rustvy:
        displayName: rustvy
        apiKeyEnv: RUSTVY_API_KEY
        api: openai-completions
        baseURL: https://rustvy.xyz/v1
        models:
          - id: placeholder
            name: placeholder

Список models обязан только разбираться: этот плагин его заменяет. Все остальные поля при перегенерации переносятся без изменений, потому что переключатель совместимости протокола или ссылка на учётные данные — это знание о вашем развёртывании, которого нет ни в одном каталоге.

apiKeyEnv задаёт, откуда маршрут берёт ключ; он разрешается на каждый запрос через механизм учётных данных harness — сначала унаследованное окружение процесса, затем $DSH_HOME/.credentials.yaml, затем .env в каталоге запуска или в $DSH_HOME. Сам ключ в конфигурационные файлы не попадает. Плагин при чтении списка моделей подставляет ключ только тогда, когда окружение процесса уже содержит переменную с таким именем; эндпоинт, под который он написан, отвечает и без ключа.

Чтобы сделать модель основной:

- id: agent-default-model
  name: "@deepseek-ai/dsh-agent-default-model"
  config:
    provider: rustvy
    model: claude-opus-5-5
    reasoningEffort: high

Как пользоваться

Откройте Настройки → Rustvy. Страница показывает, что держит зеркало, что отдаёт провайдер и каково точное расхождение между ними. Кнопка «Обновить каталог и иконки» освежает обе половины, «Записать список моделей» записывает сгенерированный список. Без одного из этих нажатий не пишется ничего, если вы сами не попросили об этом в настройках.

Настройки

Настройки → Rustvy

Значки:

ПараметрПо умолчаниюСмысл
Показывать иконки моделейвклобщий выключатель значков; в выключенном виде убирает все значки и не трогает список моделей
Иконка в кнопке выбранной моделивклзначок и в кнопке модели композера, а не только в строках меню
Прятать логотипы других скиноввклпрятать собственную плашку скина в строке, где значок нарисован этим плагином
Размер значка, px16от 10 до 32

Список моделей:

ПараметрПо умолчаниюСмысл
Держать список моделей маршрута актуальнымвклобщий выключатель; в выключенном виде YAML маршрута не трогается
Записывать списокпри нажатии «Обновить»только отдельной кнопкой — самостоятельно не пишет никогда · при нажатии «Обновить» — пишет по кнопке обновления · сам, при каждом обновлении — пишет и при фоновом суточном обновлении
Название моделикак на сайте провайдераотображаемое имя провайдера либо сырой идентификатор
Предлагать уровень «без рассуждений»вклдобавлять уровень off рассуждающей модели, которая его не объявила
Оставлять модели, которые провайдер больше не отдаётвыклсохранять установленную модель, которую эндпоинт больше не отдаёт, — на случай временно ошибочного списка, а не действительно снятой модели
Маршрут провайдераrustvyкакой ключ внутри providers записывать
Строка профиляllm-pi-aiкакая строка загрузчика его содержит
Сайт провайдераhttps://rustvy.xyzоткуда читать каталог и логотипы

Режим записи по умолчанию намеренно средний: нажатие кнопки — это решение человека, а фоновое истечение срока — нет, и переписывать конфигурацию загрузчика работающего профиля, когда никто не просил, — это то, на что стоит спросить разрешение.

Каждый адрес и файл, с которым работает плагин, виден на странице: сайт, страница каталога и эндпоинт списка моделей — ссылками, открывающимися в новой вкладке, а пути к зеркалу, настройкам, копии для отката и патчу профиля — текстом с кнопкой копирования. Кнопка «Показать блок для ручной правки» выдаёт ровно тот YAML, который получился бы при автоматической записи, так что желающий вставить его в cordis.patch.yml сам не переписывает краткий пересказ.

У одного поля нет элемента управления, потому что оно принадлежит YAML профиля, а не форме: modelZones (по умолчанию ["standard"]) — зоны каталога, которые допускаются, когда эндпоинт недоступен и состав списка определяет зеркало.

Настройки хранятся в \.dsh-rustvy\config.json. Две переменные окружения перекрывают их — для развёртывания, которое направляет зеркало в другое место или хочет смонтировать плагин неработающим: DSH_RUSTVY_ORIGIN и DSH_RUSTVY_DISABLED=1.

Откуда берутся картинки

В сам пакет ничего не вшито. Хост-половина зеркалит два публичных объекта с сайта провайдера в профиль, а браузерная половина читает их с локального адреса:

  1. каталог моделей — сайт рисует свою таблицу моделей из JSON-острова в собственной странице (``), поэтому неаутентифицированный читатель получает ровно те данные, которые видит панель. Зеркалится в \.dsh-rustvy\catalog.json.
  2. файлы логотипов (/logos/.svg) — копируются в \.dsh-rustvy\logos\ при первом обращении.

Оба читаются по собственному исходящему маршруту процесса (lib/net.js): сначала живой глобальный диспетчер, чтобы прокси, установленный dsh-proxy-gui или любым другим маршрутом процесса, соблюдался, затем соединитель, построенный здесь из HTTPS_PROXY / ALL_PROXY / HTTP_PROXY, — на случай, когда диспетчер не установлен. NO_PROXY учитывается в обоих случаях. Сама страница наружу не выходит: браузер спрашивает значок у 127.0.0.1, и именно поэтому всё работает на машине, чей браузер до источника не достаёт вовсе.

Каталог обновляется раз в 24 часа и по требованию; холодное зеркало ожидается до 6 секунд, а устаревшее обновляется в фоне, пока строки продолжают показывать имеющиеся значки. Когда источник недоступен, кеш на диске по-прежнему отдаёт всё, что в нём есть.

Откуда берётся список моделей

Два источника в таком порядке, потому что отвечают они на разные вопросы:

  1. собственный эндпоинт маршрута (GET {baseURL}/models) — авторитетный список состава: ровно те модели, которые можно назвать в запросе, каждая со своими context_k, max_output_tokens, modalities и reasoning_levels. Это тот же эндпоинт, который опрашивает собственное обнаружение адаптера.
  2. зеркало острова каталога — названия и запасной вариант. Это единственный источник, несущий отображаемое имя, производителя и имя файла логотипа, поэтому он соединяется с отдаваемым списком по идентификатору. Когда эндпоинт не отвечает, состав определяет сам остров по своим полям enabled и zone, так что маршрут остаётся актуальным и во время сбоя, а не застывает на последнем удачном чтении. На здоровом источнике оба списка совпадают точно.

Модель, которую эндпоинт отдаёт, а зеркало ни разу не видело, — признак того, что остров отстал от боевого API, а это происходит ровно в момент релиза, поэтому тогда остров перечитывается; ожидание ограничено тем же коротким сроком, что и для холодного зеркала.

Что именно записывается

Каждая сгенерированная запись несёт только те поля, которые объявлены в схеме конфигурации адаптера, потому что список models профиля маршрута заменяет каталог маршрута, а неизвестное поле в лучшем случае будет отброшено:

ПолеОткуда берётся
idидентификатор отдаваемой модели — то, что нужно назвать в запросе
nameотображаемое имя из острова либо идентификатор, если имени нет
contextWindowcontext_k × 1000
maxTokensmax_output_tokens
inputmodalities, отфильтрованные до text/image
reasoningEffortsreasoning_levels, отображённые на уровни адаптера, либо false для нерассуждающей модели
compatне генерируется никогда — существующее всегда переносится

Поле, о котором никто не высказался, пропускается, а не заполняется значением по умолчанию, чтобы запасное значение самого адаптера оставалось в силе и написанное вручную не закреплялось молча. compat — единственное, что переносится без изменений: переключатель совместимости протокола это знание о шлюзе, которого нет ни в одном каталоге.

Уровни рассуждения отображаются на словарь адаптера (off, minimal, low, medium, high, xhigh, max); неизвестный ему уровень отбрасывается и сообщается примечанием, а не отказом всей записи. Необъявленные уровни адаптер не поддерживает, а объявленный off без боевого значения означает «предлагать, ничего не отправляя» — поэтому этот переключатель включён по умолчанию.

Что запись отклоняет

Пустой список не записывается никогда: единственный способ его получить — неудачное чтение, а маршрут без моделей не обслуживает ничего. Актуальный список тоже не записывается, потому что configEditor.edit() согласует весь загрузчик, и тратить одно согласование на отсутствие изменений означало бы перезагрузить работающий профиль впустую. Каждая запись сохраняет предыдущий документ в \.dsh-rustvy\models-backup.json, а кнопка «Откатить к предыдущему» возвращает его обратно; состояние, которое откат вытесняет, само становится следующей копией, поэтому откат тоже можно откатить.

Как строка сопоставляется со значком

Строки сопоставляются по видимому названию в таком порядке:

  1. идентификатор модели из зеркального каталога (claude-opus-5-5, abyss/glm-5.3, …);
  2. её отображаемое имя (OPUS 5.5);
  3. идентификатор, с которого название начинается, — скин может оставить в том же элементе собственную строку описания, поэтому название часто является префиксом, а не всей строкой; побеждает самый длинный подходящий идентификатор, чтобы claude-opus-5-5 никогда не достался claude-opus-5;
  4. форма идентификатора — для модели, которой зеркало ни разу не видело: claude-* → Anthropic, gpt-*/o1…o9 → OpenAI, glm-* → Zhipu, kimi-*/k3 → Moonshot, qwen-* → Alibaba Qwen, deepseek-* → DeepSeek, ahmia-* → Ahmia, mimo-* → Xiaomi, fable-* → Anthropic, gemini-* → Google, grok-* → xAI.

Модель, не подошедшая ни под что, не получает значка вовсе: выдуманная иконка была бы неправильным ответом, а не отсутствующим. Модель, которая подошла, но чей логотип зеркало получить не смогло, получает вместо пустого квадрата плашку с монограммой — первыми буквами производителя: маска с неработающим URL закрасилась бы сплошным квадратом.

Строки уровней усилия, заголовки производителей, корневые ячейки меню, поле поиска и строки о сбое каталога не подходят ни под одно правило и остаются без значка.

Маршруты

Одна регистрация префикса на собственном веб-сервере harness. Маршруты плагинов не видны фильтру запросов хоста, поэтому каждый из них проверяет собеседника сам: только локальный адрес, только локальный Host, только same-origin Sec-Fetch-Site и только совпадающий Origin.

МаршрутМетодОтвет
/dsh-rustvy/catalog.jsonGETзеркальный каталог плюс настройки, с которыми браузерная половина рисует
/dsh-rustvy/logo/.svgGET, HEADодин кешированный логотип, при первом запросе забираемый с источника; 404, когда такого значка у