dsh-plugin-subscription-oauth 0.11.0 → 0.12.0
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/mimo-flow.d.ts +9 -0
- package/lib/auth/mimo-flow.js +171 -0
- package/lib/auth/registry.d.ts +10 -1
- package/lib/auth/registry.js +11 -1
- package/lib/auth/rpc.js +6 -0
- package/lib/client/SubscriptionsSection.js +37 -17
- package/lib/client.js +108 -135
- package/lib/client.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/protocol.d.ts +13 -1
- package/lib/protocol.js +1 -0
- package/lib/providers/auto.js +3 -0
- package/lib/providers/grok.d.ts +2 -0
- package/lib/providers/grok.js +31 -21
- package/lib/providers/kimi-provider.js +2 -1
- package/lib/providers/kimi.js +18 -13
- package/lib/providers/mimo.d.ts +10 -0
- package/lib/providers/mimo.js +65 -1
- package/lib/settings.d.ts +8 -0
- package/lib/settings.js +19 -5
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -167,7 +167,7 @@ export function apply(ctx, config = {}) {
|
|
|
167
167
|
break;
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
|
-
const registry = new SubscriptionRegistry(routes);
|
|
170
|
+
const registry = new SubscriptionRegistry(routes, preferences);
|
|
171
171
|
// `auto` stands in for the other routes, so it is built after them and added
|
|
172
172
|
// to the same registry it reads. Its list spans routes, which is why it is a
|
|
173
173
|
// provider of its own rather than a model inside each one.
|
package/lib/protocol.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
/** Prefix of every RPC method this plugin serves. */
|
|
13
13
|
export declare const RPC_PREFIX = "subscription-oauth.";
|
|
14
14
|
/** Endpoints the Settings page may call. */
|
|
15
|
-
export declare const RPC_ENDPOINTS: readonly ["status", "login", "cancel", "logout", "setDefault", "refresh", "discover", "setModelVisible", "setModelOrder", "addModel", "removeModel", "usage", "reload", "deepseek-balance", "ccswitch-balance", "model-variants"];
|
|
15
|
+
export declare const RPC_ENDPOINTS: readonly ["status", "login", "cancel", "logout", "setDefault", "refresh", "discover", "setModelVisible", "setModelOrder", "addModel", "removeModel", "usage", "reload", "setAutoOn", "deepseek-balance", "ccswitch-balance", "model-variants"];
|
|
16
16
|
/** One endpoint name. */
|
|
17
17
|
export type RpcEndpoint = typeof RPC_ENDPOINTS[number];
|
|
18
18
|
/** Client → host envelope. */
|
|
@@ -315,6 +315,10 @@ export interface RpcMap {
|
|
|
315
315
|
payload: undefined;
|
|
316
316
|
value: SubscriptionStatus;
|
|
317
317
|
};
|
|
318
|
+
setAutoOn: {
|
|
319
|
+
payload: SetAutoOnRequest;
|
|
320
|
+
value: AutoStateResult;
|
|
321
|
+
};
|
|
318
322
|
'deepseek-balance': {
|
|
319
323
|
payload: DeepSeekBalanceRequest;
|
|
320
324
|
value: DeepSeekBalanceResult;
|
|
@@ -382,6 +386,14 @@ export interface ModelVariantsRequest {
|
|
|
382
386
|
provider: string;
|
|
383
387
|
id: string;
|
|
384
388
|
}
|
|
389
|
+
/** Payload of `setAutoOn`: whether the `auto` provider is offered at all. */
|
|
390
|
+
export interface SetAutoOnRequest {
|
|
391
|
+
enabled: boolean;
|
|
392
|
+
}
|
|
393
|
+
/** Result of `setAutoOn`: the `auto` provider's live enabled state. */
|
|
394
|
+
export interface AutoStateResult {
|
|
395
|
+
enabled: boolean;
|
|
396
|
+
}
|
|
385
397
|
/** Payload of `deepseek-balance`. */
|
|
386
398
|
export interface DeepSeekBalanceRequest {
|
|
387
399
|
/** Client metadata the host's account service expects. */
|
package/lib/protocol.js
CHANGED
package/lib/providers/auto.js
CHANGED
|
@@ -64,6 +64,9 @@ export class AutoAdapter extends LlmAdapter {
|
|
|
64
64
|
return undefined;
|
|
65
65
|
}
|
|
66
66
|
async listModels(_provider) {
|
|
67
|
+
// A switched-off `auto` is not offered at all, so the picker shows the routes directly.
|
|
68
|
+
if (!(await this.options.preferences.autoPreferences()).enabled)
|
|
69
|
+
return [];
|
|
67
70
|
const chain = await this.chain();
|
|
68
71
|
// An `auto` with nothing to try is not offered at all, rather than offered
|
|
69
72
|
// and guaranteed to fail.
|
package/lib/providers/grok.d.ts
CHANGED
|
@@ -116,6 +116,8 @@ interface GrokCliMetadata {
|
|
|
116
116
|
export declare function isImageModel(id: string): boolean;
|
|
117
117
|
/** True when a model id names a fast/lightspeed variant of a base model. */
|
|
118
118
|
export declare function isFastVariant(id: string): boolean;
|
|
119
|
+
/** The fast word a variant's own id names (`grok-4.7-build-fast` → `fast`), lowercased. */
|
|
120
|
+
export declare function fastWordOf(id: string): string;
|
|
119
121
|
/**
|
|
120
122
|
* Every prefix of one model id, longest first, down to its first token.
|
|
121
123
|
*
|
package/lib/providers/grok.js
CHANGED
|
@@ -52,18 +52,18 @@ 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
54
|
/** The rung id the composer's quick-mode button selects. */
|
|
55
|
-
const FAST_RUNG = '
|
|
55
|
+
const FAST_RUNG = 'fast';
|
|
56
56
|
/** Display metadata for the reasoning ladder xAI documents. */
|
|
57
57
|
const EFFORT_LABELS = {
|
|
58
58
|
none: { name: 'Off', description: 'Answer without spending thinking tokens' },
|
|
59
59
|
low: { name: 'Low', description: 'Short chain of thought' },
|
|
60
60
|
medium: { name: 'Medium', description: 'Balanced thinking budget' },
|
|
61
61
|
high: { name: 'High', description: 'Deep chain of thought' },
|
|
62
|
-
// Not a thinking budget: this rung is the model's fast
|
|
63
|
-
// composer's quick-mode button selects. It rides the effort channel so the row
|
|
64
|
-
// its own id — a swapped model id would leave the picker with no way back.
|
|
65
|
-
// word for it is "
|
|
66
|
-
[FAST_RUNG]: { name: '
|
|
62
|
+
// Not a thinking budget: this rung is the model's fast variant, which the
|
|
63
|
+
// composer's quick-mode button selects. It rides the effort channel so the row
|
|
64
|
+
// keeps its own id — a swapped model id would leave the picker with no way back.
|
|
65
|
+
// xAI's own word for it is "fast" (grok-4.7-build-fast), which names the rung.
|
|
66
|
+
[FAST_RUNG]: { name: 'Fast', description: 'xAI fast variant of this model' },
|
|
67
67
|
};
|
|
68
68
|
/**
|
|
69
69
|
* Curated catalog entries.
|
|
@@ -127,18 +127,21 @@ export function parseGrokSession(value) {
|
|
|
127
127
|
}
|
|
128
128
|
/** One `reasoning.efforts` entry. */
|
|
129
129
|
function effortInfo(effort) {
|
|
130
|
-
const
|
|
130
|
+
const known = EFFORT_LABELS[effort];
|
|
131
|
+
const label = known ?? { name: effort[0].toUpperCase() + effort.slice(1), description: `${effort} variant of this model` };
|
|
131
132
|
return { id: ReasoningEffortId(effort), name: label.name, description: label.description };
|
|
132
133
|
}
|
|
133
134
|
/**
|
|
134
135
|
* The reasoning block for a catalog entry, or undefined when it supports none.
|
|
135
136
|
*
|
|
136
137
|
* @param entry - the catalog row.
|
|
137
|
-
* @param
|
|
138
|
+
* @param fastWireId - the row's fast variant wire id, when it has one; the rung is the
|
|
139
|
+
* variant's own fast word (`grok-4.7-build-fast` → `fast`).
|
|
138
140
|
*/
|
|
139
|
-
function reasoningInfo(entry,
|
|
141
|
+
function reasoningInfo(entry, fastWireId) {
|
|
140
142
|
const efforts = entry.reasoningEfforts;
|
|
141
|
-
const
|
|
143
|
+
const rung = fastWireId === undefined ? undefined : fastWordOf(fastWireId);
|
|
144
|
+
const ids = rung === undefined ? efforts : [...efforts ?? [], rung];
|
|
142
145
|
if (ids === undefined || ids.length === 0)
|
|
143
146
|
return undefined;
|
|
144
147
|
return {
|
|
@@ -289,11 +292,15 @@ export function isImageModel(id) {
|
|
|
289
292
|
* (`kimi-for-coding-highspeed`). A word has to stand on its own, so `highspeed` never
|
|
290
293
|
* matches inside another word.
|
|
291
294
|
*/
|
|
292
|
-
const FAST_VARIANT = /(?:^|[-_@])(
|
|
295
|
+
const FAST_VARIANT = /(?:^|[-_@])(fast|lightspeed|turbo|quick|highspeed)(?=[-_@]|$)/i;
|
|
293
296
|
/** True when a model id names a fast/lightspeed variant of a base model. */
|
|
294
297
|
export function isFastVariant(id) {
|
|
295
298
|
return FAST_VARIANT.test(id);
|
|
296
299
|
}
|
|
300
|
+
/** The fast word a variant's own id names (`grok-4.7-build-fast` → `fast`), lowercased. */
|
|
301
|
+
export function fastWordOf(id) {
|
|
302
|
+
return FAST_VARIANT.exec(id)?.[1]?.toLowerCase() ?? 'fast';
|
|
303
|
+
}
|
|
297
304
|
/**
|
|
298
305
|
* Every prefix of one model id, longest first, down to its first token.
|
|
299
306
|
*
|
|
@@ -503,9 +510,10 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
503
510
|
...reasoning === undefined ? {} : { reasoning },
|
|
504
511
|
};
|
|
505
512
|
}
|
|
506
|
-
// A row with a fast variant offers
|
|
507
|
-
// its own name and the mode as the effort
|
|
508
|
-
const
|
|
513
|
+
// A row with a fast variant offers a rung named for the variant's own word; the
|
|
514
|
+
// picker shows the row under its own name and the mode as the effort.
|
|
515
|
+
const fastWireId = this.fastVariants.variantOf(entry.id);
|
|
516
|
+
const reasoning = reasoningInfo(entry, fastWireId);
|
|
509
517
|
return {
|
|
510
518
|
provider: GROK_PROVIDER_ID,
|
|
511
519
|
id: model,
|
|
@@ -520,13 +528,15 @@ export class GrokAdapter extends LlmAdapter {
|
|
|
520
528
|
stream(options) {
|
|
521
529
|
// Resolve @Nk context suffixes to the largest variant the endpoint offers.
|
|
522
530
|
const base = this.resolveModelId(options.model);
|
|
523
|
-
// Fast mode rides the reasoning channel:
|
|
524
|
-
// of its own, so the row the picker selected stays dispatchable and the user
|
|
525
|
-
// always select the standard model again. Only the wire id changes.
|
|
526
|
-
const
|
|
527
|
-
const
|
|
531
|
+
// Fast mode rides the reasoning channel: the rung is the variant's own fast word, not
|
|
532
|
+
// a model id of its own, so the row the picker selected stays dispatchable and the user
|
|
533
|
+
// can always select the standard model again. Only the wire id changes.
|
|
534
|
+
const effort = String(options.reasoningEffort ?? '');
|
|
535
|
+
const fastWireId = this.fastVariants.variantOf(base);
|
|
536
|
+
const fast = fastWireId !== undefined && effort === fastWordOf(fastWireId);
|
|
537
|
+
const model = fast ? fastWireId : base;
|
|
528
538
|
const call = { ...options, model };
|
|
529
|
-
// xAI has no
|
|
539
|
+
// xAI has no fast-variant effort; the variant already carries the behaviour.
|
|
530
540
|
if (fast)
|
|
531
541
|
delete call.reasoningEffort;
|
|
532
542
|
return streamProviderResponses(call, {
|
|
@@ -1003,7 +1013,7 @@ export function createGrokProvider(options) {
|
|
|
1003
1013
|
const pair = adapter.fastPairOf(id);
|
|
1004
1014
|
const image = adapter.imageModelId();
|
|
1005
1015
|
return {
|
|
1006
|
-
...pair === undefined ? {} : { fast: pair.wireId, fastBase: pair.baseId, fastRung:
|
|
1016
|
+
...pair === undefined ? {} : { fast: pair.wireId, fastBase: pair.baseId, fastRung: fastWordOf(pair.wireId) },
|
|
1007
1017
|
...image === undefined ? {} : { image },
|
|
1008
1018
|
};
|
|
1009
1019
|
},
|
|
@@ -13,6 +13,7 @@ import { loadOrCreateDeviceId } from '../auth/device-id.js';
|
|
|
13
13
|
import { kimiIdentityHeaders } from '../auth/headers.js';
|
|
14
14
|
import { KimiAdapter, parseKimiSession } from './kimi.js';
|
|
15
15
|
import { readKimiUsage } from './usage.js';
|
|
16
|
+
import { fastWordOf } from './grok.js';
|
|
16
17
|
import { ProviderController } from '../auth/provider-controller.js';
|
|
17
18
|
import { proxiedFetch } from '../http.js';
|
|
18
19
|
/**
|
|
@@ -154,7 +155,7 @@ export function createKimiProvider(options) {
|
|
|
154
155
|
const pair = adapter.fastPairOf(id);
|
|
155
156
|
const image = adapter.imageModelId();
|
|
156
157
|
return {
|
|
157
|
-
...pair === undefined ? {} : { fast: pair.wireId, fastBase: pair.baseId, fastRung:
|
|
158
|
+
...pair === undefined ? {} : { fast: pair.wireId, fastBase: pair.baseId, fastRung: fastWordOf(pair.wireId) },
|
|
158
159
|
...image === undefined ? {} : { image },
|
|
159
160
|
};
|
|
160
161
|
},
|
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, FastVariantIndex } from './grok.js';
|
|
18
|
+
import { isImageModel, isFastVariant, baseModelOf, fastWordOf, 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
|
/**
|
|
@@ -127,11 +127,13 @@ function effortInfo(effort) {
|
|
|
127
127
|
* The reasoning block for a catalog entry, or undefined when it supports none.
|
|
128
128
|
*
|
|
129
129
|
* @param entry - the catalog row.
|
|
130
|
-
* @param
|
|
130
|
+
* @param fastWireId - the row's fast variant wire id, when it has one; the rung is the
|
|
131
|
+
* variant's own fast word (`kimi-for-coding-highspeed` → `highspeed`).
|
|
131
132
|
*/
|
|
132
|
-
function reasoningInfo(entry,
|
|
133
|
+
function reasoningInfo(entry, fastWireId) {
|
|
133
134
|
const efforts = entry.reasoningEfforts;
|
|
134
|
-
const
|
|
135
|
+
const rung = fastWireId === undefined ? undefined : fastWordOf(fastWireId);
|
|
136
|
+
const ids = rung === undefined ? efforts : [...efforts ?? [], rung];
|
|
135
137
|
if (ids === undefined || ids.length === 0)
|
|
136
138
|
return undefined;
|
|
137
139
|
const defaultEffort = entry.defaultEffort ?? ids[ids.length - 1];
|
|
@@ -271,9 +273,10 @@ export class KimiAdapter extends LlmAdapter {
|
|
|
271
273
|
...reasoning === undefined ? {} : { reasoning },
|
|
272
274
|
};
|
|
273
275
|
}
|
|
274
|
-
// A row with a fast variant offers
|
|
275
|
-
// its own name and the mode as the effort
|
|
276
|
-
const
|
|
276
|
+
// A row with a fast variant offers a rung named for the variant's own word; the
|
|
277
|
+
// picker shows the row under its own name and the mode as the effort.
|
|
278
|
+
const fastWireId = this.fastVariants.variantOf(entry.id);
|
|
279
|
+
const reasoning = reasoningInfo(entry, fastWireId);
|
|
277
280
|
// An alias is just another spelling of the row, so it resolves onto the row's own id:
|
|
278
281
|
// that is what keeps a selection dispatchable and the picker able to show it.
|
|
279
282
|
return {
|
|
@@ -288,13 +291,15 @@ export class KimiAdapter extends LlmAdapter {
|
|
|
288
291
|
};
|
|
289
292
|
}
|
|
290
293
|
stream(options) {
|
|
291
|
-
// Fast mode rides the reasoning channel:
|
|
292
|
-
// of its own, so the row the picker selected stays dispatchable and the user
|
|
293
|
-
// always select the standard model again. Only the wire id changes.
|
|
294
|
-
const
|
|
295
|
-
const
|
|
294
|
+
// Fast mode rides the reasoning channel: the rung is the variant's own fast word, not
|
|
295
|
+
// a model id of its own, so the row the picker selected stays dispatchable and the user
|
|
296
|
+
// can always select the standard model again. Only the wire id changes.
|
|
297
|
+
const fastWireId = this.fastVariants.variantOf(options.model);
|
|
298
|
+
const effort = String(options.reasoningEffort ?? '');
|
|
299
|
+
const fast = fastWireId !== undefined && effort === fastWordOf(fastWireId);
|
|
300
|
+
const model = fast ? fastWireId : options.model;
|
|
296
301
|
const call = { ...options, model };
|
|
297
|
-
// Kimi has no
|
|
302
|
+
// Kimi has no fast-variant effort; the variant already carries the behaviour.
|
|
298
303
|
if (fast)
|
|
299
304
|
delete call.reasoningEffort;
|
|
300
305
|
return streamProviderResponses(call, {
|
package/lib/providers/mimo.d.ts
CHANGED
|
@@ -82,6 +82,16 @@ export declare class MimoAdapter extends LlmAdapter {
|
|
|
82
82
|
/** The ids the route itself serves, without hand-added extras. */
|
|
83
83
|
ownCatalogEntries(): readonly MimoModelEntry[];
|
|
84
84
|
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
85
|
+
/** The app's names for its models, as the Token Plan's endpoint names them. */
|
|
86
|
+
private static readonly TP_MODELS;
|
|
87
|
+
/**
|
|
88
|
+
* Re-ask a membership_required chat at the Token Plan's endpoint.
|
|
89
|
+
*
|
|
90
|
+
* Reads the account's tp- API key from the open platform, then posts the chat to the
|
|
91
|
+
* plan's OpenAI base with that key. Undefined when the account has no live plan or no
|
|
92
|
+
* readable key.
|
|
93
|
+
*/
|
|
94
|
+
private tokenPlanRequest;
|
|
85
95
|
/**
|
|
86
96
|
* The session cookies as one Cookie header, in a steady order.
|
|
87
97
|
*
|
package/lib/providers/mimo.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { LlmAdapter, errorChain, } from '@deepseek-ai/dsh-llm';
|
|
12
12
|
import { httpLlmError, isMissingOrInvalidCredential, mapFetchFailure, idleWatchdog } from './common.js';
|
|
13
13
|
import { proxiedFetch } from '../http.js';
|
|
14
|
-
import { refreshMimoSession } from '../auth/mimo-flow.js';
|
|
14
|
+
import { readMimoPlanKey, refreshMimoSession } from '../auth/mimo-flow.js';
|
|
15
15
|
/** The `mimo` provider route key. */
|
|
16
16
|
export const MIMO_PROVIDER_ID = 'mimo';
|
|
17
17
|
/** Human name for the route and its cards. */
|
|
@@ -145,6 +145,28 @@ export class MimoAdapter extends LlmAdapter {
|
|
|
145
145
|
body: JSON.stringify(body),
|
|
146
146
|
signal: watchdog.signal,
|
|
147
147
|
});
|
|
148
|
+
// A 403 with code membership_required means the account has no app plan but a
|
|
149
|
+
// Token Plan at the open platform: re-ask at its endpoint with its tp- key.
|
|
150
|
+
if (response.status === 403) {
|
|
151
|
+
const text = await response.text();
|
|
152
|
+
let code;
|
|
153
|
+
try {
|
|
154
|
+
code = JSON.parse(text).error !== undefined
|
|
155
|
+
? JSON.parse(text).error.code
|
|
156
|
+
: JSON.parse(text).code;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
code = undefined;
|
|
160
|
+
}
|
|
161
|
+
if (code === 'membership_required') {
|
|
162
|
+
const plan = await this.tokenPlanRequest(session, body, watchdog);
|
|
163
|
+
if (plan !== undefined) {
|
|
164
|
+
yield* this.readStream(plan, watchdog);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
throw new Error(`Xiaomi MiMo: ${text.slice(0, 200)}`);
|
|
169
|
+
}
|
|
148
170
|
if (!response.ok || response.body === null) {
|
|
149
171
|
throw await httpLlmError(response, 'Xiaomi MiMo');
|
|
150
172
|
}
|
|
@@ -157,6 +179,48 @@ export class MimoAdapter extends LlmAdapter {
|
|
|
157
179
|
watchdog.stop();
|
|
158
180
|
}
|
|
159
181
|
}
|
|
182
|
+
/** The app's names for its models, as the Token Plan's endpoint names them. */
|
|
183
|
+
static TP_MODELS = {
|
|
184
|
+
'mimo-pro': 'mimo-v2.6-pro',
|
|
185
|
+
'mimo-flash': 'mimo-v2.6-flash',
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* Re-ask a membership_required chat at the Token Plan's endpoint.
|
|
189
|
+
*
|
|
190
|
+
* Reads the account's tp- API key from the open platform, then posts the chat to the
|
|
191
|
+
* plan's OpenAI base with that key. Undefined when the account has no live plan or no
|
|
192
|
+
* readable key.
|
|
193
|
+
*/
|
|
194
|
+
async tokenPlanRequest(session, body, watchdog) {
|
|
195
|
+
let creds;
|
|
196
|
+
try {
|
|
197
|
+
creds = JSON.parse(session.mimoCreds);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
const plan = await readMimoPlanKey(creds, this.fetchFn);
|
|
204
|
+
if (plan === null)
|
|
205
|
+
return undefined;
|
|
206
|
+
const model = MimoAdapter.TP_MODELS[String(body.model)] ?? String(body.model);
|
|
207
|
+
const path = new URL(session.apiBase.replace(/\/+$/, '') + '/route/chat/completions').pathname;
|
|
208
|
+
const rest = path.replace(/^.*?\/route(?=\/|$)/, '');
|
|
209
|
+
return await this.fetchFn(`${plan.base}${rest}`, {
|
|
210
|
+
method: 'POST',
|
|
211
|
+
headers: {
|
|
212
|
+
'Content-Type': 'application/json',
|
|
213
|
+
'Accept': 'text/event-stream',
|
|
214
|
+
'Authorization': `Bearer ${plan.key}`,
|
|
215
|
+
},
|
|
216
|
+
body: JSON.stringify({ ...body, model }),
|
|
217
|
+
signal: watchdog.signal,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
160
224
|
/**
|
|
161
225
|
* The session cookies as one Cookie header, in a steady order.
|
|
162
226
|
*
|
package/lib/settings.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export interface AutoPreferences {
|
|
|
33
33
|
order: readonly string[];
|
|
34
34
|
/** Keys `auto` must not use, whatever their own route offers. */
|
|
35
35
|
off: readonly string[];
|
|
36
|
+
/** Whether the `auto` provider is offered at all. Defaults to true. */
|
|
37
|
+
enabled: boolean;
|
|
36
38
|
}
|
|
37
39
|
/**
|
|
38
40
|
* Owns the model preference document.
|
|
@@ -89,6 +91,12 @@ export declare class ModelPreferences {
|
|
|
89
91
|
removeExtra(provider: string, id: string): Promise<boolean>;
|
|
90
92
|
/** The `auto` provider's arrangement. */
|
|
91
93
|
autoPreferences(): Promise<AutoPreferences>;
|
|
94
|
+
/**
|
|
95
|
+
* Record whether the `auto` provider is offered at all.
|
|
96
|
+
* @param enabled - whether `auto` appears in the picker.
|
|
97
|
+
* @returns whether the stored state actually changed.
|
|
98
|
+
*/
|
|
99
|
+
setAutoOn(enabled: boolean): Promise<boolean>;
|
|
92
100
|
/**
|
|
93
101
|
* Replace the `auto` provider's order.
|
|
94
102
|
* @param keys - `provider/model` keys, most preferred first.
|
package/lib/settings.js
CHANGED
|
@@ -26,10 +26,11 @@ export const LEGACY_FLAT_PROVIDER = 'kimi';
|
|
|
26
26
|
/** Read the `auto` section, keeping only usable keys. */
|
|
27
27
|
function readAuto(document) {
|
|
28
28
|
if (!isRecord(document.auto))
|
|
29
|
-
return { order: [], off: [] };
|
|
29
|
+
return { order: [], off: [], enabled: true };
|
|
30
30
|
return {
|
|
31
31
|
order: readIds(document.auto.order),
|
|
32
32
|
off: readIds(document.auto.off),
|
|
33
|
+
enabled: document.auto.enabled !== false,
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
36
|
/** True for a plain object usable as a JSON record. */
|
|
@@ -102,7 +103,7 @@ export class ModelPreferences {
|
|
|
102
103
|
file;
|
|
103
104
|
hidden = {};
|
|
104
105
|
order = {};
|
|
105
|
-
auto = { order: [], off: [] };
|
|
106
|
+
auto = { order: [], off: [], enabled: true };
|
|
106
107
|
extra = {};
|
|
107
108
|
loaded = false;
|
|
108
109
|
/** The in-flight first read, so concurrent callers share one. */
|
|
@@ -137,7 +138,7 @@ export class ModelPreferences {
|
|
|
137
138
|
catch {
|
|
138
139
|
this.hidden = {};
|
|
139
140
|
this.order = {};
|
|
140
|
-
this.auto = { order: [], off: [] };
|
|
141
|
+
this.auto = { order: [], off: [], enabled: true };
|
|
141
142
|
this.extra = {};
|
|
142
143
|
this.loaded = true;
|
|
143
144
|
return;
|
|
@@ -153,7 +154,7 @@ export class ModelPreferences {
|
|
|
153
154
|
catch {
|
|
154
155
|
this.hidden = {};
|
|
155
156
|
this.order = {};
|
|
156
|
-
this.auto = { order: [], off: [] };
|
|
157
|
+
this.auto = { order: [], off: [], enabled: true };
|
|
157
158
|
this.extra = {};
|
|
158
159
|
}
|
|
159
160
|
this.loaded = true;
|
|
@@ -220,7 +221,20 @@ export class ModelPreferences {
|
|
|
220
221
|
/** The `auto` provider's arrangement. */
|
|
221
222
|
async autoPreferences() {
|
|
222
223
|
await this.ensureLoaded();
|
|
223
|
-
return { order: [...this.auto.order], off: [...this.auto.off] };
|
|
224
|
+
return { order: [...this.auto.order], off: [...this.auto.off], enabled: this.auto.enabled };
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Record whether the `auto` provider is offered at all.
|
|
228
|
+
* @param enabled - whether `auto` appears in the picker.
|
|
229
|
+
* @returns whether the stored state actually changed.
|
|
230
|
+
*/
|
|
231
|
+
async setAutoOn(enabled) {
|
|
232
|
+
await this.ensureLoaded();
|
|
233
|
+
if (this.auto.enabled === enabled)
|
|
234
|
+
return false;
|
|
235
|
+
this.auto = { ...this.auto, enabled };
|
|
236
|
+
await this.persist();
|
|
237
|
+
return true;
|
|
224
238
|
}
|
|
225
239
|
/**
|
|
226
240
|
* Replace the `auto` provider's order.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-subscription-oauth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
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",
|