dsh-plugin-subscription-oauth 0.8.16 → 0.8.18

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/protocol.d.ts CHANGED
@@ -364,6 +364,14 @@ export interface ModelVariants {
364
364
  * already the fast variant, which is not itself a listed row.
365
365
  */
366
366
  fastBase?: string;
367
+ /**
368
+ * The reasoning rung that selects the fast variant.
369
+ *
370
+ * Each provider names its own variant (xAI `lightspeed`, Kimi `highspeed`), so the
371
+ * rung is the provider's word — the picker reads it, and the stream maps it back to
372
+ * the variant's wire id. Defaults to `fast`.
373
+ */
374
+ fastRung?: string;
367
375
  /** Image-generation model wire id, when the provider reported one. */
368
376
  image?: string;
369
377
  }
@@ -51,12 +51,19 @@ export const GROK_DEFAULT_MAX_TOKENS = 32_000;
51
51
  export const GROK_PREEMPT_MS = 2 * 60 * 1000;
52
52
  /** Hosts an authorization server endpoint may live on. */
53
53
  const TRUSTED_AUTH_HOSTS = new Set(['auth.x.ai', 'accounts.x.ai']);
54
+ /** The rung id the composer's quick-mode button selects. */
55
+ const FAST_RUNG = 'lightspeed';
54
56
  /** Display metadata for the reasoning ladder xAI documents. */
55
57
  const EFFORT_LABELS = {
56
58
  none: { name: 'Off', description: 'Answer without spending thinking tokens' },
57
59
  low: { name: 'Low', description: 'Short chain of thought' },
58
60
  medium: { name: 'Medium', description: 'Balanced thinking budget' },
59
61
  high: { name: 'High', description: 'Deep chain of thought' },
62
+ // Not a thinking budget: this rung is the model's fast/lightspeed variant, which the
63
+ // composer's quick-mode button selects. It rides the effort channel so the row keeps
64
+ // its own id — a swapped model id would leave the picker with no way back. xAI's own
65
+ // word for it is "lightspeed", which is what the rung is named here.
66
+ [FAST_RUNG]: { name: 'Lightspeed', description: 'xAI lightspeed variant of this model' },
60
67
  };
