joslynSmall/dsh-plugin-reasoning-effort-sync ↗★ 0

dsh-plugin-reasoning-effort-sync

Keep DeepSeek Harness model reasoning-effort levels in sync with what an OpenAI-compatible gateway advertises, so a new route or model needs no hand-written reasoningEfforts. 适合使用兼容 OpenAI 网关且不想手动维护推理配置的系统管理员。

パッケージ
dsh-plugin-reasoning-effort-sync
互換性
未検証
バージョン
0.1.0
ライセンス
MIT
最終更新
2026/10/04

インストール

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:joslynSmall/dsh-plugin-reasoning-effort-sync

ドキュメント

README 全文を読む ↗

Configuration

The bundle's patch registers one row with these defaults:

- id: reasoning-effort-sync
  name: dsh-plugin-reasoning-effort-sync
  config:
    enabled: true
    syncOnLoad: true
    intervalMinutes: 0        # 0 disables the periodic sync
    requestTimeoutMs: 10000
    dryRun: false
    routes: {}                # empty means every route the pi-ai row declares
    modelsDev:                # fallback source, read only for models the endpoint does not describe
      enabled: true
      url: https://models.dev/api.json
      ttlHours: 12
      timeoutMs: 30000
      minShare: 0.5           # agreement the dominant declaration needs before it is trusted
FieldMeaning
enabledMaster switch. Off means no request and no write.
routesEmpty processes every route. A populated dict is an allowlist: name a route to include it, and enabled: false under that name to exclude it.
syncOnLoadSync once when the profile loads.
intervalMinutesAlso sync on this interval. 0 (the default) disables periodic sync; load and configuration-change sync remain active.
requestTimeoutMsDeadline for one listing request.
dryRunCompute and log the result without writing. Start here.
modelsDev.enabledConsult models.dev for models whose endpoint published no levels.
modelsDev.urlDataset address. The default is models.dev's full dataset, about 5 MB.
modelsDev.ttlHoursHow long one fetched dataset is reused in memory.
modelsDev.timeoutMsDeadline for that one fetch.
modelsDev.minShareAgreement the dominant declaration needs. 1 demands unanimity (kimi-k3 would then be skipped), 0 accepts any plurality, 0.5 accepts a majority.

The load-time sync is not awaited, so an unreachable gateway never delays a profile. The plugin observes app-boot/config-reload, emitted after DSH finishes reconciling a profile save, and synchronizes when the addressable pi-ai configuration changes. A channel or model added in the Models page is picked up without restarting DSH or refreshing the page. Unrelated or unchanged profile saves do not fetch model metadata. Changes arriving during a sync are coalesced into a subsequent serial pass, so a slow gateway cannot discard a new model. Every pass is diff-first: a sync that resolves nothing new writes nothing. When HMR is present, sync work starts outside the profile transaction's async context, so its later config-editor write can queue normally rather than being rejected as nested.

Where the levels come from

  1. The route's endpoint, when it names them. It describes the very gateway being configured, so its answer is final.
  2. models.dev, for the models the endpoint did not describe. The same model name is declared differently by dozens of providers there — deepseek-v4.1-flash had 15 distinct level sets across 75 declarations when this was written — so one rule has to pick. The offered levels are the dominant declaration: the exact set the largest number of declarations agree on, taken only when at least modelsDev.minShare of them agree and at least two providers say it. A weaker or tied plurality falls back to the intersection, so lowering minShare can only add levels some declaration already named.

Two details make that rule work in practice:

  • "Off" levels are dropped before anything is compared. none, off, disabled and false say "do not reason", which the picker's Default row already expresses by sending no parameter. Counting them would duplicate that row and let a reseller recording only "off" veto every real level. Dropping them also merges declarations that differ only in whether they mention it — which is why deepseek-v4.1-flash resolves to low, high, max, the very set the unrelated WorkBuddy gateway declares authoritatively for that name.
  • A weak or tied plurality is refused. Under-offering is recoverable; a level the upstream rejects is a hard failure at request time. A model neither rule can place is left untouched, so some names still need a hand-written block even with the fallback on.