dsh-plugin-subscription-oauth 0.8.15 → 0.8.17

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.
@@ -57,6 +57,10 @@ const EFFORT_LABELS = {
57
57
  low: { name: 'Low', description: 'Short chain of thought' },
58
58
  medium: { name: 'Medium', description: 'Balanced thinking budget' },
59
59
  high: { name: 'High', description: 'Deep chain of thought' },
60
+ // Not a thinking budget: this rung is the model's fast variant, which the composer's
61
+ // quick-mode button selects. It rides the effort channel so the row keeps its own id —
62
+ // a swapped model id would leave the picker with no way back to the standard model.
63
+ fast: { name: 'Fast', description: 'Lightspeed variant of this model' },
60
64
  };
61
65
  /**
62
66
  * Curated catalog entries.
@@ -123,13 +127,19 @@ function effortInfo(effort) {
123
127
  const label = EFFORT_LABELS[effort] ?? { name: effort, description: '' };
124
128
  return { id: ReasoningEffortId(effort), name: label.name, description: label.description };
125
129
  }
126
- /** The reasoning block for a catalog entry, or undefined when it supports none. */
127
- function reasoningInfo(entry) {
130
+ /**
131
+ * The reasoning block for a catalog entry, or undefined when it supports none.
132
+ *
133
+ * @param entry - the catalog row.
134
+ * @param fast - add the `fast` rung when this row has a fast variant.
135
+ */
136
+ function reasoningInfo(entry, fast = false) {
128
137
  const efforts = entry.reasoningEfforts;
129
- if (efforts === undefined || efforts.length === 0)
138
+ const ids = fast ? [...efforts ?? [], 'fast'] : efforts;
139
+ if (ids === undefined || ids.length === 0)
130
140
  return undefined;
131
141
  return {
132
- efforts: efforts.map(effortInfo),
142
+ efforts: ids.map(effortInfo),
133
143
  ...entry.defaultEffort === undefined ? {} : { defaultEffort: ReasoningEffortId(entry.defaultEffort) },
134
144
  };
135
145
  }
@@ -446,25 +456,18 @@ export class GrokAdapter extends LlmAdapter {
446
456
  return [];
447
457
  await this.syncUserModels();
448
458
  const hidden = await this.hidden();
449
- // A fast variant is not a picker row, but the host validates a GUI selection
450
- // against the exact list `listModels` returns, so the variant must appear there
451
- // or selecting it is refused with `session/model-unavailable`. The picker's
452
- // menu collapses entries that share one `group` value into a single choice,
453
- // so the variant rides with its base id as the group: the host can name and
454
- // select it, and the picker still shows one row per model.
459
+ // One row per model, always under the model's own id: the host validates every GUI
460
+ // selection against this list, so publishing only the fast variant would leave the
461
+ // picker with no way back to the standard model. Fast mode is the row's `fast`
462
+ // reasoning rung instead (see `stream`).
455
463
  const imageless = this.catalog().filter((entry) => !isImageModel(entry.id));
456
- const listed = resolveCatalog(imageless, [], hidden).entries.flatMap((entry) => {
457
- const fast = this.fastVariants.variantOf(entry.id);
458
- const base = {
459
- provider: GROK_PROVIDER_ID,
460
- id: entry.id,
461
- name: entry.name,
462
- ...entry.description === undefined ? {} : { description: entry.description },
463
- ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
464
- };
465
- return fast === undefined ? [base] : [base, { provider: GROK_PROVIDER_ID, id: fast, name: entry.name, group: entry.id, description: 'Fast variant', ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities } }];
466
- });
467
- return listed;
464
+ return resolveCatalog(imageless, [], hidden).entries.map((entry) => ({
465
+ provider: GROK_PROVIDER_ID,
466
+ id: entry.id,
467
+ name: entry.name,
468
+ ...entry.description === undefined ? {} : { description: entry.description },
469
+ ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
470
+ }));
468
471
  }
