dsh-opencode-go-key-broker
Verifieddsh-opencode-go-key-broker · v0.1.1 · MIT · Web UI
DSH plugin: OpenCode Go API-key pool with quota-driven automatic switching, a Settings tab and a composer quota badge.
Install
dsh plugin add dsh-opencode-go-key-broker Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dsh-opencode-go-key-broker
DSH-плагин: автоматическое переключение ключей OpenCode Go по состоянию квоты (rolling / weekly / monthly) + отдельная вкладка в Settings для управления пулом.
Зачем
В настройках моделей у маршрута opencode-go можно указать только один ключ
(apiKeyEnv: OPENCODE_GO_API_KEY). Когда у ключа выгорает окно квоты, запросы
падают с QUOTA, и переключение приходится делать руками.
DSH резолвит ключ маршрута перед каждым запросом
(dsh-llm-pi-ai: credentials.resolve(profile.apiKeyEnv) внутри prepareCall),
поэтому достаточно менять значение одного рефа — маршруты, модели и адаптер
трогать не нужно.
Что делает
Пул хранится как конвенция (её же читает виджет dsh-opencode-go-usage):
OPENCODE_GO_API_KEY: sk-… # то, что реально читает маршрут (активный ключ)
OPENCODE_GO_KEY_ACTIVE: go2 # пометка активного (★ в виджете)
OPENCODE_GO_KEY_go1: sk-…
OPENCODE_GO_KEY_go2: sk-…
OPENCODE_GO_KEY_go3: sk-…
Две ветки переключения:
- Превентивная — раз в
refreshMsопрашиваетGET /v1/usageпо каждому ключу пула. Если активный ключ «красный» (status !== "ok"илиpercent >= thresholds[window]), берётся следующий зелёный и остаётся активным (sticky), пока не покраснеет сам. - Реактивная — слушает waterfall
agent/request-error. ПриQUOTA/INVALID_CREDENTIALменяет ключ и возвращает{ kind: 'retry' }: агент-луп переподготавливает запрос и перерезолвивает креденшел, то есть повтор идёт уже с новым ключом — в том же ходу, без ожидания следующего.
Запись идёт через credentials.set/unset (dsh-credentials-local) — тот же
кросс-процессный лок, что у страницы Models, поэтому ручные правки и UI не
затирают друг друга. Значения ключей не покидают Host: в браузер уходят только
имена, маски и проценты.
Установка
Из реестра npm:
dsh plugin --profile desktop add dsh-opencode-go-key-broker
Из GitHub (без реестра, ставится сразу после публикации репозитория):
dsh plugin --profile desktop add github:Gdenich/dsh-opencode-go-key-broker
Локально из исходников (для разработки):
dsh plugin --profile desktop add file:/path/to/dsh-opencode-go-key-broker
dsh plugin add дописывает пакет в dsh.profile.bundles сам — по полю
dsh.bundle.patch. Дальше перезапусти DSH Desktop: список плагинов и
boot manifest читаются при загрузке профиля.
Две ловушки pnpm, о которых стоит знать:
- свежий релиз не ставится сразу (политика минимального возраста релиза) —
если нужна именно новая версия, ставь точную:
[email protected]; dsh.profile.bundlesвdesktop-профиле правится только вручную или через CLI: профильdesktopуправляется приложением, но списокbundles, разошедшийся с шаблоном поставки, приложение считает пользовательским и не перезаписывает.
Настройка
Политика — в cordis.patch.yml (или в override профиля):
| Ключ | По умолчанию | Смысл |
|---|---|---|
enabled |
true |
выключить брокер целиком |
dryRun |
true |
только логировать решения, ничего не менять |
refreshMs |
60000 |
период опроса /v1/usage |
timeoutMs |
15000 |
таймаут запроса usage |
thresholds.{rolling,weekly,monthly} |
98 |
с какого процента окно «красное» |
warnPercent |
80 |
с какого процента показывать «близко» |
sticky |
true |
сидеть на ключе, пока он не покраснеет |
prefer |
first |
кого брать при переключении: first | headroom |
switchOnError |
true |
реактивная ветка (retry в том же ходу) |
keyNames |
авто | явный список имён пула вместо сканирования файла |
Переключение возможно только на «не красный» кандидат: если у всех
остальных ключей окно ≥ порога, статус rate-limited или запрос usage не
удался (сеть/401), брокер остаётся на текущем ключе и пишет в журнал
no-alternative. Уровень «близко» (warn, ≥ warnPercent) кандидатом быть
не мешает — он не красный.
Порядок ввода в эксплуатацию: оставь dryRun: true, поработай, посмотри
«Журнал решений» на вкладке Settings → OpenCode Go Keys («переключил бы на
go2, потому что monthly: 96%»), и только потом поставь dryRun: false.
Ограничитель: не больше 3 переключений в минуту (защита от циклов при исчерпанных окнах у всех ключей).
Вкладка Settings
Settings → OpenCode Go Keys: активный ключ и состояние, таблица ключей (маска, ★ активный, окна rolling/weekly/monthly с процентами и временем до сброса, уровень ok/близко/лимит/нет данных), кнопки «Сделать активным» и «Удалить», форма добавления ключа и журнал решений.
HTTP-маршруты (Host)
| Метод | Путь | Назначение |
|---|---|---|
| GET | /plugins/dsh-opencode-go-key-broker/snapshot?force=1 |
состояние пула и лог |
| POST | /plugins/dsh-opencode-go-key-broker/activate {name} |
форс активного ключа |
| POST | /plugins/dsh-opencode-go-key-broker/refresh |
опросить usage сейчас |
| POST | /plugins/dsh-opencode-go-key-broker/diag |
диагностика клиента (пишется в $DSH_HOME/opencode-go-key-broker-diag.ndjson) |
Мутации принимаются только с loopback и с того же origin.
Разработка
# хост-тесты: самодостаточны, но плагину нужны peer-пакеты DSH,
# поэтому рядом с исходниками должен быть node_modules с ними
ln -sfn "$HOME/.dsh/profiles/desktop/node_modules" node_modules # или путь к бандлу приложения
node test/host.test.mjs # 14 сценариев брокера
node test/client-render.test.mjs # 4 блока клиента (React-заглушка, без зависимостей)
Правки исходников не подхватываются автоматически: профиль ставит пакет как
file:-зависимость, pnpm кладёт копию (жёсткими ссылками) в
node_modules/dsh-opencode-go-key-broker. После изменения файлов нужно либо
скопировать их в эту папку, либо повторить dsh plugin --profile desktop add file:<путь>.
Хост-код и cordis.patch.yml читаются при старте — изменения политики и хоста
требуют перезапуска приложения; клиентский бандл отдаётся с диска, ему достаточно
жёсткого рефреша страницы.
Ограничения
- Ключи в пуле должны быть валидны: невалидный (401) считается «красным».
network/timeoutпри опросе не считаются «красными» — иначе один сетевой сбой уводил бы с рабочего ключа.- Смена ключа меняет аккаунт-контекст: prompt-cache у OpenCode Go привязан к ключу, поэтому первый запрос на новом ключе пойдёт без кэша.