dsh-plugin-subscription-oauth 0.8.14 → 0.8.16
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/lib/auth/provider-controller.js +27 -17
- package/lib/auth/tokens.js +1 -1
- package/lib/client/FastModeButton.d.ts +50 -0
- package/lib/client/FastModeButton.js +94 -0
- package/lib/client/UsageChip.js +2 -1
- package/lib/client/index.d.ts +14 -1
- package/lib/client/index.js +46 -2
- package/lib/client/styles.d.ts +8 -0
- package/lib/client/styles.js +61 -0
- package/lib/client.js +205 -3
- package/lib/client.js.map +1 -1
- package/lib/index.js +2 -0
- package/lib/protocol.d.ts +13 -1
- package/lib/providers/antigravity-catalog.d.ts +29 -9
- package/lib/providers/antigravity-catalog.js +212 -56
- package/lib/providers/antigravity.d.ts +2 -0
- package/lib/providers/antigravity.js +25 -3
- package/lib/providers/grok.d.ts +109 -3
- package/lib/providers/grok.js +261 -35
- package/lib/providers/kimi-provider.js +2 -2
- package/lib/providers/kimi.d.ts +22 -2
- package/lib/providers/kimi.js +74 -23
- package/lib/translate/antigravity.js +3 -3
- package/package.json +1 -1
package/lib/providers/grok.js
CHANGED
|
@@ -268,15 +268,152 @@ const IMAGE_MODEL = /(?:^|[-_/])(?:image|imagine|draw|pic|photo)(?:[-_/]|$)/i;
|
|
|
268
268
|
export function isImageModel(id) {
|
|
269
269
|
return IMAGE_MODEL.test(id);
|
|
270
270
|
}
|
|
271
|
-
/**
|
|
272
|
-
|
|
271
|
+
/**
|
|
272
|
+
* Model ids that are the fast/lightspeed variant of a base model, matched per base.
|
|
273
|
+
*
|
|
274
|
+
* The vocabulary is the providers' own: xAI says `fast` (`grok-4.7-build-fast`), the
|
|
275
|
+
* Claude/Codex world says `lightspeed` or `turbo`, and Kimi says `highspeed`
|
|
276
|
+
* (`kimi-for-coding-highspeed`). A word has to stand on its own, so `highspeed` never
|
|
277
|
+
* matches inside another word.
|
|
278
|
+
*/
|
|
279
|
+
const FAST_VARIANT = /(?:^|[-_@])(?:fast|lightspeed|turbo|quick|highspeed)(?=[-_@]|$)/i;
|
|
273
280
|
/** True when a model id names a fast/lightspeed variant of a base model. */
|
|
274
281
|
export function isFastVariant(id) {
|
|
275
282
|
return FAST_VARIANT.test(id);
|
|
276
283
|
}
|
|
277
|
-
/**
|
|
284
|
+
/**
|
|
285
|
+
* Every prefix of one model id, longest first, down to its first token.
|
|
286
|
+
*
|
|
287
|
+
* `grok-4.7-build-fast` → [`grok-4.7-build`, `grok-4.7`, `grok`]. A fast variant pairs
|
|
288
|
+
* with the longest prefix that is itself a listed model id, which is how
|
|
289
|
+
* `grok-4.7-build-fast` lands on `grok-4.7` (its own prefix `grok-4.7-build` is not a
|
|
290
|
+
* model) instead of inventing a base that no catalog row serves.
|
|
291
|
+
*
|
|
292
|
+
* @param id - model id.
|
|
293
|
+
* @returns the candidate bases, longest first.
|
|
294
|
+
*/
|
|
295
|
+
export function baseCandidatesOf(id) {
|
|
296
|
+
const out = [];
|
|
297
|
+
let at = id.length;
|
|
298
|
+
while (at > 0) {
|
|
299
|
+
at = id.lastIndexOf('-', at - 1);
|
|
300
|
+
if (at <= 0)
|
|
301
|
+
break;
|
|
302
|
+
out.push(id.slice(0, at));
|
|
303
|
+
}
|
|
304
|
+
return out;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* The base model id a fast variant belongs to, derived only from its own name.
|
|
308
|
+
*
|
|
309
|
+
* The fast token is removed, then any trailing generation qualifier (`build`, `beta`,
|
|
310
|
+
* `rc`, …) left behind by that removal, then any `@Nk` context suffix. What remains is
|
|
311
|
+
* the base (`grok-4.7-build-fast@500k` → `grok-4.7`, `kimi-for-coding-highspeed` →
|
|
312
|
+
* `kimi-for-coding`). Whether the base is a real catalog row is the index's job, not
|
|
313
|
+
* this function's.
|
|
314
|
+
*/
|
|
278
315
|
export function baseModelOf(id) {
|
|
279
|
-
return id
|
|
316
|
+
return id
|
|
317
|
+
.replace(FAST_VARIANT, '')
|
|
318
|
+
.replace(/@\d+k$/i, '')
|
|
319
|
+
.replace(/[-_]$/, '')
|
|
320
|
+
.replace(/-(?:build|beta|alpha|rc|stable)$/i, '')
|
|
321
|
+
.replace(/[-_]$/, '');
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* The fast variant of one picker row, from either side of the pair.
|
|
325
|
+
*
|
|
326
|
+
* Shared by every route that discovers fast ids, so the composer's quick-mode button
|
|
327
|
+
* behaves the same wherever a fast model is identifiable: it finds the pair when asked
|
|
328
|
+
* about the base row, and when asked about the fast id itself — which is what the
|
|
329
|
+
* selection becomes once the mode is on — so it can switch back off again.
|
|
330
|
+
*/
|
|
331
|
+
export class FastVariantIndex {
|
|
332
|
+
byBase = new Map();
|
|
333
|
+
rowOfVariant = new Map();
|
|
334
|
+
knownIds = new Set();
|
|
335
|
+
/** Forget every pair and every known id, before re-reading a catalog. */
|
|
336
|
+
clear() {
|
|
337
|
+
this.byBase.clear();
|
|
338
|
+
this.rowOfVariant.clear();
|
|
339
|
+
this.knownIds.clear();
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Record one id the catalog listed.
|
|
343
|
+
*
|
|
344
|
+
* Listed ids are what a variant may pair with: the pair is the longest listed prefix
|
|
345
|
+
* of the variant's own name, so nothing is invented that no row actually serves.
|
|
346
|
+
*
|
|
347
|
+
* @param id - a wire id from a catalog.
|
|
348
|
+
*/
|
|
349
|
+
noteListed(id) {
|
|
350
|
+
this.knownIds.add(id);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Pair one fast id with its base, purely from its own name.
|
|
354
|
+
*
|
|
355
|
+
* Every listed prefix of the id is a candidate base, longest first; the first one
|
|
356
|
+
* that is itself a listed model wins. No curated alias or hardcoded map is needed:
|
|
357
|
+
* a provider that names its variants after the base model pairs them automatically.
|
|
358
|
+
*
|
|
359
|
+
* @param id - a wire id the catalog named.
|
|
360
|
+
* @returns the base id, or undefined when no listed prefix names one.
|
|
361
|
+
*/
|
|
362
|
+
pair(id) {
|
|
363
|
+
if (!isFastVariant(id))
|
|
364
|
+
return undefined;
|
|
365
|
+
for (const base of baseCandidatesOf(id)) {
|
|
366
|
+
if (this.knownIds.has(base))
|
|
367
|
+
return base;
|
|
368
|
+
}
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Record one id, if it names a fast variant.
|
|
373
|
+
*
|
|
374
|
+
* The first variant named for a row wins: a catalog that lists two spellings of the
|
|
375
|
+
* same variant (`kimi-for-coding-highspeed` and `kimi-k2.7-code-highspeed`) offers
|
|
376
|
+
* one button, and the earlier entry is the more specific one.
|
|
377
|
+
*
|
|
378
|
+
* @param id - a wire id from a catalog.
|
|
379
|
+
* @param rowOf - maps a base id to the picker row that serves it, when the catalog
|
|
380
|
+
* spells the base differently from the variant's own prefix.
|
|
381
|
+
*/
|
|
382
|
+
note(id, rowOf) {
|
|
383
|
+
if (!isFastVariant(id))
|
|
384
|
+
return;
|
|
385
|
+
const base = baseModelOf(id);
|
|
386
|
+
if (base.length === 0)
|
|
387
|
+
return;
|
|
388
|
+
const row = rowOf?.(base) ?? base;
|
|
389
|
+
if (!this.byBase.has(row))
|
|
390
|
+
this.byBase.set(row, id);
|
|
391
|
+
if (!this.rowOfVariant.has(id))
|
|
392
|
+
this.rowOfVariant.set(id, row);
|
|
393
|
+
}
|
|
394
|
+
/** The fast variant's wire id for one picker row, when the catalog named one. */
|
|
395
|
+
variantOf(baseId) {
|
|
396
|
+
return this.byBase.get(baseId);
|
|
397
|
+
}
|
|
398
|
+
/** The pair one picker id belongs to, from either side. */
|
|
399
|
+
pairOf(id) {
|
|
400
|
+
const direct = this.byBase.get(id);
|
|
401
|
+
if (direct !== undefined)
|
|
402
|
+
return { baseId: id, wireId: direct };
|
|
403
|
+
const row = this.rowOfVariant.get(id);
|
|
404
|
+
return row === undefined ? undefined : { baseId: row, wireId: id };
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/** A context-size suffix like `@500k` on a model id. */
|
|
408
|
+
const CONTEXT_SUFFIX = /@(\d+)k$/i;
|
|
409
|
+
/** Extract the context size from a model id's `@Nk` suffix, or undefined. */
|
|
410
|
+
export function contextOf(id) {
|
|
411
|
+
const match = CONTEXT_SUFFIX.exec(id);
|
|
412
|
+
return match ? parseInt(match[1], 10) : undefined;
|
|
413
|
+
}
|
|
414
|
+
/** Strip the `@Nk` context suffix from a model id. */
|
|
415
|
+
export function stripContext(id) {
|
|
416
|
+
return id.replace(CONTEXT_SUFFIX, '');
|
|
280
417
|
}
|
|
281
418
|
/** Grok wire adapter: one instance serves the `grok` provider route. */
|
|
282
419
|
export class GrokAdapter extends LlmAdapter {
|
|
@@ -286,7 +423,7 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
286
423
|
/** Capability metadata from the CLI catalog, keyed by model id. */
|
|
287
424
|
metadata = new Map();
|
|
288
425
|
/** Fast-variant wire id per base model, for the picker's quick-mode button. */
|
|
289
|
-
fastVariants = new
|
|
426
|
+
fastVariants = new FastVariantIndex();
|
|
290
427
|
/** Image-generation model id, when discovery reported one. */
|
|
291
428
|
imageModel;
|
|
292
429
|
/** Ids the user added by hand, cached so the sync catalog can name them. */
|
|
@@ -309,15 +446,24 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
309
446
|
return [];
|
|
310
447
|
await this.syncUserModels();
|
|
311
448
|
const hidden = await this.hidden();
|
|
312
|
-
//
|
|
449
|
+
// The host validates a GUI selection against the exact ids `listModels` returns
|
|
450
|
+
// and refuses an unknown one with `session/model-unavailable`, and its picker
|
|
451
|
+
// lists every returned id as its own row. So a fast variant is published under
|
|
452
|
+
// its base id: selecting it names the variant the request must send, and the
|
|
453
|
+
// base's own id is withheld so the variant does not appear twice.
|
|
313
454
|
const imageless = this.catalog().filter((entry) => !isImageModel(entry.id));
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
id
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
455
|
+
const listed = resolveCatalog(imageless, [], hidden).entries.map((entry) => {
|
|
456
|
+
const fast = this.fastVariants.variantOf(entry.id);
|
|
457
|
+
const id = fast ?? entry.id;
|
|
458
|
+
return {
|
|
459
|
+
provider: GROK_PROVIDER_ID,
|
|
460
|
+
id,
|
|
461
|
+
name: entry.name,
|
|
462
|
+
...entry.description === undefined ? {} : { description: entry.description },
|
|
463
|
+
...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
|
|
464
|
+
};
|
|
465
|
+
});
|
|
466
|
+
return listed;
|
|
321
467
|
}
|
|
322
468
|
async hidden() {
|
|
323
469
|
if (this.options.hiddenModels === undefined)
|
|
@@ -332,7 +478,12 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
332
478
|
}
|
|
333
479
|
async resolveModel(_provider, model) {
|
|
334
480
|
await this.syncUserModels();
|
|
335
|
-
|
|
481
|
+
// A fast variant is not a catalog row of its own: it answers with its base model's
|
|
482
|
+
// metadata — the same 500k window, name and ladder the picker shows — while the id
|
|
483
|
+
// stays the fast wire id the request must send.
|
|
484
|
+
const pair = this.fastPairOf(model);
|
|
485
|
+
const entry = findEntry(this.catalog(), model)
|
|
486
|
+
?? (pair === undefined ? undefined : findEntry(this.catalog(), pair.baseId));
|
|
336
487
|
if (entry === undefined) {
|
|
337
488
|
const template = findEntry(GROK_MODELS, 'grok-4.6');
|
|
338
489
|
const reasoning = template === undefined ? undefined : reasoningInfo(template);
|
|
@@ -346,10 +497,13 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
346
497
|
};
|
|
347
498
|
}
|
|
348
499
|
const reasoning = reasoningInfo(entry);
|
|
500
|
+
// The fast selection names itself "Fast" so the picker trigger reads the mode, not
|
|
501
|
+
// the base model it replaces; the id stays the fast wire id the request must send.
|
|
502
|
+
const fast = pair !== undefined && pair.wireId === model;
|
|
349
503
|
return {
|
|
350
504
|
provider: GROK_PROVIDER_ID,
|
|
351
|
-
id:
|
|
352
|
-
name: entry.name,
|
|
505
|
+
id: model,
|
|
506
|
+
name: fast ? `${entry.name} Fast` : entry.name,
|
|
353
507
|
...entry.description === undefined ? {} : { description: entry.description },
|
|
354
508
|
...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
|
|
355
509
|
context: { contextWindow: entry.contextWindow },
|
|
@@ -358,7 +512,9 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
358
512
|
};
|
|
359
513
|
}
|
|
360
514
|
stream(options) {
|
|
361
|
-
|
|
515
|
+
// Resolve @Nk context suffixes to the largest variant the endpoint offers.
|
|
516
|
+
const model = this.resolveModelId(options.model);
|
|
517
|
+
return streamProviderResponses({ ...options, model }, {
|
|
362
518
|
label: 'xAI API',
|
|
363
519
|
tokens: this.options.tokens,
|
|
364
520
|
request: (call, model, accessToken, signal) => this.request(call, model, accessToken, signal),
|
|
@@ -409,14 +565,17 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
409
565
|
...meta?.defaultEffort === undefined ? {} : { defaultEffort: meta.defaultEffort },
|
|
410
566
|
});
|
|
411
567
|
}
|
|
412
|
-
// The seeds also pick up live metadata (
|
|
568
|
+
// The seeds also pick up live metadata (reasoning ladder, default effort). The
|
|
569
|
+
// curated context window is never narrowed by a live figure: the CLI catalog states
|
|
570
|
+
// 256k for `grok-4.7`, which serves 500k, and a live read may only widen what this
|
|
571
|
+
// build ships.
|
|
413
572
|
const seeded = GROK_MODELS.map((entry) => {
|
|
414
573
|
const meta = this.metadata.get(entry.id);
|
|
415
574
|
if (meta === undefined)
|
|
416
575
|
return entry;
|
|
417
576
|
return {
|
|
418
577
|
...entry,
|
|
419
|
-
contextWindow: meta.contextWindow ??
|
|
578
|
+
contextWindow: Math.max(entry.contextWindow, meta.contextWindow ?? 0),
|
|
420
579
|
...meta.reasoningEfforts === undefined ? {} : { reasoningEfforts: meta.reasoningEfforts },
|
|
421
580
|
...meta.defaultEffort === undefined ? {} : { defaultEffort: meta.defaultEffort },
|
|
422
581
|
};
|
|
@@ -459,7 +618,11 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
459
618
|
}
|
|
460
619
|
/** The fast/lightspeed variant wire id for a base model, when discovery reported one. */
|
|
461
620
|
fastVariant(baseId) {
|
|
462
|
-
return this.fastVariants.
|
|
621
|
+
return this.fastVariants.variantOf(baseId);
|
|
622
|
+
}
|
|
623
|
+
/** The fast pair one picker id belongs to, from either side. */
|
|
624
|
+
fastPairOf(id) {
|
|
625
|
+
return this.fastVariants.pairOf(id);
|
|
463
626
|
}
|
|
464
627
|
/** The image-generation model id, when discovery reported one. */
|
|
465
628
|
imageModelId() {
|
|
@@ -474,6 +637,22 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
474
637
|
return this.shippedCatalog();
|
|
475
638
|
}
|
|
476
639
|
/** Build and send one request for one model. */
|
|
640
|
+
/** The default context variant per base model, set during discovery. */
|
|
641
|
+
defaultContext = new Map();
|
|
642
|
+
/** Resolve a model id to the wire id the endpoint accepts (largest context). */
|
|
643
|
+
resolveModelId(model) {
|
|
644
|
+
return this.defaultContext.get(model) ?? model;
|
|
645
|
+
}
|
|
646
|
+
/** Record one default-context mapping. */
|
|
647
|
+
noteContextVariant(base, context, wireId) {
|
|
648
|
+
const existing = this.defaultContext.get(base);
|
|
649
|
+
if (existing !== undefined) {
|
|
650
|
+
const existingCtx = contextOf(existing);
|
|
651
|
+
if (existingCtx !== undefined && existingCtx >= context)
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
this.defaultContext.set(base, wireId);
|
|
655
|
+
}
|
|
477
656
|
async request(options, model, accessToken, signal) {
|
|
478
657
|
const resolved = await toResponsesInput(options.messages, options.system, this.imageResolver(signal));
|
|
479
658
|
const body = {
|
|
@@ -552,24 +731,37 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
552
731
|
const rawIds = allIds.filter((id) => !NON_CHAT_ID.test(id));
|
|
553
732
|
// Fast/lightspeed variants ride with their base model: they share the base's
|
|
554
733
|
// visibility switch and are reached by a picker button, not a separate row.
|
|
734
|
+
// Context variants (@500k) also fold into the base; the largest context wins.
|
|
555
735
|
this.fastVariants.clear();
|
|
736
|
+
this.defaultContext.clear();
|
|
556
737
|
for (const id of rawIds) {
|
|
557
|
-
|
|
558
|
-
continue;
|
|
559
|
-
const base = baseModelOf(id);
|
|
560
|
-
if (!this.fastVariants.has(base))
|
|
561
|
-
this.fastVariants.set(base, id);
|
|
738
|
+
this.fastVariants.noteListed(id);
|
|
562
739
|
}
|
|
740
|
+
this.noteWireVariants(rawIds);
|
|
563
741
|
const ids = rawIds
|
|
564
|
-
.map((id) =>
|
|
742
|
+
.map((id) => {
|
|
743
|
+
if (isFastVariant(id))
|
|
744
|
+
return this.fastVariants.pair(id) ?? baseModelOf(id);
|
|
745
|
+
const ctx = contextOf(id);
|
|
746
|
+
if (ctx !== undefined)
|
|
747
|
+
return stripContext(id);
|
|
748
|
+
return id;
|
|
749
|
+
})
|
|
565
750
|
.filter((id, index, list) => list.indexOf(id) === index);
|
|
566
751
|
if (ids.length === 0) {
|
|
567
752
|
this.options.onWarn?.('xAI model discovery returned an empty catalog; using the built-in catalog');
|
|
568
753
|
return undefined;
|
|
569
754
|
}
|
|
570
|
-
const
|
|
571
|
-
for (const [id, meta] of metadata)
|
|
755
|
+
const cli = await this.readCliCatalog(fetchFn, signal, accessToken);
|
|
756
|
+
for (const [id, meta] of cli.metadata)
|
|
572
757
|
this.metadata.set(id, meta);
|
|
758
|
+
// The account's own CLI catalog is the only surface that names a fast variant:
|
|
759
|
+
// the public `/models` list omits `grok-4.7-build-fast` entirely. Its ids fold
|
|
760
|
+
// into the same base rows, and are never added as picker rows of their own.
|
|
761
|
+
for (const id of cli.ids) {
|
|
762
|
+
this.fastVariants.noteListed(id);
|
|
763
|
+
}
|
|
764
|
+
this.noteWireVariants(cli.ids);
|
|
573
765
|
return ids;
|
|
574
766
|
}
|
|
575
767
|
catch (error) {
|
|
@@ -579,21 +771,55 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
579
771
|
return undefined;
|
|
580
772
|
}
|
|
581
773
|
}
|
|
582
|
-
/**
|
|
583
|
-
|
|
774
|
+
/**
|
|
775
|
+
* Fold the fast and context variants of one id list into their base models.
|
|
776
|
+
*
|
|
777
|
+
* @param ids - wire ids to classify.
|
|
778
|
+
*/
|
|
779
|
+
noteWireVariants(ids) {
|
|
780
|
+
for (const id of ids) {
|
|
781
|
+
if (NON_CHAT_ID.test(id) || isImageModel(id))
|
|
782
|
+
continue;
|
|
783
|
+
if (isFastVariant(id)) {
|
|
784
|
+
// Pair with the longest listed prefix, not a derived string: the prefix is a
|
|
785
|
+
// model the account actually serves, so the button always targets a real row.
|
|
786
|
+
const base = this.fastVariants.pair(id);
|
|
787
|
+
this.fastVariants.note(id, () => base);
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
const ctx = contextOf(id);
|
|
791
|
+
if (ctx !== undefined)
|
|
792
|
+
this.noteContextVariant(stripContext(id), ctx, id);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Read per-model capabilities from the CLI catalog; failures are silent.
|
|
797
|
+
*
|
|
798
|
+
* The catalog answers only for the signed-in account's own bearer — an anonymous
|
|
799
|
+
* request is refused — and it, unlike the public `/models` list, names the account's
|
|
800
|
+
* fast variant.
|
|
801
|
+
*
|
|
802
|
+
* @param fetchFn - fetch implementation.
|
|
803
|
+
* @param signal - caller cancellation.
|
|
804
|
+
* @param accessToken - the account's bearer.
|
|
805
|
+
* @returns the capability metadata and every id the catalog named.
|
|
806
|
+
*/
|
|
807
|
+
async readCliCatalog(fetchFn, signal, accessToken) {
|
|
584
808
|
const result = new Map();
|
|
809
|
+
const ids = [];
|
|
585
810
|
try {
|
|
586
811
|
const response = await fetchFn(GROK_CLI_MODELS_URL, {
|
|
587
|
-
headers: attributedHeaders({ 'authorization':
|
|
812
|
+
headers: attributedHeaders({ 'authorization': `Bearer ${accessToken}` }),
|
|
588
813
|
...signal === undefined ? {} : { signal },
|
|
589
814
|
});
|
|
590
815
|
if (!response.ok)
|
|
591
|
-
return result;
|
|
816
|
+
return { metadata: result, ids };
|
|
592
817
|
const payload = await response.json();
|
|
593
818
|
for (const entry of payload.data ?? []) {
|
|
594
819
|
const id = typeof entry.id === 'string' && entry.id.length > 0 ? entry.id : undefined;
|
|
595
820
|
if (id === undefined)
|
|
596
821
|
continue;
|
|
822
|
+
ids.push(id);
|
|
597
823
|
const contextWindow = typeof entry.context_window === 'number' && Number.isFinite(entry.context_window)
|
|
598
824
|
? entry.context_window
|
|
599
825
|
: undefined;
|
|
@@ -617,7 +843,7 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
617
843
|
catch {
|
|
618
844
|
// Capability metadata is a bonus; the id list is what matters.
|
|
619
845
|
}
|
|
620
|
-
return result;
|
|
846
|
+
return { metadata: result, ids };
|
|
621
847
|
}
|
|
622
848
|
}
|
|
623
849
|
/**
|
|
@@ -759,10 +985,10 @@ export function createGrokProvider(options) {
|
|
|
759
985
|
usage: (force) => controller.usage(force),
|
|
760
986
|
reload: () => controller.reload(),
|
|
761
987
|
modelVariants: (id) => {
|
|
762
|
-
const
|
|
988
|
+
const pair = adapter.fastPairOf(id);
|
|
763
989
|
const image = adapter.imageModelId();
|
|
764
990
|
return {
|
|
765
|
-
...
|
|
991
|
+
...pair === undefined ? {} : { fast: pair.wireId, fastBase: pair.baseId },
|
|
766
992
|
...image === undefined ? {} : { image },
|
|
767
993
|
};
|
|
768
994
|
},
|
|
@@ -151,10 +151,10 @@ export function createKimiProvider(options) {
|
|
|
151
151
|
usage: (force) => controller.usage(force),
|
|
152
152
|
reload: () => controller.reload(),
|
|
153
153
|
modelVariants: (id) => {
|
|
154
|
-
const
|
|
154
|
+
const pair = adapter.fastPairOf(id);
|
|
155
155
|
const image = adapter.imageModelId();
|
|
156
156
|
return {
|
|
157
|
-
...
|
|
157
|
+
...pair === undefined ? {} : { fast: pair.wireId, fastBase: pair.baseId },
|
|
158
158
|
...image === undefined ? {} : { image },
|
|
159
159
|
};
|
|
160
160
|
},
|
package/lib/providers/kimi.d.ts
CHANGED
|
@@ -104,13 +104,33 @@ export declare class KimiAdapter extends LlmAdapter {
|
|
|
104
104
|
private discovered;
|
|
105
105
|
/** Image-generation model id, when discovery reported one. */
|
|
106
106
|
private imageModel;
|
|
107
|
-
/**
|
|
107
|
+
/**
|
|
108
|
+
* Fast-variant wire id per picker row, for the composer's quick-mode button.
|
|
109
|
+
*
|
|
110
|
+
* Seeded from the curated aliases — `kimi-for-coding-highspeed` is one — so the button
|
|
111
|
+
* exists before any discovery run, and then updated from the live catalog, which is
|
|
112
|
+
* the authority on what this account actually serves.
|
|
113
|
+
*/
|
|
108
114
|
private readonly fastVariants;
|
|
109
115
|
/** Ids the user added by hand, cached so the sync catalog can name them. */
|
|
110
116
|
private userAddedIds;
|
|
111
117
|
/** Tools already reported as flattened, so each is stated once. */
|
|
112
118
|
private readonly flattenedTools;
|
|
113
119
|
constructor(options: KimiAdapterOptions);
|
|
120
|
+
/**
|
|
121
|
+
* Record the fast variants the curated catalog already names as aliases.
|
|
122
|
+
*
|
|
123
|
+
* The alias is the recognition: `kimi-for-coding-highspeed` is stated as an accepted
|
|
124
|
+
* id of `kimi-for-coding`, so the route can offer the quick-mode button without
|
|
125
|
+
* waiting for a live list that may never name it. A row a live catalog already paired
|
|
126
|
+
* keeps that pairing, so this only fills the gaps.
|
|
127
|
+
*/
|
|
128
|
+
private seedCuratedFastVariants;
|
|
129
|
+
/** The fast pair one picker id belongs to, from either side. */
|
|
130
|
+
fastPairOf(id: string): {
|
|
131
|
+
baseId: string;
|
|
132
|
+
wireId: string;
|
|
133
|
+
} | undefined;
|
|
114
134
|
/**
|
|
115
135
|
* Tool schemas in the shape Moonshot accepts: no `$ref`, and under its size
|
|
116
136
|
* ceiling. A declaration too large to send keeps its arguments, and that is
|
|
@@ -122,7 +142,7 @@ export declare class KimiAdapter extends LlmAdapter {
|
|
|
122
142
|
listModels(_provider: string): Promise<readonly LlmModelInfo[]>;
|
|
123
143
|
/** The image-generation model id, when discovery reported one. */
|
|
124
144
|
imageModelId(): string | undefined;
|
|
125
|
-
/** The fast/lightspeed variant wire id for a
|
|
145
|
+
/** The fast/lightspeed variant wire id for a picker row. */
|
|
126
146
|
fastVariant(baseId: string): string | undefined;
|
|
127
147
|
/** The ids the picker must currently omit. */
|
|
128
148
|
private hidden;
|
package/lib/providers/kimi.js
CHANGED
|
@@ -15,7 +15,7 @@ import { streamProviderResponses, accountPoolHooks } from './responses-stream.js
|
|
|
15
15
|
import { fallbackEntry, findEntry, resolveCatalog } from './catalog.js';
|
|
16
16
|
import { streamResponses, toResponsesInput, toResponsesTools } from '../translate/responses.js';
|
|
17
17
|
import { prepareMoonshotTool } from '../translate/moonshot-schema.js';
|
|
18
|
-
import { isImageModel, isFastVariant, baseModelOf } from './grok.js';
|
|
18
|
+
import { isImageModel, isFastVariant, baseModelOf, FastVariantIndex } from './grok.js';
|
|
19
19
|
/** Model ids that are clearly not chat models. */
|
|
20
20
|
const NON_CHAT_ID = /(?:^|[-_/])(?:image|video|imagine|embed|embedding|whisper|tts|vision-only)/i;
|
|
21
21
|
/**
|
|
@@ -134,8 +134,14 @@ export class KimiAdapter extends LlmAdapter {
|
|
|
134
134
|
discovered;
|
|
135
135
|
/** Image-generation model id, when discovery reported one. */
|
|
136
136
|
imageModel;
|
|
137
|
-
/**
|
|
138
|
-
|
|
137
|
+
/**
|
|
138
|
+
* Fast-variant wire id per picker row, for the composer's quick-mode button.
|
|
139
|
+
*
|
|
140
|
+
* Seeded from the curated aliases — `kimi-for-coding-highspeed` is one — so the button
|
|
141
|
+
* exists before any discovery run, and then updated from the live catalog, which is
|
|
142
|
+
* the authority on what this account actually serves.
|
|
143
|
+
*/
|
|
144
|
+
fastVariants = new FastVariantIndex();
|
|
139
145
|
/** Ids the user added by hand, cached so the sync catalog can name them. */
|
|
140
146
|
userAddedIds = [];
|
|
141
147
|
/** Tools already reported as flattened, so each is stated once. */
|
|
@@ -143,6 +149,28 @@ export class KimiAdapter extends LlmAdapter {
|
|
|
143
149
|
constructor(options) {
|
|
144
150
|
super();
|
|
145
151
|
this.options = options;
|
|
152
|
+
this.seedCuratedFastVariants();
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Record the fast variants the curated catalog already names as aliases.
|
|
156
|
+
*
|
|
157
|
+
* The alias is the recognition: `kimi-for-coding-highspeed` is stated as an accepted
|
|
158
|
+
* id of `kimi-for-coding`, so the route can offer the quick-mode button without
|
|
159
|
+
* waiting for a live list that may never name it. A row a live catalog already paired
|
|
160
|
+
* keeps that pairing, so this only fills the gaps.
|
|
161
|
+
*/
|
|
162
|
+
seedCuratedFastVariants() {
|
|
163
|
+
for (const entry of KIMI_MODELS) {
|
|
164
|
+
for (const alias of entry.aliases ?? []) {
|
|
165
|
+
// Every alias of one row maps back to that row, so a variant whose own prefix
|
|
166
|
+
// names another alias (`kimi-k2.7-code-highspeed`) still pairs with the row.
|
|
167
|
+
this.fastVariants.note(alias, (base) => this.entryFor(base)?.id ?? base);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/** The fast pair one picker id belongs to, from either side. */
|
|
172
|
+
fastPairOf(id) {
|
|
173
|
+
return this.fastVariants.pairOf(id);
|
|
146
174
|
}
|
|
147
175
|
/**
|
|
148
176
|
* Tool schemas in the shape Moonshot accepts: no `$ref`, and under its size
|
|
@@ -178,23 +206,32 @@ export class KimiAdapter extends LlmAdapter {
|
|
|
178
206
|
return [];
|
|
179
207
|
await this.syncUserModels();
|
|
180
208
|
const hidden = await this.hidden();
|
|
181
|
-
//
|
|
209
|
+
// The host validates a GUI selection against the exact ids `listModels` returns
|
|
210
|
+
// and refuses an unknown one with `session/model-unavailable`, and its picker
|
|
211
|
+
// lists every returned id as its own row. So a fast variant is published under
|
|
212
|
+
// its base id: selecting it names the variant the request must send, and the
|
|
213
|
+
// base's own id is withheld so the variant does not appear twice.
|
|
182
214
|
const imageless = this.catalog().filter((entry) => !isImageModel(entry.id));
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
id
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
215
|
+
const listed = resolveCatalog(imageless, [], hidden).entries.map((entry) => {
|
|
216
|
+
const fast = this.fastVariants.variantOf(entry.id);
|
|
217
|
+
const id = fast ?? entry.id;
|
|
218
|
+
return {
|
|
219
|
+
provider: KIMI_PROVIDER_ID,
|
|
220
|
+
id,
|
|
221
|
+
name: entry.name,
|
|
222
|
+
...entry.description === undefined ? {} : { description: entry.description },
|
|
223
|
+
...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
|
|
224
|
+
};
|
|
225
|
+
});
|
|
226
|
+
return listed;
|
|
190
227
|
}
|
|
191
228
|
/** The image-generation model id, when discovery reported one. */
|
|
192
229
|
imageModelId() {
|
|
193
230
|
return this.imageModel;
|
|
194
231
|
}
|
|
195
|
-
/** The fast/lightspeed variant wire id for a
|
|
232
|
+
/** The fast/lightspeed variant wire id for a picker row. */
|
|
196
233
|
fastVariant(baseId) {
|
|
197
|
-
return this.fastVariants.
|
|
234
|
+
return this.fastVariants.variantOf(baseId);
|
|
198
235
|
}
|
|
199
236
|
/** The ids the picker must currently omit. */
|
|
200
237
|
async hidden() {
|
|
@@ -228,10 +265,16 @@ export class KimiAdapter extends LlmAdapter {
|
|
|
228
265
|
};
|
|
229
266
|
}
|
|
230
267
|
const reasoning = reasoningInfo(entry);
|
|
268
|
+
// A fast variant is a wire id of its own — the button switches to it and back, so the
|
|
269
|
+
// selection must keep that id — while an ordinary alias is just another spelling of
|
|
270
|
+
// the row and resolves onto it. The fast selection names itself "Fast" so the picker
|
|
271
|
+
// trigger reads the mode, not the base model it replaces.
|
|
272
|
+
const pair = this.fastVariants.pairOf(model);
|
|
273
|
+
const fast = pair !== undefined && pair.wireId === model;
|
|
231
274
|
return {
|
|
232
275
|
provider: KIMI_PROVIDER_ID,
|
|
233
|
-
id: entry.id,
|
|
234
|
-
name: entry.name,
|
|
276
|
+
id: fast ? model : entry.id,
|
|
277
|
+
name: fast ? `${entry.name} Fast` : entry.name,
|
|
235
278
|
...entry.description === undefined ? {} : { description: entry.description },
|
|
236
279
|
...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
|
|
237
280
|
context: { contextWindow: entry.contextWindow },
|
|
@@ -436,17 +479,25 @@ export class KimiAdapter extends LlmAdapter {
|
|
|
436
479
|
.filter((id) => typeof id === 'string' && id.length > 0);
|
|
437
480
|
// Image models are never picker rows: they are agent-called, always on.
|
|
438
481
|
this.imageModel = allIds.find((id) => isImageModel(id));
|
|
439
|
-
// Fast/lightspeed variants ride with their base
|
|
440
|
-
// visibility switch and are reached by
|
|
482
|
+
// Fast/lightspeed variants ride with their base row: they share the row's
|
|
483
|
+
// visibility switch and are reached by the composer's quick-mode button, not a
|
|
484
|
+
// separate row. The live list is the authority on what this account serves, so
|
|
485
|
+
// it is recorded first, and each variant pairs with the longest listed prefix
|
|
486
|
+
// of its own name — a provider that names its variants after the base model
|
|
487
|
+
// pairs them with no curated map at all.
|
|
441
488
|
this.fastVariants.clear();
|
|
442
489
|
for (const id of allIds) {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
490
|
+
this.fastVariants.noteListed(id);
|
|
491
|
+
}
|
|
492
|
+
for (const id of allIds) {
|
|
493
|
+
const base = this.fastVariants.pair(id);
|
|
494
|
+
this.fastVariants.note(id, () => base ?? this.entryFor(baseModelOf(id))?.id ?? baseModelOf(id));
|
|
448
495
|
}
|
|
449
|
-
|
|
496
|
+
this.seedCuratedFastVariants();
|
|
497
|
+
const ids = allIds
|
|
498
|
+
.filter((id) => !NON_CHAT_ID.test(id))
|
|
499
|
+
.map((id) => (isFastVariant(id) ? this.fastVariants.pair(id) ?? baseModelOf(id) : id))
|
|
500
|
+
.filter((id, index, list) => list.indexOf(id) === index);
|
|
450
501
|
if (ids.length === 0) {
|
|
451
502
|
this.options.onWarn?.('Kimi model discovery returned an empty catalog; using the built-in catalog');
|
|
452
503
|
return undefined;
|
|
@@ -25,7 +25,7 @@ import { parseSse } from './sse.js';
|
|
|
25
25
|
export function antigravityReasoning(model) {
|
|
26
26
|
const ids = model.startsWith('claude-') ? ['high']
|
|
27
27
|
: model.startsWith('gpt-oss-') ? ['medium']
|
|
28
|
-
: model.startsWith('gemini-3.1-pro') || model === 'gemini-pro-agent' ? ['low', 'high']
|
|
28
|
+
: model.startsWith('gemini-3.1-pro') || model === 'gemini-pro' || model === 'gemini-pro-agent' ? ['low', 'high']
|
|
29
29
|
: /^gemini-(?:2\.5|3)/.test(model) ? ['low', 'medium', 'high'] : [];
|
|
30
30
|
const fixed = /^gemini-.*-(low|medium|high)$/.exec(model)?.[1];
|
|
31
31
|
const efforts = fixed !== undefined && ids.includes(fixed) ? [fixed] : ids;
|
|
@@ -59,10 +59,10 @@ export function antigravityThinking(model, effort, maxTokens) {
|
|
|
59
59
|
budget = 1024;
|
|
60
60
|
else if (model.startsWith('gpt-oss-'))
|
|
61
61
|
budget = 8192;
|
|
62
|
-
else if (model.startsWith('gemini-3.1-pro') || model === 'gemini-pro-agent') {
|
|
62
|
+
else if (model.startsWith('gemini-3.1-pro') || model === 'gemini-pro' || model === 'gemini-pro-agent') {
|
|
63
63
|
budget = effort === 'high' ? 10001 : 1001;
|
|
64
64
|
}
|
|
65
|
-
else if (model.startsWith('gemini-3.5-flash') || model === 'gemini-3-flash-agent') {
|
|
65
|
+
else if (model.startsWith('gemini-3.5-flash') || model === 'gemini-3-flash' || model === 'gemini-3-flash-agent') {
|
|
66
66
|
budget = effort === 'high' ? 10000 : effort === 'medium' ? 4000 : 1000;
|
|
67
67
|
}
|
|
68
68
|
else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-subscription-oauth",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.16",
|
|
4
4
|
"description": "Use subscription accounts as DeepSeek Harness LLM providers — Kimi Code (OAuth device flow), Grok / X Premium (OIDC + PKCE), Google Antigravity (Google OAuth + Cloud Code Assist) and GLM / BigModel (ZCode's browser sign-in) — with per-model visibility, drag-to-reorder Auto fallback and plan quotas from the web Settings page",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "EricFL1998",
|