469
472
  async hidden() {
470
473
  if (this.options.hiddenModels === undefined)
@@ -497,7 +500,9 @@ export class GrokAdapter extends LlmAdapter {
497
500
  ...reasoning === undefined ? {} : { reasoning },
498
501
  };
499
502
  }
500
- const reasoning = reasoningInfo(entry);
503
+ // A row with a fast variant offers the `fast` rung; the picker shows the row under
504
+ // its own name and the mode as the effort, which is what the trigger already reads.
505
+ const reasoning = reasoningInfo(entry, this.fastVariants.variantOf(entry.id) !== undefined);
501
506
  return {
502
507
  provider: GROK_PROVIDER_ID,
503
508
  id: model,
@@ -511,8 +516,17 @@ export class GrokAdapter extends LlmAdapter {
511
516
  }
512
517
  stream(options) {
513
518
  // Resolve @Nk context suffixes to the largest variant the endpoint offers.
514
- const model = this.resolveModelId(options.model);
515
- return streamProviderResponses({ ...options, model }, {
519
+ const base = this.resolveModelId(options.model);
520
+ // Fast mode rides the reasoning channel: `fast` is a rung of the row, not a model id
521
+ // of its own, so the row the picker selected stays dispatchable and the user can
522
+ // always select the standard model again. Only the wire id changes.
523
+ const fast = String(options.reasoningEffort ?? '') === 'fast';
524
+ const model = fast ? this.fastVariants.variantOf(base) ?? base : base;
525
+ const call = { ...options, model };
526
+ // xAI has no `fast` effort; the variant already carries the behaviour.
527
+ if (fast)
528
+ delete call.reasoningEffort;
529
+ return streamProviderResponses(call, {
516
530
  label: 'xAI API',
517
531
  tokens: this.options.tokens,
518
532
  request: (call, model, accessToken, signal) => this.request(call, model, accessToken, signal),
@@ -63,6 +63,10 @@ const EFFORT_LABELS = {
63
63
  high: { name: 'High', description: 'Deep chain of thought' },
64
64
  xhigh: { name: 'Max', description: 'Highest thinking budget Kimi accepts' },
65
65
  max: { name: 'Max', description: 'Highest thinking budget Kimi accepts' },
66
+ // Not a thinking budget: this rung is the model's fast variant, which the composer's
67
+ // quick-mode button selects. It rides the effort channel so the row keeps its own id —
68
+ // a swapped model id would leave the picker with no way back to the standard model.
69
+ fast: { name: 'Fast', description: 'Highspeed variant of this model' },
66
70
  };
67
71
  /**
68
72
  * Kimi Code's live coding catalog.
@@ -116,14 +120,20 @@ function effortInfo(effort) {
116
120
  const label = EFFORT_LABELS[effort] ?? { name: effort, description: '' };
117
121
  return { id: ReasoningEffortId(effort), name: label.name, description: label.description };
118
122
  }
119
- /** The reasoning block for a catalog entry, or undefined when it supports none. */
120
- function reasoningInfo(entry) {
123
+ /**
124
+ * The reasoning block for a catalog entry, or undefined when it supports none.
125
+ *
126
+ * @param entry - the catalog row.
127
+ * @param fast - add the `fast` rung when this row has a fast variant.
128
+ */
129
+ function reasoningInfo(entry, fast = false) {
121
130
  const efforts = entry.reasoningEfforts;
122
- if (efforts === undefined || efforts.length === 0)
131
+ const ids = fast ? [...efforts ?? [], 'fast'] : efforts;
132
+ if (ids === undefined || ids.length === 0)
123
133
  return undefined;
124
- const defaultEffort = entry.defaultEffort ?? efforts[efforts.length - 1];
134
+ const defaultEffort = entry.defaultEffort ?? ids[ids.length - 1];
125
135
  return {
126
- efforts: efforts.map(effortInfo),
136
+ efforts: ids.map(effortInfo),
127
137
  ...defaultEffort === undefined ? {} : { defaultEffort: ReasoningEffortId(defaultEffort) },
128
138
  };
129
139
  }
@@ -206,25 +216,18 @@ export class KimiAdapter extends LlmAdapter {
206
216
  return [];
207
217
  await this.syncUserModels();
208
218
  const hidden = await this.hidden();
209
- // A fast variant is not a picker row, but the host validates a GUI selection
210
- // against the exact list `listModels` returns, so the variant must appear there
211
- // or selecting it is refused with `session/model-unavailable`. The picker's
212
- // menu collapses entries that share one `group` value into a single choice,
213
- // so the variant rides with its base id as the group: the host can name and
214
- // select it, and the picker still shows one row per model.
219
+ // One row per model, always under the model's own id: the host validates every GUI
220
+ // selection against this list, so publishing only the fast variant would leave the
221
+ // picker with no way back to the standard model. Fast mode is the row's `fast`
222
+ // reasoning rung instead (see `stream`).
215
223
  const imageless = this.catalog().filter((entry) => !isImageModel(entry.id));
216
- const listed = resolveCatalog(imageless, [], hidden).entries.flatMap((entry) => {
217
- const fast = this.fastVariants.variantOf(entry.id);
218
- const base = {
219
- provider: KIMI_PROVIDER_ID,
220
- id: entry.id,
221
- name: entry.name,
222
- ...entry.description === undefined ? {} : { description: entry.description },
223
- ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
224
- };
225
- return fast === undefined ? [base] : [base, { provider: KIMI_PROVIDER_ID, id: fast, name: entry.name, group: entry.id, description: 'Fast variant', ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities } }];
226
- });
227
- return listed;
224
+ return resolveCatalog(imageless, [], hidden).entries.map((entry) => ({
225
+ provider: KIMI_PROVIDER_ID,
226
+ id: entry.id,
227
+ name: entry.name,
228
+ ...entry.description === undefined ? {} : { description: entry.description },
229
+ ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
230
+ }));
228
231
  }
229
232
  /** The image-generation model id, when discovery reported one. */
230
233
  imageModelId() {
@@ -265,14 +268,14 @@ export class KimiAdapter extends LlmAdapter {
265
268
  ...reasoning === undefined ? {} : { reasoning },
266
269
  };
267
270
  }
268
- const reasoning = reasoningInfo(entry);
269
- // A fast variant is a wire id of its own — the button switches to it and back, so the
270
- // selection must keep that id — while an ordinary alias is just another spelling of
271
- // the row and resolves onto it.
272
- const pair = this.fastVariants.pairOf(model);
271
+ // A row with a fast variant offers the `fast` rung; the picker shows the row under
272
+ // its own name and the mode as the effort, which is what the trigger already reads.
273
+ const reasoning = reasoningInfo(entry, this.fastVariants.variantOf(entry.id) !== undefined);
274
+ // An alias is just another spelling of the row, so it resolves onto the row's own id:
275
+ // that is what keeps a selection dispatchable and the picker able to show it.
273
276
  return {
274
277
  provider: KIMI_PROVIDER_ID,
275
- id: pair !== undefined && pair.wireId === model ? model : entry.id,
278
+ id: entry.id,
276
279
  name: entry.name,
277
280
  ...entry.description === undefined ? {} : { description: entry.description },
278
281
  ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
@@ -282,7 +285,16 @@ export class KimiAdapter extends LlmAdapter {
282
285
  };
283
286
  }
284
287
  stream(options) {
285
- return streamProviderResponses(options, {
288
+ // Fast mode rides the reasoning channel: `fast` is a rung of the row, not a model id
289
+ // of its own, so the row the picker selected stays dispatchable and the user can
290
+ // always select the standard model again. Only the wire id changes.
291
+ const fast = String(options.reasoningEffort ?? '') === 'fast';
292
+ const model = fast ? this.fastVariants.variantOf(options.model) ?? options.model : options.model;
293
+ const call = { ...options, model };
294
+ // Kimi has no `fast` effort; the variant already carries the behaviour.
295
+ if (fast)
296
+ delete call.reasoningEffort;
297
+ return streamProviderResponses(call, {
286
298
  label: 'Kimi API',
287
299
  tokens: this.options.tokens,
288
300
  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.15",
3
+ "version": "0.8.17",
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",