@goodandready/dsh-model-sync 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -149
- package/README.ru.md +0 -125
- package/README.zh.md +0 -10
- package/lib/models.js +84 -2
- package/lib/reconcile.js +14 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -75,6 +75,7 @@ graph LR
|
|
|
75
75
|
## ✨ Key Features
|
|
76
76
|
|
|
77
77
|
* 🔄 **Automated Catalog Discovery**: Syncs model lists, aliases, context windows, and capability flags (`vision`, `tools`, `reasoning`, `embeddings`) across 25+ providers.
|
|
78
|
+
* 🛡️ **Minijinja Chat Template & Role Compatibility**: Automatically sets `compat.supportsDeveloperRole: false` for Groq open-source models (Qwen, Llama, Mistral, Gemma, DeepSeek) and DeepSeek API, preventing 400 `Unexpected message role` errors with reasoning models while preserving user overrides. Syncs model lists, aliases, context windows, and capability flags (`vision`, `tools`, `reasoning`, `embeddings`) across 25+ providers.
|
|
78
79
|
* 🌐 **25+ Built-in Provider Adapters**: Pre-configured discovery for OpenAI, Anthropic, Google, DeepSeek, xAI, OpenRouter, Groq, Mistral, Cerebras, Fireworks, HuggingFace, Moonshot, NVIDIA, Qwen, Together, Xiaomi MiMo, SiliconFlow, and local Ollama.
|
|
79
80
|
* 🔌 **Generic / Custom Adapter Support**: Connect arbitrary OpenAI-compatible `/v1/models` endpoints with configurable auth (`bearer`, `x-api-key`, `query-key`, `none`).
|
|
80
81
|
* 📊 **Balance & Quota Monitoring**: Queries upstream billing endpoints (where supported) to report account credit balances and prevent unexpected exhaustion.
|
|
@@ -96,7 +97,7 @@ graph LR
|
|
|
96
97
|
| `deepseek` | Bearer Token | `tools`, `reasoning` |
|
|
97
98
|
| `xai` | Bearer Token | `vision`, `tools`, `reasoning` |
|
|
98
99
|
| `openrouter` | Bearer Token | Multi-vendor model catalog with pricing & context limits |
|
|
99
|
-
| `groq` | Bearer Token |
|
|
100
|
+
| `groq` | Bearer Token | `tools`, `reasoning`, `vision`, `supportsDeveloperRole: false` |
|
|
100
101
|
| `mistral` | Bearer Token | `tools`, `reasoning`, `vision` |
|
|
101
102
|
| `fireworks` | Bearer Token | Open-weights inference endpoints |
|
|
102
103
|
| `huggingface` | Bearer Token | Serverless Inference API catalog |
|
|
@@ -116,151 +117,3 @@ dsh plugin --profile web add @goodandready/dsh-model-sync
|
|
|
116
117
|
> Restart DSH Web UI after installation (`systemctl --user restart dsh-web`) to activate background catalog synchronization.
|
|
117
118
|
|
|
118
119
|
---
|
|
119
|
-
|
|
120
|
-
## 🚀 Enhancements in v0.4.0
|
|
121
|
-
|
|
122
|
-
- **One-Click In-App Updater**: Check npm registry for updates and trigger one-click upgrades directly within the DSH Settings Card, complete with version diff badges and server restart alerts.
|
|
123
|
-
- **Strict Loopback Security**: All mutating HTTP endpoints (`/apply`, `/policy`, `/clear-cache`, `/updater/update`) now require verified loopback origin and remote socket IP to prevent CSRF / unauthorized network access.
|
|
124
|
-
- **100% Theme Token Compliance**: Eliminated all hardcoded colors and `rgba()` values in client UI in favor of official DSH theme tokens (`--dsw-alias-*`), ensuring perfect dark/light mode rendering.
|
|
125
|
-
- **Modular Architecture**: Decomposed core synchronization logic into specialized modules (`synchronizer-helpers.js`, `synchronizer-transfer.js`, `synchronizer-prober.js`), significantly enhancing code readability and maintainability.
|
|
126
|
-
- **Clean Packaging**: Excluded development and internal planning artifacts from git and npm distribution, maintaining an ultra-lightweight release bundle (< 70 KiB).
|
|
127
|
-
|
|
128
|
-
## 🚀 Enhancements in v0.3.14
|
|
129
|
-
|
|
130
|
-
- **Language Standard**: Canonical plugin in `en` and `zh`. Runtime Russian translations decoupled into `goodandready/dsh-russian-lang` (#191).
|
|
131
|
-
- **Packaging Isolation**: Dedicated `.npmignore` excludes tests, plans, and documentation to maintain a minimal < 256 KiB npm release bundle.
|
|
132
|
-
- **Batch Health Check**: Probe multiple selected models in parallel via `POST /dsh-model-sync/batch-try` with latency badges and one-click removal of unreachable models.
|
|
133
|
-
- **Cost & Context Policies**: Set maximum price per million tokens and minimum context window thresholds in provider policies.
|
|
134
|
-
- **Catalog Export & Import**: Backup and restore full plugin configuration (policies, selections, aliases, scheduler) via `GET /export` and `POST /import`.
|
|
135
|
-
- **Model Alias Mapping**: Assign friendly aliases to provider/model pairs with `GET /aliases` and `POST /aliases` with interactive UI card.
|
|
136
|
-
|
|
137
|
-
## 🚀 Enhancements in v0.3.13
|
|
138
|
-
|
|
139
|
-
* ⚡ **Zero-Overhead Polling via HTTP ETag / 304 Not Modified**:
|
|
140
|
-
* Implemented weak ETag generation for `GET /dsh-model-sync/status`. When the Web UI polls every 15 seconds, unchanged catalogs receive an empty `304 Not Modified` response, eliminating redundant JSON serialization and network traffic.
|
|
141
|
-
* 🌐 **Upstream Conditional HTTP Requests**:
|
|
142
|
-
* Added `If-None-Match` and `If-Modified-Since` headers to upstream provider discovery. Catalogs that return `304 Not Modified` resolve instantly from memory cache without re-parsing or diff re-computation.
|
|
143
|
-
* 🎯 **Debounced Search & Memoized Sorting in UI**:
|
|
144
|
-
* Introduced 150ms input debouncing and `React.useMemo` for model filtering/sorting in the model picker, ensuring fluid search responsiveness on catalogs with hundreds of models.
|
|
145
|
-
* 🧠 **Expanded Capability Detection**:
|
|
146
|
-
* Added detection for modern reasoning models (`DeepSeek-R1`, `o1`, `o3-mini`, `thinking`) and specialized code generation models (`code`), plus support for the `code` capability filter in policy matching and UI picker.
|
|
147
|
-
* 🛡️ **Exponential Retry Jitter**:
|
|
148
|
-
* Enhanced `retryWithBackoff` with randomized jitter (`0.5 - 1.0` multiplier) to prevent thundering-herd effects on provider APIs during network hiccups or rate limits.
|
|
149
|
-
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
## 🛠️ Enhancements & Fixes in v0.3.11
|
|
153
|
-
|
|
154
|
-
* 🗂️ **Streamlined Settings UI Surface**:
|
|
155
|
-
* Removed the redundant top-level settings sidebar section fallback (`settings.section`), keeping configuration strictly inside the standard DSH plugin settings card (`settings.plugin.item`).
|
|
156
|
-
* 🛡️ **Hardened Cordis Service Access**:
|
|
157
|
-
* Service access for `settings` and `llm` is now performed via `ctx.get(...)` with safe fallback to direct property inspection, preventing silent resolution failures on Cordis proxy implementations.
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
## 🛠️ Enhancements & Fixes in v0.3.8
|
|
162
|
-
|
|
163
|
-
* ⚙️ **Reactive Settings Card Binding (`settingsScope`)**:
|
|
164
|
-
* Integrated modern DSH kernel `settingsScope` service (`ctx.settingsScope.bind({ namespace: 'dsh-model-sync' })`) with `useSyncExternalStore`.
|
|
165
|
-
* Added direct configuration controls for the background scheduler in the Web UI: enable/disable background sync (`scheduleEnabled`), customize interval (`intervalMinutes`), and toggle automatic application of new models (`autoApply`).
|
|
166
|
-
* Gracefully handles all snapshot lifecycle states (`ready`, `loading`, `unavailable`) and collects field validation errors without dropping form drafts.
|
|
167
|
-
* 🌐 **Full Model Picker Localization**:
|
|
168
|
-
* Translated all previously hardcoded strings in the model selector, including search input placeholder and sorting options (`Name A→Z`, `Price ↑`, `Context ↓`, `Newest ↓`), dynamically reacting to DSH locale switching (`en` / `ru`).
|
|
169
|
-
* 📜 **Synchronization History Localization**:
|
|
170
|
-
* Added the missing `noHistory` key to English and Russian localization dictionaries, ensuring informative feedback when sync history is empty.
|
|
171
|
-
* 📋 **Project Design Contract**:
|
|
172
|
-
* Added authoritative `docs/design/DESIGN.md` defining UI surfaces, styling foundations, token conventions, and state contracts.
|
|
173
|
-
|
|
174
|
-
---
|
|
175
|
-
|
|
176
|
-
## 🛠️ Enhancements & Fixes in v0.3.6
|
|
177
|
-
|
|
178
|
-
* 🔑 **Universal Credential Resolution (`credentialRef` & `apiKeyRef`)**:
|
|
179
|
-
* Added full support for modern DSH `credentialRef` and `apiKeyRef` references across inventory detection, provider adapters, and OpenAI-compatible generic routes.
|
|
180
|
-
* Providers configured via DSH Credentials Service are now accurately discovered and authenticated without requiring legacy `apiKeyEnv`.
|
|
181
|
-
* ♻️ **Lifecycle Cleanup for Deprecated Models**:
|
|
182
|
-
* Fixed an issue where models previously marked as `deprecated` would remain indefinitely in settings when removed by the upstream provider. When `removeMissing: true` is enabled, missing deprecated models now cleanly transition to `removed` status once the grace period expires.
|
|
183
|
-
* ⏰ **Accurate Scheduler Inactive Status**:
|
|
184
|
-
* Corrected `scheduler.status()` to return `nextRunAt: null` when background synchronization is disabled, avoiding misleading run times in the Web UI.
|
|
185
|
-
* 🛡️ **Web UI Resilience & Big Catalog Scalability**:
|
|
186
|
-
* Eliminated potential UI crashes during model sorting by safely handling missing model display names.
|
|
187
|
-
* Replaced spread operations on model arrays with iterative aggregations, preventing call stack overflow (`RangeError`) on massive catalogs (10,000+ models).
|
|
188
|
-
* Surfaced detailed probe error messages in the UI when testing individual models via the `▶` button.
|
|
189
|
-
* Localized cache expiration and offline status strings in Russian and English.
|
|
190
|
-
* ⚡ **Deterministic Model Diffing & HTTP Stream Safety**:
|
|
191
|
-
* Implemented stable key-sorted serialization in `diffModels` and `sameModel` to eliminate false-positive diffs caused by non-deterministic JSON key order.
|
|
192
|
-
* Added early stream destruction on oversized HTTP request bodies to prevent memory bloat.
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
|
-
## 🚀 Enhancements in v0.3.10
|
|
197
|
-
|
|
198
|
-
* 📦 **Compacted History Storage**:
|
|
199
|
-
* Stripped non-essential metadata (`description`, `tags`, `aliases`) from catalog snapshots (`before`/`after`) in `settings.yaml`, retaining only essential properties (`id`, `name`, `capabilities`, `pricing`, `contextWindow`, `maxTokens`).
|
|
200
|
-
* Optimized default snapshot retention (`DEFAULT_SNAPSHOT_RETENTION = 3`) to keep configuration files lean while preserving full rollback functionality.
|
|
201
|
-
* ⚡ **Immediate Scheduler First Tick**:
|
|
202
|
-
* Scheduler now triggers an initial discovery run immediately upon startup when enabled without requiring an initial 60-minute wait.
|
|
203
|
-
* 🛡️ **Client-side Policy Regex Validation**:
|
|
204
|
-
* Added instant regex pattern verification in the Web UI before submitting `/policy` requests with localized error feedback.
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
## 🚀 Enhancements in v0.3.9
|
|
209
|
-
|
|
210
|
-
* 🔒 **Serialized Settings Mutations (`saveConfig`)**:
|
|
211
|
-
* Chained internal settings persistence via an async promise mutex (`saveQueue`).
|
|
212
|
-
* Eliminates race conditions between simultaneous sync runs and user UI interactions, ensuring clean atomic writes to `settings.yaml`.
|
|
213
|
-
* 🛡️ **Hardened Cross-Origin & CSRF Protections**:
|
|
214
|
-
* Enhanced `trusted(req)` checking to evaluate `sec-fetch-site`, `origin`, and `referer` against the HTTP `Host`.
|
|
215
|
-
* Blocks unauthorized cross-origin mutations while preserving legitimate local and reverse-proxy requests.
|
|
216
|
-
* 🎨 **Standardized Plugin Style Discovery**:
|
|
217
|
-
* Added `data-dsh-plugin="dsh-model-sync"` attribute to injected UI style tags in compliance with the DeepSeek Harness plugin authoring standard.
|
|
218
|
-
|
|
219
|
-
---
|
|
220
|
-
|
|
221
|
-
## 🚀 Enhancements in v0.3.5
|
|
222
|
-
|
|
223
|
-
* ⏱️ **Adaptive Rate Limit & Retry-After Handling**:
|
|
224
|
-
* Automatically parses HTTP headers `Retry-After` (in seconds or RFC dates) and `x-ratelimit-reset`.
|
|
225
|
-
* Exponential backoff prioritizes the exact delay requested by upstream providers, eliminating unnecessary throttling.
|
|
226
|
-
* Re-classified HTTP 429 errors under a dedicated `rate-limit` diagnostic label.
|
|
227
|
-
* 🔄 **Optimistic Concurrency & Conflict Auto-Recovery**:
|
|
228
|
-
* Added automated retry loop for `SETTINGS_CONFLICT` (HTTP 409). When concurrent settings updates occur in DSH, the plugin seamlessly re-fetches the latest revision and reapplies the catalog mutations.
|
|
229
|
-
* 🎯 **Advanced Web UI Picker & Filtering**:
|
|
230
|
-
* **Tokenized Smart Search**: Multi-word queries (`claude 3.5 sonnet`) match across model IDs, display names, tags, and descriptions simultaneously.
|
|
231
|
-
* **Quick Filter Chips**: One-click toggles for `Context ≥ 100k` and `Cheap ≤ $1/1M` in addition to capability toggles (`Vision`, `Tools`, `Reasoning`, `Embeddings`).
|
|
232
|
-
* **Batch Selection Controls**: One-click buttons to *Select all shown*, *Deselect all shown*, and *Invert selection*.
|
|
233
|
-
* **Chunked Rendering / Pagination**: Renders models in batches of 50 to maintain smooth 60fps UI performance even with catalogs containing 1,000+ models.
|
|
234
|
-
* **Deprecation Badges**: Models with scheduled retirement dates display an explicit countdown badge (`Deprecates in Nd`).
|
|
235
|
-
* 💾 **Storage & Metadata Optimizations**:
|
|
236
|
-
* Robust context limit parser supporting suffix multipliers (`128k`, `1M`, `128,000`).
|
|
237
|
-
* Automatic history compaction: historical snapshots older than the 5 latest sync runs have heavy before/after dumps pruned while retaining summary diffs, keeping `settings.yaml` ultra-compact.
|
|
238
|
-
|
|
239
|
-
---
|
|
240
|
-
|
|
241
|
-
## ⚙️ Configuration Reference (`settings.yaml`)
|
|
242
|
-
|
|
243
|
-
```yaml
|
|
244
|
-
dsh-model-sync:
|
|
245
|
-
enabled: true
|
|
246
|
-
syncIntervalMinutes: 60
|
|
247
|
-
autoReconcile: true
|
|
248
|
-
providers:
|
|
249
|
-
openrouter:
|
|
250
|
-
enabled: true
|
|
251
|
-
keyEnv: OPENROUTER_API_KEY
|
|
252
|
-
deepseek:
|
|
253
|
-
enabled: true
|
|
254
|
-
keyEnv: DEEPSEEK_API_KEY
|
|
255
|
-
custom:
|
|
256
|
-
enabled: false
|
|
257
|
-
baseURL: http://127.0.0.1:8000/v1
|
|
258
|
-
authType: bearer
|
|
259
|
-
keyEnv: CUSTOM_API_KEY
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
---
|
|
263
|
-
|
|
264
|
-
## 📄 License
|
|
265
|
-
|
|
266
|
-
MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
|
package/README.ru.md
CHANGED
|
@@ -116,128 +116,3 @@ dsh plugin --profile web add @goodandready/dsh-model-sync
|
|
|
116
116
|
* Защита от thundering herd с помощью случайного коэффициента джиттера (`0.5 - 1.0`) при повторных запросах к API провайдеров.
|
|
117
117
|
|
|
118
118
|
---
|
|
119
|
-
|
|
120
|
-
## 🛠️ Улучшения и исправления в v0.3.11
|
|
121
|
-
|
|
122
|
-
* 🗂️ **Чистый интерфейс настроек (DSH Design Contract)**:
|
|
123
|
-
* Удалена избыточная регистрация fallback-раздела верхнего уровня бокового меню (`settings.section`), настройки доступны только через стандартную карточку в «Настройки → Плагины → Настройки плагинов» (`settings.plugin.item`).
|
|
124
|
-
* 🛡️ **Надёжный доступ к сервисам Cordis**:
|
|
125
|
-
* Доступ к сервисам ядра (`settings`, `llm`) переведён на `ctx.get(...)` с безопасным fallback к прямым свойствам контекста для исключения ошибок проксирования.
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
## 🛠️ Улучшения и исправления в v0.3.8
|
|
130
|
-
|
|
131
|
-
* ⚙️ **Реактивное управление настройками через `settingsScope`**:
|
|
132
|
-
* Интегрирована встроенная служба ядра DSH `settingsScope` (`ctx.settingsScope.bind({ namespace: 'dsh-model-sync' })`) с использованием `useSyncExternalStore`.
|
|
133
|
-
* В карточку настроек плагина добавлены элементы прямого управления планировщиком: включение фонового расписания (`scheduleEnabled`), настройка интервала синхронизации (`intervalMinutes`) и флаг автоприменения изменений (`autoApply`).
|
|
134
|
-
* Корректная обработка всех статусов снимка (`ready`, `loading`, `unavailable`) с валидацией и сохранением полей без прерывания на первой ошибке.
|
|
135
|
-
* 🌐 **Полная локализация пикера моделей**:
|
|
136
|
-
* Заменены захардкоженные русские строки в селекторе моделей: плейсхолдер поиска и варианты сортировки (`Имя A→Z`, `Цена ↑`, `Контекст ↓`, `Новые ↓`) теперь динамически переключаются при смене языка интерфейса (`en` / `ru`).
|
|
137
|
-
* 📜 **Локализация пустой истории синхронизаций**:
|
|
138
|
-
* Добавлен отсутствовавший ключ `noHistory` в словари английского и русского языков («No synchronization history.» / «Истории синхронизаций нет.»).
|
|
139
|
-
* 📋 **Дизайн-контракт проекта**:
|
|
140
|
-
* Создан обязательный документ `docs/design/DESIGN.md`, фиксирующий пользовательские поверхности, токены `--dsw-*` и контракты компонентов.
|
|
141
|
-
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
## 🛠️ Улучшения и исправления в v0.3.6
|
|
145
|
-
|
|
146
|
-
* 🔑 **Универсальное разрешение учетных данных (`credentialRef` и `apiKeyRef`)**:
|
|
147
|
-
* Добавлена полная поддержка ссылок `credentialRef` и `apiKeyRef` в модулях инвентаря, реестре адаптеров и generic-маршрутах OpenAI-совместимых провайдеров.
|
|
148
|
-
* Провайдеры, настроенные через DSH Credentials Service, теперь корректно обнаруживаются и аутентифицируются без необходимости обязательного наличия `apiKeyEnv`.
|
|
149
|
-
* ♻️ **Очистка устаревших моделей в жизненном цикле**:
|
|
150
|
-
* Исправлена ошибка, из-за которой модели в статусе `deprecated` оставались в конфигурации бессрочно после их удаления провайдером. При флаге `removeMissing: true` такие модели теперь гарантированно переводятся в статус `removed` по истечении grace-периода.
|
|
151
|
-
* ⏰ **Точный статус неактивного планировщика**:
|
|
152
|
-
* Исправлен `scheduler.status()`: при отключённой фоновой синхронизации `nextRunAt` теперь возвращает `null`, исключая вводящие в заблуждение даты следующего запуска в Web UI.
|
|
153
|
-
* 🛡️ **Надежность и масштабируемость Web UI**:
|
|
154
|
-
* Защита от сбоев сортировки при отсутствии поля `name` у модели.
|
|
155
|
-
* Замена spread-операций на итеративную агрегацию при вычислении экстремумов контекста и цены, что предотвращает переполнение стека (`RangeError`) на огромных каталогах (10 000+ моделей).
|
|
156
|
-
* Детальный вывод текста ошибки при тестировании модели по кнопке `▶`.
|
|
157
|
-
* Локализация срока давности кеша в карточке провайдера.
|
|
158
|
-
* ⚡ **Детерминированное сравнение каталогов и безопасность потоков**:
|
|
159
|
-
* Реализована стабильная сортировка ключей перед сравнением моделей, исключающая фиктивные diff-записи из-за произвольного порядка ключей в JSON.
|
|
160
|
-
* Добавлено прерывание сетевого потока при превышении лимита размера тела HTTP-запроса для защиты от утечек памяти.
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
## 🚀 Новые возможности в v0.3.10
|
|
165
|
-
|
|
166
|
-
* 📦 **Компактизация хранения истории**:
|
|
167
|
-
* Очистка некритичных метаданных (`description`, `tags`, `aliases`) из снимков моделей (`before`/`after`) в `settings.yaml`, с сохранением ключевых свойств (`id`, `name`, `capabilities`, `pricing`, `contextWindow`, `maxTokens`).
|
|
168
|
-
* Оптимизирована глубина хранения снимков (`DEFAULT_SNAPSHOT_RETENTION = 3`) для предотвращения разрастания конфигурационного файла при сохранении возможности безопасного отката.
|
|
169
|
-
* ⚡ **Мгновенный первый запуск планировщика**:
|
|
170
|
-
* Планировщик автоматически запускает первичный синк сразу при старте, если расписание активно и предыдущие запуски отсутствуют.
|
|
171
|
-
* 🛡️ **Клиентская валидация regex-политик**:
|
|
172
|
-
* Добавлена проверка синтаксиса регулярных выражений в интерфейсе настроек перед отправкой запроса на `/policy` с локализованными подсказками.
|
|
173
|
-
|
|
174
|
-
---
|
|
175
|
-
|
|
176
|
-
## 🚀 Новые возможности в v0.3.9
|
|
177
|
-
|
|
178
|
-
* 🔒 **Атомарная очередь сохранения настроек (`saveConfig`)**:
|
|
179
|
-
* Сериализация внутренних мутаций конфигурации через цепочку промисов (`saveQueue`).
|
|
180
|
-
* Предотвращает состояние гонки между фоновой синхронизацией и действиями пользователя в интерфейсе, гарантируя целостность `settings.yaml`.
|
|
181
|
-
* 🛡️ **Усиленная защита от CSRF и cross-origin атак**:
|
|
182
|
-
* Расширенная валидация запросов `trusted(req)` с проверкой заголовков `sec-fetch-site`, `origin` и `referer` против `Host`.
|
|
183
|
-
* Блокировка межсайтовых вызовов мутаций без нарушения локальных обращений и проксирования.
|
|
184
|
-
* 🎨 **Стандартизация инжекции стилей интерфейса**:
|
|
185
|
-
* Добавлен атрибут `data-dsh-plugin="dsh-model-sync"` для тега стилей в полном соответствии со стандартом разработки плагинов DeepSeek Harness.
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
|
-
## 🚀 Новые возможности в v0.3.5
|
|
190
|
-
|
|
191
|
-
* ⏱️ **Адаптивная обработка Rate Limit и Retry-After**:
|
|
192
|
-
* Автоматический парсинг HTTP-заголовков `Retry-After` (в секундах и формате RFC-дат) и `x-ratelimit-reset`.
|
|
193
|
-
* При повторах задержка выставляется строго по требованию провайдера.
|
|
194
|
-
* Ошибки 429 классифицируются в отдельную категорию `rate-limit`.
|
|
195
|
-
* 🔄 **Автоматическое разрешение конфликтов настроек**:
|
|
196
|
-
* Добавлен цикл повторов для `SETTINGS_CONFLICT` (HTTP 409). При параллельных правках конфигурации DSH плагин автоматически перечитывает ревизию и накладывает изменения без ошибок.
|
|
197
|
-
* 🎯 **Оптимизация панели выбора моделей в Web UI**:
|
|
198
|
-
* **Токенизированный умный поиск**: Слова поискового запроса (`claude 3.5 sonnet`) сопоставляются независимо по ID, названиям, тегам и описаниям моделей.
|
|
199
|
-
* **Быстрые фильтр-чипы**: Фильтры `Контекст ≥ 100k` и `Дешевые ≤ $1/1M` в дополнение к фильтрам возможностей (`Зрение`, `Инструменты`, `Рассуждение`, `Эмбеддинги`).
|
|
200
|
-
* **Массовый выбор**: Кнопки *Выбрать все показанные*, *Снять выбор с показанных*, *Инвертировать выбор*.
|
|
201
|
-
* **Порционный рендеринг (пагинация)**: Отображение порциями по 50 моделей с кнопкой «Показать ещё» для плавной работы интерфейса в каталогах с 1000+ моделями.
|
|
202
|
-
* **Бейджи устаревания моделей**: Для моделей с датой вывода из эксплуатации выводится обратный отсчет (`Устареет через N дн.`).
|
|
203
|
-
* 💾 **Хранение и парсинг метаданных**:
|
|
204
|
-
* Корректный разбор числовых значений с запятыми и суффиксами (`128k`, `1M`, `128,000`).
|
|
205
|
-
* Автоматическая компактификация: снимки каталогов старше 5 последних запусков очищаются от тяжелых дампов, сохраняя diff-аудит и компактность `settings.yaml`.
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
## ⚙️ Пример конфигурации (`settings.yaml`)
|
|
210
|
-
|
|
211
|
-
```yaml
|
|
212
|
-
dsh-model-sync:
|
|
213
|
-
enabled: true
|
|
214
|
-
syncIntervalMinutes: 60
|
|
215
|
-
autoReconcile: true
|
|
216
|
-
providers:
|
|
217
|
-
openrouter:
|
|
218
|
-
enabled: true
|
|
219
|
-
keyEnv: OPENROUTER_API_KEY
|
|
220
|
-
deepseek:
|
|
221
|
-
enabled: true
|
|
222
|
-
keyEnv: DEEPSEEK_API_KEY
|
|
223
|
-
custom:
|
|
224
|
-
enabled: false
|
|
225
|
-
baseURL: http://127.0.0.1:8000/v1
|
|
226
|
-
authType: bearer
|
|
227
|
-
keyEnv: CUSTOM_API_KEY
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
---
|
|
231
|
-
|
|
232
|
-
## 🚀 Улучшения в версии 0.3.14
|
|
233
|
-
|
|
234
|
-
- **Языковой стандарт**: Каноническая поддержка `en` и `zh` в кодовой базе плагина; русскоязычная локализация вынесена в пакет `goodandready/dsh-russian-lang` (#191).
|
|
235
|
-
- **Изоляция релиза**: Настроен `.npmignore` для исключения тестов, планов и документации из npm-пакета.
|
|
236
|
-
- **Пакетная проверка моделей (Batch Try)**: Эндпоинт `POST /dsh-model-sync/batch-try`, бейджи задержки и мгновенная деселекция недоступных моделей.
|
|
237
|
-
- **Политики по цене и контексту**: Опциональные фильтры `maxPricePerMillion` и `minContextTokens` в настройках провайдера.
|
|
238
|
-
- **Экспорт и импорт конфигурации**: JSON-бэкап и перенос настроек через `GET /export` и `POST /import`.
|
|
239
|
-
- **Пользовательские алиасы моделей**: Управление алиасами моделей через `GET/POST /aliases` и UI-карточку.
|
|
240
|
-
|
|
241
|
-
## 📄 Лицензия
|
|
242
|
-
|
|
243
|
-
MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
|
package/README.zh.md
CHANGED
|
@@ -115,13 +115,3 @@ dsh plugin --profile web add @goodandready/dsh-model-sync
|
|
|
115
115
|
## 📄 开源协议
|
|
116
116
|
|
|
117
117
|
MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
|
|
118
|
-
|
|
119
|
-
## 🛠️ v0.3.11 改进与修复
|
|
120
|
-
|
|
121
|
-
* 🗂️ **规范化设置界面**:
|
|
122
|
-
* 移除侧边栏顶层多余的 `settings.section` fallback,统一使用标准插件设置卡片 `settings.plugin.item`。
|
|
123
|
-
* 🛡️ **增强 Cordis 服务访问稳定性**:
|
|
124
|
-
* 使用 `ctx.get(...)` 安全获取 `settings` 与 `llm` 服务,避免代理对象属性解析异常。
|
|
125
|
-
|
|
126
|
-
---
|
|
127
|
-
|
package/lib/models.js
CHANGED
|
@@ -92,7 +92,14 @@ function normalizeCapabilities(row) {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
const sources = [
|
|
95
|
+
const sources = [
|
|
96
|
+
row?.capabilities,
|
|
97
|
+
row?.supportedCapabilities,
|
|
98
|
+
row?.supported_capabilities,
|
|
99
|
+
row?.supportedFeatures,
|
|
100
|
+
row?.supported_features,
|
|
101
|
+
row?.features,
|
|
102
|
+
]
|
|
96
103
|
for (const source of sources) {
|
|
97
104
|
if (Array.isArray(source)) {
|
|
98
105
|
for (const token of source) {
|
|
@@ -148,6 +155,74 @@ function normalizeCapabilities(row) {
|
|
|
148
155
|
return Object.keys(result).length > 0 ? result : undefined
|
|
149
156
|
}
|
|
150
157
|
|
|
158
|
+
|
|
159
|
+
function isGroqMinijinjaModel(id) {
|
|
160
|
+
if (typeof id !== 'string') return false
|
|
161
|
+
const lower = id.toLowerCase().replace(/^groq\//, '')
|
|
162
|
+
return (
|
|
163
|
+
lower.startsWith('qwen') ||
|
|
164
|
+
lower.startsWith('meta-llama') ||
|
|
165
|
+
lower.startsWith('llama') ||
|
|
166
|
+
lower.startsWith('mistral') ||
|
|
167
|
+
lower.startsWith('mixtral') ||
|
|
168
|
+
lower.startsWith('gemma') ||
|
|
169
|
+
lower.startsWith('deepseek')
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function normalizeCompat(provider, row, id) {
|
|
174
|
+
const source = row?.compat && typeof row.compat === 'object' ? { ...row.compat } : {}
|
|
175
|
+
const isGroq = provider === 'groq'
|
|
176
|
+
const isDeepSeek = provider === 'deepseek'
|
|
177
|
+
|
|
178
|
+
let defaultSupportsDeveloperRole
|
|
179
|
+
if (isGroq && id && isGroqMinijinjaModel(id)) {
|
|
180
|
+
defaultSupportsDeveloperRole = false
|
|
181
|
+
} else if (isDeepSeek) {
|
|
182
|
+
defaultSupportsDeveloperRole = false
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (source.supportsDeveloperRole === undefined && defaultSupportsDeveloperRole !== undefined) {
|
|
186
|
+
source.supportsDeveloperRole = defaultSupportsDeveloperRole
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return Object.keys(source).length > 0 ? source : undefined
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function normalizeInput(row) {
|
|
193
|
+
const modalitySources = [row?.inputModalities, row?.input_modalities, row?.modalities]
|
|
194
|
+
for (const source of modalitySources) {
|
|
195
|
+
if (Array.isArray(source) && source.length > 0) {
|
|
196
|
+
const set = new Set()
|
|
197
|
+
for (const item of source) {
|
|
198
|
+
if (typeof item !== 'string') continue
|
|
199
|
+
const val = item.trim().toLowerCase()
|
|
200
|
+
if (val === 'image' || val === 'vision') set.add('image')
|
|
201
|
+
else if (val === 'text') set.add('text')
|
|
202
|
+
else if (val) set.add(val)
|
|
203
|
+
}
|
|
204
|
+
const order = ['text', 'image']
|
|
205
|
+
const result = []
|
|
206
|
+
for (const k of order) {
|
|
207
|
+
if (set.has(k)) {
|
|
208
|
+
result.push(k)
|
|
209
|
+
set.delete(k)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
for (const k of set) {
|
|
213
|
+
result.push(k)
|
|
214
|
+
}
|
|
215
|
+
if (result.length > 0) return result
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (Array.isArray(row?.input)) {
|
|
220
|
+
return row.input.map((item) => (typeof item === 'string' ? item.trim() : item)).filter(Boolean)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return undefined
|
|
224
|
+
}
|
|
225
|
+
|
|
151
226
|
function normalizeTags(row) {
|
|
152
227
|
const source = row?.tags ?? row?.labels
|
|
153
228
|
if (!Array.isArray(source)) return undefined
|
|
@@ -208,6 +283,9 @@ export function normalizeModel(provider, row) {
|
|
|
208
283
|
row = { id: row }
|
|
209
284
|
}
|
|
210
285
|
if (!row || typeof row !== 'object') return null
|
|
286
|
+
const effectiveProvider = (typeof provider === 'string' && provider.trim())
|
|
287
|
+
? provider.trim()
|
|
288
|
+
: (typeof row.provider === 'string' ? row.provider.trim() : '')
|
|
211
289
|
const id = String(row.id ?? row.slug ?? row.model ?? '').trim()
|
|
212
290
|
if (!id) return null
|
|
213
291
|
const name = String(row.name ?? row.displayName ?? row.display_name ?? id).trim() || id
|
|
@@ -218,13 +296,17 @@ export function normalizeModel(provider, row) {
|
|
|
218
296
|
const tags = normalizeTags(row)
|
|
219
297
|
const aliases = normalizeAliases(row, id)
|
|
220
298
|
const lifecycle = normalizeLifecycle(row)
|
|
299
|
+
const input = normalizeInput(row)
|
|
300
|
+
const compat = normalizeCompat(effectiveProvider, row, id)
|
|
221
301
|
return {
|
|
222
|
-
provider,
|
|
302
|
+
provider: effectiveProvider || provider,
|
|
223
303
|
id,
|
|
224
304
|
name,
|
|
225
305
|
...(contextWindow === undefined ? {} : { contextWindow }),
|
|
226
306
|
...(maxTokens === undefined ? {} : { maxTokens }),
|
|
227
307
|
...(row.description ? { description: String(row.description) } : {}),
|
|
308
|
+
...(input === undefined ? {} : { input }),
|
|
309
|
+
...(compat === undefined ? {} : { compat }),
|
|
228
310
|
...(capabilities === undefined ? {} : { capabilities }),
|
|
229
311
|
...(pricing === undefined ? {} : { pricing }),
|
|
230
312
|
...(tags === undefined ? {} : { tags }),
|
package/lib/reconcile.js
CHANGED
|
@@ -18,8 +18,20 @@ export function reconcileModels(provider, current, discovered, {
|
|
|
18
18
|
const stale = []
|
|
19
19
|
for (const row of before) {
|
|
20
20
|
const fresh = advertisedById.get(row.id)
|
|
21
|
-
if (fresh)
|
|
22
|
-
|
|
21
|
+
if (fresh) {
|
|
22
|
+
const merged = {
|
|
23
|
+
...row,
|
|
24
|
+
...fresh,
|
|
25
|
+
...(row.capabilities || fresh.capabilities ? {
|
|
26
|
+
capabilities: { ...(fresh.capabilities ?? {}), ...(row.capabilities ?? {}) },
|
|
27
|
+
} : {}),
|
|
28
|
+
...(row.compat || fresh.compat ? {
|
|
29
|
+
compat: { ...(fresh.compat ?? {}), ...(row.compat ?? {}) },
|
|
30
|
+
} : {}),
|
|
31
|
+
...(fresh.input?.length ? { input: fresh.input } : row.input ? { input: row.input } : {}),
|
|
32
|
+
}
|
|
33
|
+
next.push(merged)
|
|
34
|
+
} else if (renamedBefore.has(row.id)) {
|
|
23
35
|
// An explicit provider alias is safe evidence that the old id was renamed.
|
|
24
36
|
} else {
|
|
25
37
|
stale.push(row)
|