Bundle
dsh-opencode-go-key-broker
DSH plugin: OpenCode Go API-key pool with quota-driven automatic switching, a Settings tab and a composer quota badge.
- Source
- Gdenich
- License
- MIT
- Updated
- Updated 2 hours ago
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`):
```yaml
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-…
```
Две ветки переключения:
1. **Превентивная** — раз в `refreshMs` опрашивает `GET /v1/usage` по каждому
ключу пула. Если активный ключ «красный» (`status !== "ok"` или
`percent >= thresholds[window]`), берётся следующий зелёный и остаётся
активным (sticky), пока не покраснеет сам.
2. **Реактивная** — слушает waterfall `agent/request-error`. При
`QUOTA` / `INVALID_CREDENTIAL` меняет ключ и возвращает `{ kind: 'retry' }`:
агент-луп переподготавливает запрос и **перерезолвивает креденшел**, то есть
повтор идёт уже с новым ключом — в том же ходу, без ожидания следующего.
Запись идёт через `credentials.set/unset` (dsh-credentials-local) — тот же
кросс-процессный лок, что у страницы Models, поэтому ручные правки и UI не
затирают друг друга. Значения ключей не покидают Host: в браузер уходят только
имена, маски и проценты.
## Установка
Из реестра npm:
```sh
dsh plugin --profile desktop add dsh-opencode-go-key-broker
```
Из GitHub (без реестра, ставится сразу после публикации репозитория):
```sh
dsh plugin --profile desktop add github:Gdenich/dsh-opencode-go-key-broker
```
Локально из исходников (для разработки):
```sh
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, о которых стоит знать:
- свежий релиз не ставится сразу (политика минимального возраста релиза) —
если нужна именно новая версия, ставь точную: `dsh-opencode-go-key-broker@0.1.1`;
- `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.
## Разработка
```sh
# хост-тесты: самодостаточны, но плагину нужны 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 привязан к
ключу, поэтому первый запрос на новом ключе пойдёт без кэша.
Install
dsh plugin --profile web add github:Gdenich/dsh-opencode-go-key-broker
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-opencode-go-key-broker from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.