dsh-connect-minimaxcode 0.2.3 → 0.3.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/README.md +82 -27
- package/lib/client.js +199 -0
- package/lib/index.d.ts +275 -3
- package/lib/index.js +603 -19
- package/package.json +14 -4
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "@earendil-works/pi-ai";
|
|
2
|
-
import {
|
|
2
|
+
import { LlmAdapter } from "@deepseek-ai/dsh-llm";
|
|
3
3
|
import { Context } from "@deepseek-ai/cordis";
|
|
4
4
|
//#region src/auth.d.ts
|
|
5
5
|
/** File the desktop app writes its runtime auth context into. */
|
|
@@ -197,9 +197,260 @@ declare class MinimaxCatalog {
|
|
|
197
197
|
get identity(): string | undefined;
|
|
198
198
|
}
|
|
199
199
|
//#endregion
|
|
200
|
+
//#region src/credits.d.ts
|
|
201
|
+
/** The desktop app's own OAuth client id. */
|
|
202
|
+
declare const MINIMAX_OAUTH_CLIENT_ID = "mcode-public";
|
|
203
|
+
/** Membership endpoint: carries the credit summary. */
|
|
204
|
+
declare const MEMBERSHIP_PATH = "/matrix/api/v1/commerce/get_membership_info";
|
|
205
|
+
/** The OAuth credential the account endpoints accept. */
|
|
206
|
+
interface OAuthCredential {
|
|
207
|
+
/** The `mmoat_` bearer token. */
|
|
208
|
+
token: string;
|
|
209
|
+
/** The refresh token, when the app stored one. */
|
|
210
|
+
refreshToken?: string;
|
|
211
|
+
/** Expiry in milliseconds since the epoch, when known. */
|
|
212
|
+
expiresAtMs?: number;
|
|
213
|
+
/** The client the token was issued to. */
|
|
214
|
+
clientId: string;
|
|
215
|
+
/** Scopes the token carries. */
|
|
216
|
+
scopes: string[];
|
|
217
|
+
/** Audience the token was issued for. */
|
|
218
|
+
audience: string;
|
|
219
|
+
/** The app's login generation; preserved verbatim on write-back. */
|
|
220
|
+
generation?: number;
|
|
221
|
+
}
|
|
222
|
+
/** Why the account data may be unavailable. */
|
|
223
|
+
type OAuthState = {
|
|
224
|
+
state: 'signed-in';
|
|
225
|
+
credential: OAuthCredential;
|
|
226
|
+
} | {
|
|
227
|
+
state: 'expired';
|
|
228
|
+
credential: OAuthCredential;
|
|
229
|
+
} | {
|
|
230
|
+
state: 'signed-out';
|
|
231
|
+
reason: 'app-missing' | 'not-signed-in' | 'unreadable' | 'malformed';
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* Parse the app's credential document.
|
|
235
|
+
*
|
|
236
|
+
* The record key is generated per install, so the record is found by value
|
|
237
|
+
* rather than by a hard-coded name.
|
|
238
|
+
*/
|
|
239
|
+
declare function parseOAuthDocument(text: string, now?: number): OAuthState;
|
|
240
|
+
/**
|
|
241
|
+
* Read the desktop app's OAuth credential.
|
|
242
|
+
*
|
|
243
|
+
* Every failure is a state, not an exception: an app that is not installed, or
|
|
244
|
+
* not signed in, is a normal condition the UI renders rather than an error the
|
|
245
|
+
* host logs on every request.
|
|
246
|
+
*/
|
|
247
|
+
declare function readOAuthCredential(region: MinimaxRegion, env?: NodeJS.ProcessEnv, now?: number): Promise<OAuthState>;
|
|
248
|
+
/**
|
|
249
|
+
* Exchange the stored refresh token for a fresh access token.
|
|
250
|
+
*
|
|
251
|
+
* The authorization server rotates the refresh token, so the new pair is
|
|
252
|
+
* written back into the app's own file, in the app's own format, with an
|
|
253
|
+
* atomic replace. `generation` is left untouched on purpose: the app uses it
|
|
254
|
+
* to decide whether a stored credential still belongs to its own login, and
|
|
255
|
+
* raising it would make the app believe it had been signed in elsewhere.
|
|
256
|
+
*/
|
|
257
|
+
declare function refreshOAuthCredential(region: MinimaxRegion, credential: OAuthCredential, env?: NodeJS.ProcessEnv, now?: number, fetchImpl?: typeof fetch): Promise<OAuthState>;
|
|
258
|
+
/**
|
|
259
|
+
* Write a rotated credential back into the app's store.
|
|
260
|
+
*
|
|
261
|
+
* The document is rewritten as a whole so the app's own reader keeps seeing
|
|
262
|
+
* the shape it wrote, and the replace is atomic so a crash mid-write cannot
|
|
263
|
+
* leave a truncated credential file behind.
|
|
264
|
+
*/
|
|
265
|
+
declare function writeOAuthCredential(region: MinimaxRegion, credential: OAuthCredential, env?: NodeJS.ProcessEnv): Promise<void>;
|
|
266
|
+
/**
|
|
267
|
+
* Read the credential, refreshing it when it is close to expiry.
|
|
268
|
+
*
|
|
269
|
+
* A refresh is only attempted for a credential the app already stored, and
|
|
270
|
+
* only when it is actually stale: a fresh token is left alone, so the plugin
|
|
271
|
+
* never competes with the app for the same grant.
|
|
272
|
+
*/
|
|
273
|
+
declare function ensureOAuthCredential(region: MinimaxRegion, env?: NodeJS.ProcessEnv, now?: number, fetchImpl?: typeof fetch): Promise<OAuthState>;
|
|
274
|
+
/** The credit balance the desktop app shows. */
|
|
275
|
+
interface CreditSummary {
|
|
276
|
+
/** Remaining credits, free plus purchased. */
|
|
277
|
+
total: number;
|
|
278
|
+
/** Remaining purchased credits. */
|
|
279
|
+
purchased: number;
|
|
280
|
+
/** Remaining free (granted) credits. */
|
|
281
|
+
free: number;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Read the credit summary out of a membership response.
|
|
285
|
+
*
|
|
286
|
+
* The app's settings page prefers the summary and falls back to the flat
|
|
287
|
+
* balance fields, so the same fallback chain is used here.
|
|
288
|
+
*/
|
|
289
|
+
declare function parseCreditSummary(document: unknown): CreditSummary | undefined;
|
|
290
|
+
/**
|
|
291
|
+
* Fetch the current credit balance.
|
|
292
|
+
*
|
|
293
|
+
* @returns The balance, or `undefined` when the account has no credit summary.
|
|
294
|
+
*/
|
|
295
|
+
declare function fetchCreditSummary(credential: OAuthCredential, region: MinimaxRegion, fetchImpl?: typeof fetch): Promise<CreditSummary | undefined>;
|
|
296
|
+
/** The balance plus what changed since the previous read. */
|
|
297
|
+
interface CreditSnapshot {
|
|
298
|
+
summary: CreditSummary;
|
|
299
|
+
/** Milliseconds since the epoch, when the balance was read. */
|
|
300
|
+
fetchedAtMs: number;
|
|
301
|
+
/**
|
|
302
|
+
* Credits consumed since the previous read.
|
|
303
|
+
*
|
|
304
|
+
* The upstream balance is a live counter, so the difference between two
|
|
305
|
+
* reads is the credits actually spent in between. It can be negative when
|
|
306
|
+
* credits are granted (the app grants credits daily), and it counts every
|
|
307
|
+
* client of the account, not just this one.
|
|
308
|
+
*/
|
|
309
|
+
consumed: number;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Keeps the current balance and the change between reads.
|
|
313
|
+
*
|
|
314
|
+
* The first read has nothing to compare against, so it reports no movement
|
|
315
|
+
* rather than pretending the whole balance was spent.
|
|
316
|
+
*/
|
|
317
|
+
declare class MinimaxCredits {
|
|
318
|
+
#private;
|
|
319
|
+
/** The balance as last read. */
|
|
320
|
+
get snapshot(): CreditSnapshot | undefined;
|
|
321
|
+
/** Why the last read failed, when one did. */
|
|
322
|
+
get error(): string | undefined;
|
|
323
|
+
/**
|
|
324
|
+
* Read the balance and record how much was consumed since the last read.
|
|
325
|
+
*
|
|
326
|
+
* @returns Whether the balance changed.
|
|
327
|
+
*/
|
|
328
|
+
refresh(credential: OAuthCredential, region: MinimaxRegion, fetchImpl?: typeof fetch, now?: number): Promise<boolean>;
|
|
329
|
+
}
|
|
330
|
+
//#endregion
|
|
331
|
+
//#region src/usage.d.ts
|
|
332
|
+
/**
|
|
333
|
+
* What a conversation actually cost.
|
|
334
|
+
*
|
|
335
|
+
* Every response from the gateway carries its own usage counters, so the
|
|
336
|
+
* consumption of a session can be measured exactly rather than estimated from
|
|
337
|
+
* the transcript. The upstream sends four numbers, and the distinction
|
|
338
|
+
* between them matters: `input_tokens` counts only the tokens that missed the
|
|
339
|
+
* prompt cache, so a naive sum understates a long conversation badly.
|
|
340
|
+
*
|
|
341
|
+
* The conversion to money uses MiniMax's published domestic price list
|
|
342
|
+
* (元/百万 tokens). It is an equivalent amount, not a charge: the credits the
|
|
343
|
+
* desktop app shows are a separate resource, and MiniMax publishes no
|
|
344
|
+
* numeric exchange rate between the two.
|
|
345
|
+
*
|
|
346
|
+
* @module dsh-connect-minimaxcode/usage
|
|
347
|
+
*/
|
|
348
|
+
/** Token counts of one request, as the gateway reported them. */
|
|
349
|
+
interface ModelUsage {
|
|
350
|
+
/** Tokens sent that missed the prompt cache. */
|
|
351
|
+
inputTokens: number;
|
|
352
|
+
/** Tokens produced. */
|
|
353
|
+
outputTokens: number;
|
|
354
|
+
/** Tokens served from the prompt cache. */
|
|
355
|
+
cacheReadTokens: number;
|
|
356
|
+
/** Tokens written into the prompt cache. */
|
|
357
|
+
cacheWriteTokens: number;
|
|
358
|
+
/** Tokens spent reasoning, when the model reports them separately. */
|
|
359
|
+
reasoningTokens: number;
|
|
360
|
+
}
|
|
361
|
+
/** An empty usage record. */
|
|
362
|
+
declare const EMPTY_USAGE: ModelUsage;
|
|
363
|
+
/** Prices in 元 per million tokens, from MiniMax's domestic price list. */
|
|
364
|
+
interface ModelPrice {
|
|
365
|
+
input: number;
|
|
366
|
+
output: number;
|
|
367
|
+
cacheRead: number;
|
|
368
|
+
}
|
|
369
|
+
/** The published domestic prices of the models this plugin serves. */
|
|
370
|
+
declare const MODEL_PRICES: Readonly<Record<string, ModelPrice>>;
|
|
371
|
+
/**
|
|
372
|
+
* The price for one model at one input size.
|
|
373
|
+
*
|
|
374
|
+
* M3 is billed in two tiers: requests above 512k input tokens cost double.
|
|
375
|
+
* The tier is decided by the billed input, which is the uncached input plus
|
|
376
|
+
* the cache read.
|
|
377
|
+
*/
|
|
378
|
+
declare function priceFor(model: string, billedInputTokens: number): ModelPrice | undefined;
|
|
379
|
+
/**
|
|
380
|
+
* The equivalent amount of one request, in 元.
|
|
381
|
+
*
|
|
382
|
+
* Returns `undefined` for a model without a published price, rather than
|
|
383
|
+
* pretending the request was free.
|
|
384
|
+
*/
|
|
385
|
+
declare function estimateCny(model: string, usage: ModelUsage): number | undefined;
|
|
386
|
+
/** One recorded request. */
|
|
387
|
+
interface UsageRecord {
|
|
388
|
+
model: string;
|
|
389
|
+
usage: ModelUsage;
|
|
390
|
+
/** Equivalent amount in 元, when the model has a published price. */
|
|
391
|
+
cny?: number;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Accumulates what the sessions routed through this plugin have used.
|
|
395
|
+
*
|
|
396
|
+
* The meter is the plugin's own view: it counts the requests this host made,
|
|
397
|
+
* with the counters the gateway returned. It is not the account's total, and
|
|
398
|
+
* it is not the credit balance — the balance comes from the account API.
|
|
399
|
+
*/
|
|
400
|
+
declare class UsageMeter {
|
|
401
|
+
#private;
|
|
402
|
+
/** Every recorded request, oldest first. */
|
|
403
|
+
get records(): readonly UsageRecord[];
|
|
404
|
+
/** The most recent request. */
|
|
405
|
+
get last(): UsageRecord | undefined;
|
|
406
|
+
/** Record one request's usage. */
|
|
407
|
+
record(model: string, usage: ModelUsage): UsageRecord;
|
|
408
|
+
/** Totals across every recorded request. */
|
|
409
|
+
totals(): ModelUsage;
|
|
410
|
+
/** Totals per model. */
|
|
411
|
+
byModel(): ReadonlyMap<string, ModelUsage>;
|
|
412
|
+
/** The equivalent amount of everything recorded, in 元. */
|
|
413
|
+
estimatedCny(): number;
|
|
414
|
+
/** Forget everything recorded. */
|
|
415
|
+
reset(): void;
|
|
416
|
+
}
|
|
417
|
+
//#endregion
|
|
200
418
|
//#region src/status-route.d.ts
|
|
201
419
|
/** Route this plugin mounts, matching its settings card. */
|
|
202
420
|
declare const MINIMAX_STATUS_PATH = "/plugins/dsh-connect-minimaxcode/status";
|
|
421
|
+
/** The account's credit balance, as the desktop app shows it. */
|
|
422
|
+
interface CreditStatus {
|
|
423
|
+
/** Whether the balance could be read. */
|
|
424
|
+
state: 'ok' | 'unavailable' | 'expired' | 'signed-out';
|
|
425
|
+
/** Remaining credits, free plus purchased. */
|
|
426
|
+
total?: number;
|
|
427
|
+
/** Remaining purchased credits. */
|
|
428
|
+
purchased?: number;
|
|
429
|
+
/** Remaining free (granted) credits. */
|
|
430
|
+
free?: number;
|
|
431
|
+
/** Credits consumed between the two last reads. */
|
|
432
|
+
consumed?: number;
|
|
433
|
+
/** When the balance was read, in milliseconds since the epoch. */
|
|
434
|
+
updatedAtMs?: number;
|
|
435
|
+
/** Why the balance could not be read. */
|
|
436
|
+
error?: string;
|
|
437
|
+
}
|
|
438
|
+
/** What the plugin's own requests have used. */
|
|
439
|
+
interface UsageStatus {
|
|
440
|
+
inputTokens: number;
|
|
441
|
+
outputTokens: number;
|
|
442
|
+
cacheReadTokens: number;
|
|
443
|
+
cacheWriteTokens: number;
|
|
444
|
+
reasoningTokens: number;
|
|
445
|
+
/** Equivalent amount of everything this host spent, in 元. */
|
|
446
|
+
estimatedCny: number;
|
|
447
|
+
/** The equivalent amount of the last request, in 元. */
|
|
448
|
+
lastCny?: number;
|
|
449
|
+
/** The model of the last request. */
|
|
450
|
+
lastModel?: string;
|
|
451
|
+
/** How many requests were measured. */
|
|
452
|
+
requests: number;
|
|
453
|
+
}
|
|
203
454
|
/** What the card renders. */
|
|
204
455
|
interface StatusDocument {
|
|
205
456
|
state: 'signed-in' | 'signed-out' | 'expired';
|
|
@@ -220,6 +471,10 @@ interface StatusDocument {
|
|
|
220
471
|
}[];
|
|
221
472
|
/** Whether a catalog refresh is in flight. */
|
|
222
473
|
refreshing?: boolean;
|
|
474
|
+
/** The account's credit balance, when it could be read. */
|
|
475
|
+
credits?: CreditStatus;
|
|
476
|
+
/** What this host's requests have used. */
|
|
477
|
+
usage?: UsageStatus;
|
|
223
478
|
}
|
|
224
479
|
/** Inputs the document is derived from. */
|
|
225
480
|
interface StatusDeps {
|
|
@@ -238,6 +493,10 @@ interface StatusDeps {
|
|
|
238
493
|
contextWindow: number;
|
|
239
494
|
}[];
|
|
240
495
|
refreshing: boolean;
|
|
496
|
+
/** The account's credit balance, when the account API could be reached. */
|
|
497
|
+
credits?: CreditStatus;
|
|
498
|
+
/** What this host's requests have used. */
|
|
499
|
+
usage?: UsageStatus;
|
|
241
500
|
}
|
|
242
501
|
/**
|
|
243
502
|
* Build the card's status document.
|
|
@@ -263,10 +522,23 @@ interface AdapterOptions {
|
|
|
263
522
|
* model descriptors that carry it are built inside `getModels()`.
|
|
264
523
|
*/
|
|
265
524
|
bearerToken: () => string | undefined;
|
|
525
|
+
/**
|
|
526
|
+
* Called with the usage the gateway reported for a finished request.
|
|
527
|
+
*
|
|
528
|
+
* The counters come from the upstream response, not from an estimate of the
|
|
529
|
+
* transcript, so what is reported is what was actually billed.
|
|
530
|
+
*/
|
|
531
|
+
onUsage?: (model: string, usage: ModelUsage) => void;
|
|
266
532
|
}
|
|
267
533
|
/** What {@link createMinimaxCodeAdapter} hands back. */
|
|
268
534
|
interface AdapterBundle {
|
|
269
|
-
|
|
535
|
+
/**
|
|
536
|
+
* The adapter the host registers.
|
|
537
|
+
*
|
|
538
|
+
* It is the pi-ai adapter itself, or a wrapper around it that copies the
|
|
539
|
+
* usage counters out of the stream.
|
|
540
|
+
*/
|
|
541
|
+
adapter: LlmAdapter;
|
|
270
542
|
/** Drop cached profiles so the next pick rebuilds them. */
|
|
271
543
|
invalidate: () => void;
|
|
272
544
|
}
|
|
@@ -297,4 +569,4 @@ declare const inject: string[];
|
|
|
297
569
|
*/
|
|
298
570
|
declare function apply(ctx: Context): void;
|
|
299
571
|
//#endregion
|
|
300
|
-
export { type AuthState, type CatalogModel, type CatalogSource, type Credential, FALLBACK_MODELS, MINIMAXCODE_PROVIDER_ID, MINIMAX_AUTH_FILENAME, MINIMAX_DATA_DIR, MINIMAX_GATEWAYS, MINIMAX_REGIONS, MINIMAX_STATUS_PATH, MINIMAX_STREAM_IDLE_TIMEOUT_MS, MinimaxCatalog, type MinimaxRegion, type StatusDocument, type TokenClaims, apply, authPath, bearerToken, catalogUrl, chatBaseUrl, createMinimaxCodeAdapter, dataDir, daysRemaining, decodeClaims, expiresInMs, expiryLevel, inject, name, parseAuthDocument, parseCatalog, readCredential, statusDocument };
|
|
572
|
+
export { type AuthState, type CatalogModel, type CatalogSource, type Credential, type CreditSummary, EMPTY_USAGE, FALLBACK_MODELS, MEMBERSHIP_PATH, MINIMAXCODE_PROVIDER_ID, MINIMAX_AUTH_FILENAME, MINIMAX_DATA_DIR, MINIMAX_GATEWAYS, MINIMAX_OAUTH_CLIENT_ID, MINIMAX_REGIONS, MINIMAX_STATUS_PATH, MINIMAX_STREAM_IDLE_TIMEOUT_MS, MODEL_PRICES, MinimaxCatalog, MinimaxCredits, type MinimaxRegion, type ModelUsage, type OAuthCredential, type OAuthState, type StatusDocument, type TokenClaims, UsageMeter, apply, authPath, bearerToken, catalogUrl, chatBaseUrl, createMinimaxCodeAdapter, dataDir, daysRemaining, decodeClaims, ensureOAuthCredential, estimateCny, expiresInMs, expiryLevel, fetchCreditSummary, inject, name, parseAuthDocument, parseCatalog, parseCreditSummary, parseOAuthDocument, priceFor, readCredential, readOAuthCredential, refreshOAuthCredential, statusDocument, writeOAuthCredential };
|