dsh-plugin-subscription-oauth 0.8.13 → 0.8.14

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.
@@ -170,5 +170,9 @@ export function createArkProvider(options) {
170
170
  removeModel: (id) => controller.removeModel(id),
171
171
  usage: (force) => controller.usage(force),
172
172
  reload: () => controller.reload(),
173
+ modelVariants: (id) => {
174
+ const image = adapter.imageModelId();
175
+ return image === undefined ? undefined : { image };
176
+ },
173
177
  };
174
178
  }
@@ -100,10 +100,14 @@ export interface ArkAdapterOptions {
100
100
  export declare class ArkAdapter extends LlmAdapter {
101
101
  private readonly options;
102
102
  private live;
103
+ /** Image-generation model id, when discovery reported one. */
104
+ private imageModel;
103
105
  constructor(options: ArkAdapterOptions);
104
106
  providerInfo(provider: string): LlmProviderInfo;
105
107
  providerRetryPolicy(): undefined;
106
108
  listModels(_provider: string): Promise<readonly LlmModelInfo[]>;
109
+ /** The image-generation model id, when discovery reported one. */
110
+ imageModelId(): string | undefined;
107
111
  resolveModel(_provider: string, model: string): Promise<LlmResolvedModelInfo>;
108
112
  stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
109
113
  /** Translate an auth failure into the message a user can act on. */
@@ -23,6 +23,9 @@ import { proxiedFetch } from '../http.js';
23
23
  import { findEntry, resolveCatalog } from './catalog.js';
24
24
  import { streamProviderResponses, accountPoolHooks } from './responses-stream.js';
25
25
  import { toResponsesInput, toResponsesTools } from '../translate/responses.js';
26
+ import { isImageModel } from './grok.js';
27
+ /** Model ids that are clearly not chat models. */
28
+ const NON_CHAT_ID = /(?:^|[-_/])(?:image|video|imagine|embed|embedding|whisper|tts|vision-only)/i;
26
29
  /** Provider route this module serves. */
27
30
  export const ARK_PROVIDER_ID = 'ark';
28
31
  /** Display name for the picker group and the Settings card. */
@@ -113,6 +116,8 @@ function extraEntry(id) {
113
116
  export class ArkAdapter extends LlmAdapter {
114
117
  options;
115
118
  live;
119
+ /** Image-generation model id, when discovery reported one. */
120
+ imageModel;
116
121
  constructor(options) {
117
122
  super();
118
123
  this.options = options;
@@ -129,7 +134,9 @@ export class ArkAdapter extends LlmAdapter {
129
134
  if (await this.options.tokens.session() === undefined)
130
135
  return [];
131
136
  const hidden = await this.hidden();
132
- return resolveCatalog(this.catalog(), [], hidden).entries.map((entry) => ({
137
+ // Image models are never picker rows: they are agent-called, always on.
138
+ const imageless = this.catalog().filter((entry) => !isImageModel(entry.id));
139
+ return resolveCatalog(imageless, [], hidden).entries.map((entry) => ({
133
140
  provider: ARK_PROVIDER_ID,
134
141
  id: entry.id,
135
142
  name: entry.name,
@@ -137,6 +144,10 @@ export class ArkAdapter extends LlmAdapter {
137
144
  ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
138
145
  }));
139
146
  }
147
+ /** The image-generation model id, when discovery reported one. */
148
+ imageModelId() {
149
+ return this.imageModel;
150
+ }
140
151
  async resolveModel(_provider, model) {
141
152
  const entry = findEntry(this.catalog(), model);
142
153
  if (entry === undefined) {
@@ -246,9 +257,12 @@ export class ArkAdapter extends LlmAdapter {
246
257
  return undefined;
247
258
  }
248
259
  const body = await response.json();
249
- const ids = (body.data ?? [])
260
+ const allIds = (body.data ?? [])
250
261
  .map((entry) => (typeof entry?.id === 'string' ? entry.id.trim() : ''))
251
262
  .filter((id) => id !== '');
263
+ // Image models are never picker rows: they are agent-called, always on.
264
+ this.imageModel = allIds.find((id) => isImageModel(id));
265
+ const ids = allIds.filter((id) => !NON_CHAT_ID.test(id));
252
266
  return ids.length === 0 ? undefined : ids;
253
267
  }
254
268
  catch (error) {
@@ -166,5 +166,9 @@ export function createGlmProvider(options) {
166
166
  removeModel: (id) => controller.removeModel(id),
167
167
  usage: (force) => controller.usage(force),
168
168
  reload: () => controller.reload(),
169
+ modelVariants: (id) => {
170
+ const image = adapter.imageModelId();
171
+ return image === undefined ? undefined : { image };
172
+ },
169
173
  };
170
174
  }
@@ -120,6 +120,8 @@ export declare class GlmAdapter extends LlmAdapter {
120
120
  private readonly options;
121
121
  /** Live catalog ids, once discovery succeeded this session. */
122
122
  private live;
123
+ /** Image-generation model id, when discovery reported one. */
124
+ private imageModel;
123
125
  constructor(options: GlmAdapterOptions);
124
126
  providerInfo(provider: string): LlmProviderInfo;
125
127
  providerRetryPolicy(): undefined;
@@ -134,6 +136,8 @@ export declare class GlmAdapter extends LlmAdapter {
134
136
  private shippedCatalog;
135
137
  /** Ids the user published by hand that this route does not already serve. */
136
138
  private addedEntries;
139
+ /** The image-generation model id, when discovery reported one. */
140
+ imageModelId(): string | undefined;
137
141
  /** The ids the picker must currently omit. */
138
142
  private hidden;
139
143
  /**
@@ -15,6 +15,9 @@ import { proxiedFetch } from '../http.js';
15
15
  import { findEntry, resolveCatalog } from './catalog.js';
16
16
  import { streamProviderResponses, accountPoolHooks } from './responses-stream.js';
17
17
  import { toResponsesInput, toResponsesTools } from '../translate/responses.js';
18
+ import { isImageModel } 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
  /** Provider route this module serves. */
19
22
  export const GLM_PROVIDER_ID = 'glm';
20
23
  /** Display name for the picker group and the Settings card. */
@@ -220,6 +223,8 @@ export class GlmAdapter extends LlmAdapter {
220
223
  options;
221
224
  /** Live catalog ids, once discovery succeeded this session. */
222
225
  live;
226
+ /** Image-generation model id, when discovery reported one. */
227
+ imageModel;
223
228
  constructor(options) {
224
229
  super();
225
230
  this.options = options;
@@ -238,7 +243,9 @@ export class GlmAdapter extends LlmAdapter {
238
243
  if (await this.options.tokens.session() === undefined)
239
244
  return [];
240
245
  const hidden = await this.hidden();
241
- return resolveCatalog(this.catalog(), [], hidden).entries.map((entry) => ({
246
+ // Image models are never picker rows: they are agent-called, always on.
247
+ const imageless = this.catalog().filter((entry) => !isImageModel(entry.id));
248
+ return resolveCatalog(imageless, [], hidden).entries.map((entry) => ({
242
249
  provider: GLM_PROVIDER_ID,
243
250
  id: entry.id,
244
251
  name: entry.name,
@@ -326,6 +333,10 @@ export class GlmAdapter extends LlmAdapter {
326
333
  .filter((id) => findEntry(own, id) === undefined)
327
334
  .map((id) => extraEntry(id));
328
335
  }
336
+ /** The image-generation model id, when discovery reported one. */
337
+ imageModelId() {
338
+ return this.imageModel;
339
+ }
329
340
  /** The ids the picker must currently omit. */
330
341
  async hidden() {
331
342
  if (this.options.hiddenModels === undefined)
@@ -367,9 +378,12 @@ export class GlmAdapter extends LlmAdapter {
367
378
  return undefined;
368
379
  }
369
380
  const body = await response.json();
370
- const ids = (body.data ?? [])
381
+ const allIds = (body.data ?? [])
371
382
  .map((entry) => (typeof entry?.id === 'string' ? entry.id.trim() : ''))
372
383
  .filter((id) => id !== '');
384
+ // Image models are never picker rows: they are agent-called, always on.
385
+ this.imageModel = allIds.find((id) => isImageModel(id));
386
+ const ids = allIds.filter((id) => !NON_CHAT_ID.test(id));
373
387
  return ids.length === 0 ? undefined : ids;
374
388
  }
375
389
  catch (error) {
@@ -119,6 +119,7 @@ export function createKimiProvider(options) {
119
119
  { key: 'credentialFile', value: options.credentialFile },
120
120
  ],
121
121
  applyDiscovery: (ids) => { adapter.discover(ids); },
122
+ fastVariant: (baseId) => adapter.fastVariant(baseId),
122
123
  };
123
124
  const controller = new ProviderController({
124
125
  spec,
@@ -149,5 +150,13 @@ export function createKimiProvider(options) {
149
150
  removeModel: (id) => controller.removeModel(id),
150
151
  usage: (force) => controller.usage(force),
151
152
  reload: () => controller.reload(),
153
+ modelVariants: (id) => {
154
+ const fast = adapter.fastVariant(id);
155
+ const image = adapter.imageModelId();
156
+ return {
157
+ ...fast === undefined ? {} : { fast },
158
+ ...image === undefined ? {} : { image },
159
+ };
160
+ },
152
161
  };
153
162
  }
@@ -102,6 +102,10 @@ export declare class KimiAdapter extends LlmAdapter {
102
102
  private readonly options;
103
103
  /** Live catalog ids seen this session, used to accept renamed models. */
104
104
  private discovered;
105
+ /** Image-generation model id, when discovery reported one. */
106
+ private imageModel;
107
+ /** Fast-variant wire id per base model, for the picker's quick-mode button. */
108
+ private readonly fastVariants;
105
109
  /** Ids the user added by hand, cached so the sync catalog can name them. */
106
110
  private userAddedIds;
107
111
  /** Tools already reported as flattened, so each is stated once. */
@@ -116,6 +120,10 @@ export declare class KimiAdapter extends LlmAdapter {
116
120
  providerInfo(provider: string): LlmProviderInfo;
117
121
  providerRetryPolicy(): undefined;
118
122
  listModels(_provider: string): Promise<readonly LlmModelInfo[]>;
123
+ /** The image-generation model id, when discovery reported one. */
124
+ imageModelId(): string | undefined;
125
+ /** The fast/lightspeed variant wire id for a base model, when discovery reported one. */
126
+ fastVariant(baseId: string): string | undefined;
119
127
  /** The ids the picker must currently omit. */
120
128
  private hidden;
121
129
  resolveModel(_provider: string, model: string): Promise<LlmResolvedModelInfo>;
@@ -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 } 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,10 @@ 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
+ /** Fast-variant wire id per base model, for the picker's quick-mode button. */
138
+ fastVariants = new Map();
132
139
  /** Ids the user added by hand, cached so the sync catalog can name them. */
133
140
  userAddedIds = [];
134
141
  /** Tools already reported as flattened, so each is stated once. */
@@ -171,7 +178,9 @@ export class KimiAdapter extends LlmAdapter {
171
178
  return [];
172
179
  await this.syncUserModels();
173
180
  const hidden = await this.hidden();
174
- return resolveCatalog(this.catalog(), [], hidden).entries.map((entry) => ({
181
+ // Image models are never picker rows: they are agent-called, always on.
182
+ const imageless = this.catalog().filter((entry) => !isImageModel(entry.id));
183
+ return resolveCatalog(imageless, [], hidden).entries.map((entry) => ({
175
184
  provider: KIMI_PROVIDER_ID,
176
185
  id: entry.id,
177
186
  name: entry.name,
@@ -179,6 +188,14 @@ export class KimiAdapter extends LlmAdapter {
179
188
  ...entry.inputModalities === undefined ? {} : { inputModalities: entry.inputModalities },
180
189
  }));
181
190
  }
191
+ /** The image-generation model id, when discovery reported one. */
192
+ imageModelId() {
193
+ return this.imageModel;
194
+ }
195
+ /** The fast/lightspeed variant wire id for a base model, when discovery reported one. */
196
+ fastVariant(baseId) {
197
+ return this.fastVariants.get(baseId);
198
+ }
182
199
  /** The ids the picker must currently omit. */
183
200
  async hidden() {
184
201
  if (this.options.hiddenModels === undefined)
@@ -414,9 +431,22 @@ export class KimiAdapter extends LlmAdapter {
414
431
  return undefined;
415
432
  }
416
433
  const payload = await response.json();
417
- const ids = (payload.data ?? [])
434
+ const allIds = (payload.data ?? [])
418
435
  .map((entry) => entry.id)
419
436
  .filter((id) => typeof id === 'string' && id.length > 0);
437
+ // Image models are never picker rows: they are agent-called, always on.
438
+ this.imageModel = allIds.find((id) => isImageModel(id));
439
+ // Fast/lightspeed variants ride with their base model: they share the base's
440
+ // visibility switch and are reached by a picker button, not a separate row.
441
+ this.fastVariants.clear();
442
+ for (const id of allIds) {
443
+ if (!isFastVariant(id))
444
+ continue;
445
+ const base = baseModelOf(id);
446
+ if (!this.fastVariants.has(base))
447
+ this.fastVariants.set(base, id);
448
+ }
449
+ const ids = allIds.filter((id) => !NON_CHAT_ID.test(id));
420
450
  if (ids.length === 0) {
421
451
  this.options.onWarn?.('Kimi model discovery returned an empty catalog; using the built-in catalog');
422
452
  return undefined;
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.14",
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",