tensorgrid-ui 2.1.0 → 2.3.0

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.
@@ -285,6 +285,22 @@ async function listRouteModels(llm, credentials) {
285
285
  // работает, но записи не имеет, настроен извне: у OpenRouter ключ лежит
286
286
  // переменной окружения, и по записям он выглядел бы ненастроенным, хотя
287
287
  // отвечает. Проверено на живых данных.
288
+ //
289
+ // «НЕ ЗНАЮ» — ОТДЕЛЬНЫЙ ОТВЕТ, А НЕ «ПО ТОКЕНАМ».
290
+ //
291
+ // Здесь стояла дыра, которая врала в самую дорогую сторону. Когда служба
292
+ // хранилища недоступна, прежний код помечал ВСЕ модели как платные —
293
+ // включая подписочные. Человек видел «по токенам» на claude-opus-5,
294
+ // который ему давно оплачен, и мог отказаться от ревизора из-за счёта,
295
+ // которого не будет.
296
+ //
297
+ // Случай не выдуманный: он воспроизвёлся сразу. Обработчики
298
+ // перечитываются на лету, а оболочка — только при старте, и до
299
+ // перезапуска новый код спрашивал хранилище у старой оболочки, которая
300
+ // его не передавала. Все 388 моделей стали «по токенам».
301
+ //
302
+ // Теперь неизвестность возвращается как `null`, и показ обязан молчать.
303
+ let known = false
288
304
  const billing = new Map()
289
305
  if (credentials !== undefined && credentials !== null) {
290
306
  try {
@@ -294,8 +310,9 @@ async function listRouteModels(llm, credentials) {
294
310
  const name = slash >= 0 ? key.slice(slash + 1) : key
295
311
  billing.set(name, record.kind === 'grant' ? 'subscription' : 'api-key')
296
312
  }
313
+ known = true
297
314
  } catch {
298
- // Хранилище недоступно — покажем модели без отметки, это лучше отказа.
315
+ // Хранилище не ответило — покажем модели без отметки, это лучше лжи.
299
316
  }
300
317
  }
301
318
 
@@ -303,7 +320,10 @@ async function listRouteModels(llm, credentials) {
303
320
  for (const info of providers) {
304
321
  const name = typeof info === 'string' ? info : info?.name ?? info?.provider
305
322
  if (typeof name !== 'string' || name === '') continue
306
- const kind = billing.get(name) ?? 'external'
323
+ // Провайдер без записи, но отвечающий, настроен вне dsh — ключом из
324
+ // окружения. Для человека это значит то же, что сохранённый ключ: счёт
325
+ // придёт. А вот когда хранилище вовсе не спросили, сказать нечего.
326
+ const kind = known ? billing.get(name) ?? 'api-key' : null
307
327
  try {
308
328
  const models = await llm.listModels(name)
309
329
  for (const model of models ?? []) {
@@ -346,7 +366,13 @@ export async function handleReview(req, res, loadModule, services) {
346
366
  label: spec.label,
347
367
  internal: spec.kind === 'internal',
348
368
  optional: spec.optional === true,
349
- models: spec.kind === 'internal' ? routeModels : spec.models.map((id) => ({ provider: null, id, billing: 'external' })),
369
+ // У ВНЕШНИХ ПРОДУКТОВ ОТМЕТКИ ОПЛАТЫ НЕТ, и это не упущение.
370
+ //
371
+ // Claude Code и Codex работают на СВОИХ подписках и нашего маршрута не
372
+ // касаются — мы не знаем и не можем знать, во что обойдётся их запуск.
373
+ // Прежде им доставалась метка «по токенам» просто потому, что она была
374
+ // всем, кроме подписки. Это было неверно.
375
+ models: spec.kind === 'internal' ? routeModels : spec.models.map((id) => ({ provider: null, id, billing: null })),
350
376
  // Для ВНЕШНИХ продуктов список остаётся зашитым: спросить у Claude Code
351
377
  // или Codex их уровни нечем, они не наш маршрут.
352
378
  efforts: spec.kind === 'internal' ? [] : spec.efforts,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tensorgrid-ui",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "TENSOR GRID — фирменный интерфейс поверх DeepSeek Harness: палитра, живой ambient-слой, айдентика и русский язык-пакет",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",