61
68
  /**
62
69
  * Curated catalog entries.
@@ -123,13 +130,19 @@ function effortInfo(effort) {
123
130
  const label = EFFORT_LABELS[effort] ?? { name: effort, description: '' };
124
131
  return { id: ReasoningEffortId(effort), name: label.name, description: label.description };
125
132
  }
126
- /** The reasoning block for a catalog entry, or undefined when it supports none. */
127
- function reasoningInfo(entry) {
133
+ /**
134
+ * The reasoning block for a catalog entry, or undefined when it supports none.
135
+ *
136
+ * @param entry - the catalog row.
137
+ * @param fast - add the `fast` rung when this row has a fast variant.
138
+ */
139
+ function reasoningInfo(entry, fast = false) {
128
140
  const efforts = entry.reasoningEfforts;
129
- if (efforts === undefined || efforts.length === 0)
141
+ const ids = fast ? [...efforts ?? [], FAST_RUNG] : efforts;
142
+ if (ids === undefined || ids.length === 0)
130
143
  return undefined;
131
144
  return {
132
- efforts: efforts.map(effortInfo),
145
+ efforts: ids.map(effortInfo),
133
146
  ...entry.defaultEffort === undefined ? {} : { defaultEffort: ReasoningEffortId(entry.defaultEffort) },
134
147
  };
135
148
  }
@@ -446,24 +459,18 @@ export class GrokAdapter extends LlmAdapter {
446
459
  return [];
447
460
  await this.syncUserModels();
448
461
  const hidden = await this.hidden();
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.
462
+ // One row per model, always under the model's own id: the host validates every GUI
463
+ // selection against this list, so publishing only the fast variant would leave the
464
+ // picker with no way back to the standard model. Fast mode is the row's `fast`
465
+ // reasoning rung instead (see `stream`).
454
466
  const imageless = this.catalog().filter((entry) => !isImageModel(entry.id));
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;
467
+ return resolveCatalog(imageless, [], hidden).entries.map((entry) => ({
468
+ provider: GROK_PROVIDER_ID,
469
+ id: entry.id,
470
+ name: entry.name,
471
+ ...entry.description === undefined ? {} : { description: entry.description },
472
+ ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
473
+ }));
467
474
  }
468
475
  async hidden() {
469
476
  if (this.options.hiddenModels === undefined)
@@ -496,14 +503,13 @@ export class GrokAdapter extends LlmAdapter {
496
503
  ...reasoning === undefined ? {} : { reasoning },
497
504
  };
498
505
  }
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;
506
+ // A row with a fast variant offers the `fast` rung; the picker shows the row under
507
+ // its own name and the mode as the effort, which is what the trigger already reads.
508
+ const reasoning = reasoningInfo(entry, this.fastVariants.variantOf(entry.id) !== undefined);
503
509
  return {
504
510
  provider: GROK_PROVIDER_ID,
505
511
  id: model,
506
- name: fast ? `${entry.name} Fast` : entry.name,
512
+ name: entry.name,
507
513
  ...entry.description === undefined ? {} : { description: entry.description },
508
514
  ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
509
515
  context: { contextWindow: entry.contextWindow },
@@ -513,8 +519,17 @@ export class GrokAdapter extends LlmAdapter {
513
519
  }
514
520
  stream(options) {
515
521
  // Resolve @Nk context suffixes to the largest variant the endpoint offers.
516
- const model = this.resolveModelId(options.model);
517
- return streamProviderResponses({ ...options, model }, {
522
+ const base = this.resolveModelId(options.model);
523
+ // Fast mode rides the reasoning channel: `fast` is a rung of the row, not a model id
524
+ // of its own, so the row the picker selected stays dispatchable and the user can
525
+ // always select the standard model again. Only the wire id changes.
526
+ const fast = String(options.reasoningEffort ?? '') === FAST_RUNG;
527
+ const model = fast ? this.fastVariants.variantOf(base) ?? base : base;
528
+ const call = { ...options, model };
529
+ // xAI has no `fast` effort; the variant already carries the behaviour.
530
+ if (fast)
531
+ delete call.reasoningEffort;
532
+ return streamProviderResponses(call, {
518
533
  label: 'xAI API',
519
534
  tokens: this.options.tokens,
520
535
  request: (call, model, accessToken, signal) => this.request(call, model, accessToken, signal),
@@ -988,7 +1003,7 @@ export function createGrokProvider(options) {
988
1003
  const pair = adapter.fastPairOf(id);
989
1004
  const image = adapter.imageModelId();
990
1005
  return {
991
- ...pair === undefined ? {} : { fast: pair.wireId, fastBase: pair.baseId },
1006
+ ...pair === undefined ? {} : { fast: pair.wireId, fastBase: pair.baseId, fastRung: 'lightspeed' },
992
1007
  ...image === undefined ? {} : { image },
993
1008
  };
994
1009
  },
@@ -154,7 +154,7 @@ export function createKimiProvider(options) {
154
154
  const pair = adapter.fastPairOf(id);
155
155
  const image = adapter.imageModelId();
156
156
  return {
157
- ...pair === undefined ? {} : { fast: pair.wireId, fastBase: pair.baseId },
157
+ ...pair === undefined ? {} : { fast: pair.wireId, fastBase: pair.baseId, fastRung: 'highspeed' },
158
158
  ...image === undefined ? {} : { image },
159
159
  };
160
160
  },
@@ -55,6 +55,8 @@ const EFFORT_WIRE_MAP = {
55
55
  xhigh: 'max',
56
56
  max: 'max',
57
57
  };
58
+ /** The rung id the composer's quick-mode button selects. */
59
+ const FAST_RUNG = 'highspeed';
58
60
  /** Display metadata for the reasoning ladder shared by every live coding model. */
59
61
  const EFFORT_LABELS = {
60
62
  none: { name: 'Off', description: 'Answer without spending thinking tokens' },
@@ -63,6 +65,11 @@ const EFFORT_LABELS = {
63
65
  high: { name: 'High', description: 'Deep chain of thought' },
64
66
  xhigh: { name: 'Max', description: 'Highest thinking budget Kimi accepts' },
65
67
  max: { name: 'Max', description: 'Highest thinking budget Kimi accepts' },
68
+ // Not a thinking budget: this rung is the model's fast variant, which the composer's
69
+ // quick-mode button selects. It rides the effort channel so the row keeps its own id —
70
+ // a swapped model id would leave the picker with no way back. Kimi's own word for it
71
+ // is "highspeed", which is what the rung is named here.
72
+ [FAST_RUNG]: { name: 'Highspeed', description: 'Kimi highspeed variant of this model' },
66
73
  };
67
74
  /**
68
75
  * Kimi Code's live coding catalog.
@@ -116,14 +123,20 @@ function effortInfo(effort) {
116
123
  const label = EFFORT_LABELS[effort] ?? { name: effort, description: '' };
117
124
  return { id: ReasoningEffortId(effort), name: label.name, description: label.description };
118
125
  }
119
- /** The reasoning block for a catalog entry, or undefined when it supports none. */
120
- function reasoningInfo(entry) {
126
+ /**
127
+ * The reasoning block for a catalog entry, or undefined when it supports none.
128
+ *
129
+ * @param entry - the catalog row.
130
+ * @param fast - add the `fast` rung when this row has a fast variant.
131
+ */
132
+ function reasoningInfo(entry, fast = false) {
121
133
  const efforts = entry.reasoningEfforts;
122
- if (efforts === undefined || efforts.length === 0)
134
+ const ids = fast ? [...efforts ?? [], FAST_RUNG] : efforts;
135
+ if (ids === undefined || ids.length === 0)
123
136
  return undefined;
124
- const defaultEffort = entry.defaultEffort ?? efforts[efforts.length - 1];
137
+ const defaultEffort = entry.defaultEffort ?? ids[ids.length - 1];
125
138
  return {
126
- efforts: efforts.map(effortInfo),
139
+ efforts: ids.map(effortInfo),
127
140
  ...defaultEffort === undefined ? {} : { defaultEffort: ReasoningEffortId(defaultEffort) },
128
141
  };
129
142
  }
@@ -206,24 +219,18 @@ export class KimiAdapter extends LlmAdapter {
206
219
  return [];
207
220
  await this.syncUserModels();
208
221
  const hidden = await this.hidden();
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.
222
+ // One row per model, always under the model's own id: the host validates every GUI
223
+ // selection against this list, so publishing only the fast variant would leave the
224
+ // picker with no way back to the standard model. Fast mode is the row's `fast`
225
+ // reasoning rung instead (see `stream`).
214
226
  const imageless = this.catalog().filter((entry) => !isImageModel(entry.id));
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;
227
+ return resolveCatalog(imageless, [], hidden).entries.map((entry) => ({
228
+ provider: KIMI_PROVIDER_ID,
229
+ id: entry.id,
230
+ name: entry.name,
231
+ ...entry.description === undefined ? {} : { description: entry.description },
232
+ ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
233
+ }));
227
234
  }
228
235
  /** The image-generation model id, when discovery reported one. */
229
236
  imageModelId() {
@@ -264,17 +271,15 @@ export class KimiAdapter extends LlmAdapter {
264
271
  ...reasoning === undefined ? {} : { reasoning },
265
272
  };
266
273
  }
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;
274
+ // A row with a fast variant offers the `fast` rung; the picker shows the row under
275
+ // its own name and the mode as the effort, which is what the trigger already reads.
276
+ const reasoning = reasoningInfo(entry, this.fastVariants.variantOf(entry.id) !== undefined);
277
+ // An alias is just another spelling of the row, so it resolves onto the row's own id:
278
+ // that is what keeps a selection dispatchable and the picker able to show it.
274
279
  return {
275
280
  provider: KIMI_PROVIDER_ID,
276
- id: fast ? model : entry.id,
277
- name: fast ? `${entry.name} Fast` : entry.name,
281
+ id: entry.id,
282
+ name: entry.name,
278
283
  ...entry.description === undefined ? {} : { description: entry.description },
279
284
  ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
280
285
  context: { contextWindow: entry.contextWindow },
@@ -283,7 +288,16 @@ export class KimiAdapter extends LlmAdapter {
283
288
  };
284
289
  }
285
290
  stream(options) {
286
- return streamProviderResponses(options, {
291
+ // Fast mode rides the reasoning channel: `fast` is a rung of the row, not a model id
292
+ // of its own, so the row the picker selected stays dispatchable and the user can
293
+ // always select the standard model again. Only the wire id changes.
294
+ const fast = String(options.reasoningEffort ?? '') === FAST_RUNG;
295
+ const model = fast ? this.fastVariants.variantOf(options.model) ?? options.model : options.model;
296
+ const call = { ...options, model };
297
+ // Kimi has no `fast` effort; the variant already carries the behaviour.
298
+ if (fast)
299
+ delete call.reasoningEffort;
300
+ return streamProviderResponses(call, {
287
301
  label: 'Kimi API',
288
302
  tokens: this.options.tokens,
289
303
  request: (call, model, accessToken, signal) => this.request(call, model, accessToken, signal),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-subscription-oauth",
3
- "version": "0.8.16",
3
+ "version": "0.8.18",
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",