dsh-plugin-subscription-oauth 0.8.13 → 0.8.15

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.
@@ -15,6 +15,9 @@ 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, FastVariantIndex } from './grok.js';
19
+ /** Model ids that are clearly not chat models. */
20
+ const NON_CHAT_ID = /(?:^|[-_/])(?:image|video|imagine|embed|embedding|whisper|tts|vision-only)/i;
18
21
  /**
19
22
  * Coerce one decoded credential entry into a Kimi session.
20
23
  * @param value - decoded JSON value for one account.
@@ -129,6 +132,16 @@ export class KimiAdapter extends LlmAdapter {
129
132
  options;
130
133
  /** Live catalog ids seen this session, used to accept renamed models. */
131
134
  discovered;
135
+ /** Image-generation model id, when discovery reported one. */
136
+ imageModel;
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();
132
145
  /** Ids the user added by hand, cached so the sync catalog can name them. */
133
146
  userAddedIds = [];
134
147
  /** Tools already reported as flattened, so each is stated once. */
@@ -136,6 +149,28 @@ export class KimiAdapter extends LlmAdapter {
136
149
  constructor(options) {
137
150
  super();
138
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);
139
174
  }
140
175
  /**
141
176
  * Tool schemas in the shape Moonshot accepts: no `$ref`, and under its size
@@ -171,13 +206,33 @@ export class KimiAdapter extends LlmAdapter {
171
206
  return [];
172
207
  await this.syncUserModels();
173
208
  const hidden = await this.hidden();
174
- return resolveCatalog(this.catalog(), [], hidden).entries.map((entry) => ({
175
- provider: KIMI_PROVIDER_ID,
176
- id: entry.id,
177
- name: entry.name,
178
- ...entry.description === undefined ? {} : { description: entry.description },
179
- ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
180
- }));
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.
215
+ 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;
228
+ }
229
+ /** The image-generation model id, when discovery reported one. */
230
+ imageModelId() {
231
+ return this.imageModel;
232
+ }
233
+ /** The fast/lightspeed variant wire id for a picker row. */
234
+ fastVariant(baseId) {
235
+ return this.fastVariants.variantOf(baseId);
181
236
  }
182
237
  /** The ids the picker must currently omit. */
183
238
  async hidden() {
@@ -211,9 +266,13 @@ export class KimiAdapter extends LlmAdapter {
211
266
  };
212
267
  }
213
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);
214
273
  return {
215
274
  provider: KIMI_PROVIDER_ID,
216
- id: entry.id,
275
+ id: pair !== undefined && pair.wireId === model ? model : entry.id,
217
276
  name: entry.name,
218
277
  ...entry.description === undefined ? {} : { description: entry.description },
219
278
  ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
@@ -414,9 +473,30 @@ export class KimiAdapter extends LlmAdapter {
414
473
  return undefined;
415
474
  }
416
475
  const payload = await response.json();
417
- const ids = (payload.data ?? [])
476
+ const allIds = (payload.data ?? [])
418
477
  .map((entry) => entry.id)
419
478
  .filter((id) => typeof id === 'string' && id.length > 0);
479
+ // Image models are never picker rows: they are agent-called, always on.
480
+ this.imageModel = allIds.find((id) => isImageModel(id));
481
+ // Fast/lightspeed variants ride with their base row: they share the row's
482
+ // visibility switch and are reached by the composer's quick-mode button, not a
483
+ // separate row. The live list is the authority on what this account serves, so
484
+ // it is recorded first, and each variant pairs with the longest listed prefix
485
+ // of its own name — a provider that names its variants after the base model
486
+ // pairs them with no curated map at all.
487
+ this.fastVariants.clear();
488
+ for (const id of allIds) {
489
+ this.fastVariants.noteListed(id);
490
+ }
491
+ for (const id of allIds) {
492
+ const base = this.fastVariants.pair(id);
493
+ this.fastVariants.note(id, () => base ?? this.entryFor(baseModelOf(id))?.id ?? baseModelOf(id));
494
+ }
495
+ this.seedCuratedFastVariants();
496
+ const ids = allIds
497
+ .filter((id) => !NON_CHAT_ID.test(id))
498
+ .map((id) => (isFastVariant(id) ? this.fastVariants.pair(id) ?? baseModelOf(id) : id))
499
+ .filter((id, index, list) => list.indexOf(id) === index);
420
500
  if (ids.length === 0) {
421
501
  this.options.onWarn?.('Kimi model discovery returned an empty catalog; using the built-in catalog');
422
502
  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.13",
3
+ "version": "0.8.15",
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",