dsh-oauth-login 0.2.4
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/INSTALL.md +59 -0
- package/INSTALL.zh.md +45 -0
- package/LICENSE +201 -0
- package/README.en.md +104 -0
- package/README.md +104 -0
- package/README.zh.md +3 -0
- package/SECURITY.md +33 -0
- package/cordis.patch.yml +5 -0
- package/docs/network-proxy.md +45 -0
- package/docs/openrouter-sync.md +84 -0
- package/docs/screenshots/01-providers-signed-out.png +0 -0
- package/docs/screenshots/03-copilot-signing-in.png +0 -0
- package/docs/screenshots/04-mixed-live-states.png +0 -0
- package/docs/screenshots/05-copilot-sign-in.gif +0 -0
- package/docs/screenshots/06-cli-status-store.png +0 -0
- package/lib/bin.d.ts +5 -0
- package/lib/bin.js +2132 -0
- package/lib/client.js +1915 -0
- package/lib/client.js.map +1 -0
- package/lib/index.d.ts +482 -0
- package/lib/index.js +3105 -0
- package/lib/invariant.d.ts +7 -0
- package/lib/invariant.js +8 -0
- package/package.json +180 -0
- package/src/adapter.ts +207 -0
- package/src/auth-routes.ts +654 -0
- package/src/auth.ts +76 -0
- package/src/bin.ts +185 -0
- package/src/catalog.ts +129 -0
- package/src/client/OpenRouterSyncStatus.tsx +66 -0
- package/src/client/PiLoginSettings.tsx +470 -0
- package/src/client/ProxySettings.tsx +123 -0
- package/src/client/SearchableModelSelect.tsx +595 -0
- package/src/client/draft-input.ts +12 -0
- package/src/client/index.tsx +71 -0
- package/src/client/locales.ts +176 -0
- package/src/client/login-input-copy.ts +34 -0
- package/src/client/login-window.ts +24 -0
- package/src/client/model-filter.ts +45 -0
- package/src/client/openrouter-store.ts +122 -0
- package/src/client/proxy-draft.ts +57 -0
- package/src/extra-models.ts +201 -0
- package/src/hosted-capture.ts +41 -0
- package/src/hosted-images.ts +154 -0
- package/src/http.ts +241 -0
- package/src/ids.ts +17 -0
- package/src/index.ts +183 -0
- package/src/invariant.ts +12 -0
- package/src/model-error-hint.ts +98 -0
- package/src/native-tools.ts +442 -0
- package/src/oauth-refresh.ts +49 -0
- package/src/openrouter-catalog.ts +245 -0
- package/src/openrouter-free.ts +76 -0
- package/src/openrouter-models.ts +155 -0
- package/src/openrouter-types.ts +40 -0
- package/src/plugin-config.ts +30 -0
- package/src/provider.ts +137 -0
- package/src/proxy-config.ts +61 -0
- package/src/proxy-store.ts +45 -0
- package/src/proxy-transport.ts +220 -0
- package/src/redact.ts +22 -0
- package/src/responses-tap.ts +97 -0
- package/src/session.ts +104 -0
- package/src/store.ts +234 -0
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
import { LlmFailure, Message, RetryPolicyConfig, StreamChunk } from "@deepseek-ai/dsh-llm";
|
|
2
|
+
import { Api, AuthInteraction, AuthOperationOptions, Context, Credential, CredentialInfo, CredentialStore, Model, MutableModels, Provider, StreamOptions } from "@earendil-works/pi-ai";
|
|
3
|
+
import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
4
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
|
+
import { EnvHttpProxyAgent } from "undici";
|
|
6
|
+
import z from "@deepseek-ai/schemastery";
|
|
7
|
+
import { Context as Context$1 } from "@deepseek-ai/cordis";
|
|
8
|
+
import { AttachmentStore, ImageAttachmentRef, ImageMediaType, SaveImageAttachment } from "@deepseek-ai/dsh-attachment";
|
|
9
|
+
//#region src/plugin-config.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* `retryPolicy` is executed by shipped `dsh-llm-retry`, not by this plugin.
|
|
12
|
+
* Omission keeps the RC8 official normal default (5 retries for TIMEOUT /
|
|
13
|
+
* TRANSPORT / SERVER / RATE_LIMIT / EMPTY_RESPONSE).
|
|
14
|
+
*/
|
|
15
|
+
interface Config {
|
|
16
|
+
streamIdleTimeoutMs?: number;
|
|
17
|
+
retryPolicy?: RetryPolicyConfig;
|
|
18
|
+
/**
|
|
19
|
+
* Hide DSH web_search / web_fetch on OAuth routes that already have hosted
|
|
20
|
+
* search, and attach those hosted tools to the provider request.
|
|
21
|
+
*/
|
|
22
|
+
nativeTools?: boolean;
|
|
23
|
+
/** Also attach hosted image generation on Grok and Codex. */
|
|
24
|
+
nativeImage?: boolean;
|
|
25
|
+
}
|
|
26
|
+
declare const Config: z<Config>;
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/catalog.d.ts
|
|
29
|
+
/** OAuth subscriptions Pi Agent exposes via /login. Radius is omitted (needs a gateway). */
|
|
30
|
+
interface PiLoginProvider {
|
|
31
|
+
/** pi-ai provider id used by models.login(). */
|
|
32
|
+
readonly id: string;
|
|
33
|
+
/** Harness LLM route. Distinct from catalog routes and from other plugins. */
|
|
34
|
+
readonly route: string;
|
|
35
|
+
/** Credential method this plugin deliberately exposes for this provider. */
|
|
36
|
+
readonly authType: 'oauth' | 'api_key';
|
|
37
|
+
/** Official account page opened before an interactive API-key prompt. */
|
|
38
|
+
readonly loginUrl?: string;
|
|
39
|
+
readonly displayName: string;
|
|
40
|
+
readonly shortName: string;
|
|
41
|
+
readonly blurb: string;
|
|
42
|
+
readonly blurbZh: string;
|
|
43
|
+
/** HTTPS hosts this provider is allowed to open during login. */
|
|
44
|
+
readonly allowedHosts: readonly string[];
|
|
45
|
+
/** Extra allowed host suffixes (leading-dot match). */
|
|
46
|
+
readonly allowedSuffixes: readonly string[];
|
|
47
|
+
readonly preferredModels: readonly string[];
|
|
48
|
+
}
|
|
49
|
+
declare const PI_LOGIN_PROVIDERS: readonly PiLoginProvider[];
|
|
50
|
+
declare function piLoginProvider(id: string): PiLoginProvider | undefined;
|
|
51
|
+
declare function piLoginRoutes(): string[];
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/http.d.ts
|
|
54
|
+
type OAuthProxyResolution = {
|
|
55
|
+
source: 'environment';
|
|
56
|
+
} | {
|
|
57
|
+
source: 'explicit' | 'system' | 'loopback';
|
|
58
|
+
proxyUrl: string;
|
|
59
|
+
} | {
|
|
60
|
+
source: 'direct';
|
|
61
|
+
};
|
|
62
|
+
interface OAuthProxyDiscoveryOptions {
|
|
63
|
+
env?: NodeJS.ProcessEnv;
|
|
64
|
+
platform?: NodeJS.Platform;
|
|
65
|
+
readSystemProxy?: () => Promise<string | undefined>;
|
|
66
|
+
probe?: (proxyUrl: string) => Promise<boolean>;
|
|
67
|
+
candidates?: readonly string[];
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/proxy-config.d.ts
|
|
71
|
+
interface ProxyChannelSettings {
|
|
72
|
+
/** False means direct, even when proxy environment variables are set. */
|
|
73
|
+
enabled: boolean;
|
|
74
|
+
/** Empty keeps environment/system discovery; otherwise this URL wins. */
|
|
75
|
+
url: string;
|
|
76
|
+
}
|
|
77
|
+
interface ProxySettings {
|
|
78
|
+
http: ProxyChannelSettings;
|
|
79
|
+
websocket: ProxyChannelSettings;
|
|
80
|
+
}
|
|
81
|
+
interface ProxySettingsSnapshot extends ProxySettings {
|
|
82
|
+
revision: number;
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/proxy-store.d.ts
|
|
86
|
+
declare class ProxySettingsStore {
|
|
87
|
+
readonly filename: string;
|
|
88
|
+
constructor(filename: string);
|
|
89
|
+
read(): Promise<ProxySettingsSnapshot>;
|
|
90
|
+
save(value: unknown): Promise<ProxySettingsSnapshot>;
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/proxy-transport.d.ts
|
|
94
|
+
declare class OAuthProxyTransport {
|
|
95
|
+
private readonly discovery;
|
|
96
|
+
readonly settings: ProxySettingsStore;
|
|
97
|
+
private readyPromise?;
|
|
98
|
+
private readonly generations;
|
|
99
|
+
private readonly sessions;
|
|
100
|
+
private disposed;
|
|
101
|
+
constructor(filename: string, discovery?: OAuthProxyDiscoveryOptions);
|
|
102
|
+
private build;
|
|
103
|
+
private ready;
|
|
104
|
+
initialize(): Promise<OAuthProxyResolution>;
|
|
105
|
+
private acquire;
|
|
106
|
+
save(value: unknown): Promise<ProxySettingsSnapshot>;
|
|
107
|
+
private release;
|
|
108
|
+
run<T>(operation: () => Promise<T>): Promise<T>;
|
|
109
|
+
private beginSession;
|
|
110
|
+
iterate<T>(source: AsyncIterable<T>, codexSessionId?: string): AsyncIterable<T>;
|
|
111
|
+
dispose(): Promise<void>;
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/native-tools.d.ts
|
|
115
|
+
interface NativeToolPolicy {
|
|
116
|
+
/** Attach hosted tools and hide DSH web_search / web_fetch. Default true. */
|
|
117
|
+
enabled: boolean;
|
|
118
|
+
/** Also attach hosted image generation where the provider documents it. Default true. */
|
|
119
|
+
image: boolean;
|
|
120
|
+
}
|
|
121
|
+
declare const DEFAULT_NATIVE_TOOL_POLICY: NativeToolPolicy;
|
|
122
|
+
interface NativeToolPlan {
|
|
123
|
+
readonly providerId: string;
|
|
124
|
+
readonly api: string;
|
|
125
|
+
readonly hosted: readonly Record<string, unknown>[];
|
|
126
|
+
readonly guidance: string;
|
|
127
|
+
}
|
|
128
|
+
declare function nativePlan(providerId: string, api: string | undefined, policy?: NativeToolPolicy): NativeToolPlan | undefined;
|
|
129
|
+
declare function nativePlanForRoute(route: string | undefined, api: string | undefined, policy?: NativeToolPolicy): NativeToolPlan | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* xAI's Responses stream currently exposes server-executed X Search details
|
|
132
|
+
* as custom tool calls. The outer `xs_call-*` id distinguishes those traces
|
|
133
|
+
* from a same-named client function, which Harness must still execute.
|
|
134
|
+
*/
|
|
135
|
+
declare function isXaiServerXSearchCall(block: unknown): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Server-executed hosted search / image traces that Harness must not try to run.
|
|
138
|
+
* X Search leaks use `xs_call-*`. DSH `web_search` / `web_fetch` were stripped
|
|
139
|
+
* from this route, so a leftover same-named call is also a leak.
|
|
140
|
+
*/
|
|
141
|
+
declare function isHostedServerToolCall(block: unknown): boolean;
|
|
142
|
+
/**
|
|
143
|
+
* xAI hosted search hops arrive as empty `reasoning` blocks whose signature
|
|
144
|
+
* id is `tco_<response>_call-…`. The UI renders each as a blank Think card.
|
|
145
|
+
*/
|
|
146
|
+
declare function isHostedSearchReasoningReplay(block: unknown): boolean;
|
|
147
|
+
/**
|
|
148
|
+
* Remove hosted server-side search / image traces after pi-ai 0.82.1 has
|
|
149
|
+
* mistaken them for client function calls. Other blocks retain stream order,
|
|
150
|
+
* actual client tools survive, and pi-ai replay metadata stays index-aligned.
|
|
151
|
+
*/
|
|
152
|
+
declare function filterHostedServerToolTraces(source: AsyncIterable<StreamChunk>): AsyncGenerator<StreamChunk>;
|
|
153
|
+
/** @deprecated Use {@link filterHostedServerToolTraces}. */
|
|
154
|
+
declare const filterXaiServerToolTraces: typeof filterHostedServerToolTraces;
|
|
155
|
+
declare function applyNativeToolsToPayload(payload: unknown, providerId: string, api: string | undefined, policy?: NativeToolPolicy): unknown;
|
|
156
|
+
/**
|
|
157
|
+
* Prepare one provider request as a single unit.
|
|
158
|
+
*
|
|
159
|
+
* Native tools are a property of this request, not of the provider account.
|
|
160
|
+
* A context without tools is a text-only call (reviewers, summaries, titles,
|
|
161
|
+
* and similar utility traffic), so its payload hook must stay untouched even
|
|
162
|
+
* when the provider serializer later emits `tools: []`.
|
|
163
|
+
*/
|
|
164
|
+
declare function prepareNativeToolRequest<TOptions extends StreamOptions>(context: Context, options: TOptions, providerId: string, api: string | undefined, policy?: NativeToolPolicy): {
|
|
165
|
+
context: Context;
|
|
166
|
+
options: TOptions & StreamOptions;
|
|
167
|
+
};
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/store.d.ts
|
|
170
|
+
declare function piLoginAuthPath(dshHome?: string): string;
|
|
171
|
+
declare class PiLoginCredentialStore implements CredentialStore {
|
|
172
|
+
readonly filename: string;
|
|
173
|
+
readonly legacyFilename: string | undefined;
|
|
174
|
+
constructor(filename?: string);
|
|
175
|
+
private readDocument;
|
|
176
|
+
read(providerId: string, options?: AuthOperationOptions): Promise<Credential | undefined>;
|
|
177
|
+
list(options?: AuthOperationOptions): Promise<readonly CredentialInfo[]>;
|
|
178
|
+
modify(providerId: string, fn: (current: Credential | undefined) => Promise<Credential | undefined>, options?: AuthOperationOptions): Promise<Credential | undefined>;
|
|
179
|
+
delete(providerId: string, options?: AuthOperationOptions): Promise<void>;
|
|
180
|
+
}
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/openrouter-types.d.ts
|
|
183
|
+
interface OpenRouterModel {
|
|
184
|
+
id: string;
|
|
185
|
+
name: string;
|
|
186
|
+
contextWindow: number;
|
|
187
|
+
maxTokens: number;
|
|
188
|
+
inputModalities: string[];
|
|
189
|
+
outputModalities: string[];
|
|
190
|
+
supportedParameters: string[];
|
|
191
|
+
tools: boolean;
|
|
192
|
+
reasoning: boolean;
|
|
193
|
+
reasoningMandatory: boolean;
|
|
194
|
+
supportedEfforts?: string[];
|
|
195
|
+
defaultEffort?: string;
|
|
196
|
+
/** USD per token/unit as supplied by the official catalog, not pi-ai costs. */
|
|
197
|
+
pricing: Record<string, string>;
|
|
198
|
+
priceStatus: 'free' | 'paid' | 'unknown';
|
|
199
|
+
/** Endpoint deprecation, NEVER interpreted as a promotion deadline. */
|
|
200
|
+
deprecatesAt?: string;
|
|
201
|
+
}
|
|
202
|
+
interface OpenRouterCatalogSnapshot {
|
|
203
|
+
version: 1;
|
|
204
|
+
connected: boolean;
|
|
205
|
+
refreshing: boolean;
|
|
206
|
+
source: 'builtin' | 'cache' | 'live';
|
|
207
|
+
lastUpdatedAt: number | null;
|
|
208
|
+
lastAttemptAt: number | null;
|
|
209
|
+
nextRefreshAt: number | null;
|
|
210
|
+
retryAt: number | null;
|
|
211
|
+
stale: boolean;
|
|
212
|
+
error: 'fetch' | 'cache' | 'save' | null;
|
|
213
|
+
models: Array<OpenRouterModel & {
|
|
214
|
+
freeOnly: boolean;
|
|
215
|
+
}>;
|
|
216
|
+
}
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/openrouter-catalog.d.ts
|
|
219
|
+
interface OpenRouterCatalogOptions {
|
|
220
|
+
filename: string;
|
|
221
|
+
isAuthenticated: () => Promise<boolean>;
|
|
222
|
+
beforeFetch?: () => Promise<unknown>;
|
|
223
|
+
fetch?: typeof globalThis.fetch;
|
|
224
|
+
now?: () => number;
|
|
225
|
+
/** Protect zero-cost legacy selections too, without labelling them free. */
|
|
226
|
+
initiallyProtectedIds?: readonly string[];
|
|
227
|
+
}
|
|
228
|
+
declare class OpenRouterCatalog {
|
|
229
|
+
private readonly options;
|
|
230
|
+
private entries;
|
|
231
|
+
private protectedIds;
|
|
232
|
+
private connected;
|
|
233
|
+
private disposed;
|
|
234
|
+
private source;
|
|
235
|
+
private lastUpdatedAt;
|
|
236
|
+
private lastAttemptAt;
|
|
237
|
+
private nextRefreshAt;
|
|
238
|
+
private error;
|
|
239
|
+
private hydration;
|
|
240
|
+
private pending;
|
|
241
|
+
private controller;
|
|
242
|
+
private timer;
|
|
243
|
+
private generation;
|
|
244
|
+
private readonly listeners;
|
|
245
|
+
private readonly now;
|
|
246
|
+
constructor(options: OpenRouterCatalogOptions);
|
|
247
|
+
models(): readonly OpenRouterModel[] | undefined;
|
|
248
|
+
model(id: string): OpenRouterModel | undefined;
|
|
249
|
+
protects(id: string): boolean;
|
|
250
|
+
subscribe(listener: () => void): () => void;
|
|
251
|
+
private changed;
|
|
252
|
+
snapshot(): OpenRouterCatalogSnapshot;
|
|
253
|
+
private hydrate;
|
|
254
|
+
private readCache;
|
|
255
|
+
private rememberFree;
|
|
256
|
+
/** Startup reads disk first; only a newly completed login forces a refresh. */
|
|
257
|
+
syncAuthentication(reason?: 'check' | 'login'): Promise<void>;
|
|
258
|
+
/** Coalesced across routes/windows; even forced refreshes honor 60s cooldown. */
|
|
259
|
+
refresh(force?: boolean): Promise<void>;
|
|
260
|
+
private fetchCatalog;
|
|
261
|
+
private schedule;
|
|
262
|
+
disconnect(): void;
|
|
263
|
+
dispose(): void;
|
|
264
|
+
}
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/session.d.ts
|
|
267
|
+
declare class PiLoginSession {
|
|
268
|
+
readonly store: PiLoginCredentialStore;
|
|
269
|
+
readonly models: MutableModels;
|
|
270
|
+
readonly native: NativeToolPolicy;
|
|
271
|
+
readonly openRouter: OpenRouterCatalog;
|
|
272
|
+
readonly proxy: OAuthProxyTransport;
|
|
273
|
+
constructor(store?: PiLoginCredentialStore, native?: NativeToolPolicy, catalogOptions?: Partial<Pick<OpenRouterCatalogOptions, 'fetch' | 'now' | 'filename'>>, proxyDiscovery?: OAuthProxyDiscoveryOptions);
|
|
274
|
+
ensureTransport(): Promise<OAuthProxyResolution>;
|
|
275
|
+
spec(id: string): PiLoginProvider;
|
|
276
|
+
provider(id: string): import("@earendil-works/pi-ai").Provider<import("@earendil-works/pi-ai").Api>;
|
|
277
|
+
visibleModels(id: string): readonly import("@earendil-works/pi-ai").Model<import("@earendil-works/pi-ai").Api>[];
|
|
278
|
+
/**
|
|
279
|
+
* Harness routes that currently hold a stored OAuth grant.
|
|
280
|
+
* Model pickers should only advertise these — logging out must drop the route.
|
|
281
|
+
*/
|
|
282
|
+
authenticatedRoutes(): Promise<string[]>;
|
|
283
|
+
logout(id: string): Promise<void>;
|
|
284
|
+
/**
|
|
285
|
+
* Renew access tokens that are expired or close to expiry.
|
|
286
|
+
* Failures stay in the store; the next poll or chat retries.
|
|
287
|
+
*/
|
|
288
|
+
refreshStoredGrants(now?: number): Promise<void>;
|
|
289
|
+
}
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region src/adapter.d.ts
|
|
292
|
+
interface PiLoginAdapterOptions {
|
|
293
|
+
streamIdleTimeoutMs?: number;
|
|
294
|
+
retryPolicy?: RetryPolicyConfig;
|
|
295
|
+
}
|
|
296
|
+
declare function createPiLoginAdapter(session: PiLoginSession, resolveAttachments: () => AttachmentStore | undefined, options?: PiLoginAdapterOptions): PiAiAdapter;
|
|
297
|
+
//#endregion
|
|
298
|
+
//#region src/auth.d.ts
|
|
299
|
+
interface PiLoginAuthStatus {
|
|
300
|
+
providerId: string;
|
|
301
|
+
authenticated: boolean;
|
|
302
|
+
credentialType?: 'oauth' | 'api_key';
|
|
303
|
+
expiresAt?: Date;
|
|
304
|
+
}
|
|
305
|
+
declare function loginPiProvider(providerId: string, interaction: AuthInteraction, store?: PiLoginCredentialStore): Promise<void>;
|
|
306
|
+
declare function logoutPiProvider(providerId: string, store?: PiLoginCredentialStore): Promise<void>;
|
|
307
|
+
declare function piLoginStatus(store?: PiLoginCredentialStore, providerId?: string): Promise<PiLoginAuthStatus[]>;
|
|
308
|
+
declare function loginPiProviderSession(providerId: string, interaction: AuthInteraction, session: PiLoginSession): Promise<void>;
|
|
309
|
+
//#endregion
|
|
310
|
+
//#region src/auth-routes.d.ts
|
|
311
|
+
declare const PI_LOGIN_AUTH_STATUS_PATH = "/plugins/dsh-oauth-login/auth/status";
|
|
312
|
+
declare const PI_LOGIN_AUTH_LOGIN_PATH = "/plugins/dsh-oauth-login/auth/login";
|
|
313
|
+
declare const PI_LOGIN_AUTH_CANCEL_PATH = "/plugins/dsh-oauth-login/auth/cancel";
|
|
314
|
+
declare const PI_LOGIN_AUTH_COMPLETE_PATH = "/plugins/dsh-oauth-login/auth/complete";
|
|
315
|
+
declare const PI_LOGIN_AUTH_LOGOUT_PATH = "/plugins/dsh-oauth-login/auth/logout";
|
|
316
|
+
interface LoginInputChallenge {
|
|
317
|
+
type: 'secret' | 'text' | 'manual_code';
|
|
318
|
+
message: string;
|
|
319
|
+
placeholder?: string;
|
|
320
|
+
}
|
|
321
|
+
type PiLoginAccountState = {
|
|
322
|
+
status: 'signed-out';
|
|
323
|
+
} | {
|
|
324
|
+
status: 'signing-in';
|
|
325
|
+
kind?: 'browser' | 'input';
|
|
326
|
+
url?: string;
|
|
327
|
+
userCode?: string;
|
|
328
|
+
input?: LoginInputChallenge;
|
|
329
|
+
} | {
|
|
330
|
+
status: 'signed-in';
|
|
331
|
+
models: string[];
|
|
332
|
+
expiresAt?: string;
|
|
333
|
+
} | {
|
|
334
|
+
status: 'error';
|
|
335
|
+
message: string;
|
|
336
|
+
};
|
|
337
|
+
interface PiLoginProviderStatus {
|
|
338
|
+
id: string;
|
|
339
|
+
route: string;
|
|
340
|
+
displayName: string;
|
|
341
|
+
shortName: string;
|
|
342
|
+
authType: PiLoginProvider['authType'];
|
|
343
|
+
account: PiLoginAccountState;
|
|
344
|
+
}
|
|
345
|
+
interface LoginChallenge {
|
|
346
|
+
provider: string;
|
|
347
|
+
kind: 'browser' | 'input';
|
|
348
|
+
url?: string;
|
|
349
|
+
userCode?: string;
|
|
350
|
+
input?: LoginInputChallenge;
|
|
351
|
+
}
|
|
352
|
+
interface PiLoginAuthRouteOptions {
|
|
353
|
+
/** Called after a successful sign-in or sign-out so the host can refresh LLM routes. */
|
|
354
|
+
onAuthChanged?: () => void | Promise<void>;
|
|
355
|
+
}
|
|
356
|
+
declare function registerPiLoginAuthRoutes(ctx: Context$1, session: PiLoginSession, options?: PiLoginAuthRouteOptions): void;
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region src/extra-models.d.ts
|
|
359
|
+
declare const GLM_5_3_DEFAULT_EFFORT = "max";
|
|
360
|
+
declare const GLM_5_3_FLASH_DEFAULT_EFFORT = "max";
|
|
361
|
+
/** OpenRouter stealth model missing from the installed pi-ai catalog (0.82.x–0.84.x). */
|
|
362
|
+
declare const OX_ALPHA_MODEL_ID = "stealth/ox-alpha";
|
|
363
|
+
/**
|
|
364
|
+
* OpenRouter's live default for ox-alpha (`reasoning.default_effort`).
|
|
365
|
+
* Must be sent explicitly: pi-ai's OpenRouter dialect writes
|
|
366
|
+
* `reasoning: { effort: thinkingLevelMap.off ?? "none" }` when the caller
|
|
367
|
+
* omits an effort, and ox-alpha rejects `none` (`reasoning.mandatory: true`).
|
|
368
|
+
*/
|
|
369
|
+
declare const OX_ALPHA_DEFAULT_EFFORT = "max";
|
|
370
|
+
/** Per-model default the selector and request path should apply when omitted. */
|
|
371
|
+
declare function defaultReasoningEffortFor(modelId: string): typeof OX_ALPHA_DEFAULT_EFFORT | typeof GLM_5_3_DEFAULT_EFFORT | typeof GLM_5_3_FLASH_DEFAULT_EFFORT | 'medium' | undefined;
|
|
372
|
+
/**
|
|
373
|
+
* Extra models this plugin publishes for one pi-ai provider id.
|
|
374
|
+
* @param providerId - catalog provider id (e.g. `xai`), not the harness route.
|
|
375
|
+
*/
|
|
376
|
+
declare function extraModelsFor(providerId: string): readonly Model<Api>[];
|
|
377
|
+
//#endregion
|
|
378
|
+
//#region src/hosted-capture.d.ts
|
|
379
|
+
interface HostedImage {
|
|
380
|
+
id?: string;
|
|
381
|
+
base64: string;
|
|
382
|
+
}
|
|
383
|
+
interface HostedCapture {
|
|
384
|
+
images: HostedImage[];
|
|
385
|
+
}
|
|
386
|
+
//#endregion
|
|
387
|
+
//#region src/hosted-images.d.ts
|
|
388
|
+
declare function sniffImageMediaType(bytes: Uint8Array): ImageMediaType | undefined;
|
|
389
|
+
declare function collectHostedImagesFromEvent(event: unknown, into: HostedImage[]): void;
|
|
390
|
+
declare function decodeHostedImage(base64: string): {
|
|
391
|
+
data: Uint8Array;
|
|
392
|
+
mediaType: ImageMediaType;
|
|
393
|
+
} | undefined;
|
|
394
|
+
/**
|
|
395
|
+
* pi-ai replay cannot represent assistant ImageBlocks. Drop them before the
|
|
396
|
+
* next request so replay metadata still lines up with remaining content.
|
|
397
|
+
*/
|
|
398
|
+
declare function stripAssistantImages(messages: readonly Message[]): Message[];
|
|
399
|
+
declare function injectHostedImages(source: AsyncIterable<StreamChunk>, capture: HostedCapture, save: (input: SaveImageAttachment) => Promise<ImageAttachmentRef>): AsyncGenerator<StreamChunk>;
|
|
400
|
+
//#endregion
|
|
401
|
+
//#region src/oauth-refresh.d.ts
|
|
402
|
+
/**
|
|
403
|
+
* When to spend a refresh_token. Chat already refreshes via Models.getAuth;
|
|
404
|
+
* this helper is for status / boot / the host timer so the store does not sit
|
|
405
|
+
* on a stale expires stamp.
|
|
406
|
+
*/
|
|
407
|
+
/** Refresh when the stored access stamp is inside this window (Pi already skews expires by 5 min). */
|
|
408
|
+
declare const OAUTH_REFRESH_SOON_MS: number;
|
|
409
|
+
/** Host timer. Access lives ~6h; this is just how often we look. */
|
|
410
|
+
declare const OAUTH_REFRESH_POLL_MS: number;
|
|
411
|
+
declare function grantNeedsRefresh(expires: number, now?: number): boolean;
|
|
412
|
+
//#endregion
|
|
413
|
+
//#region src/ids.d.ts
|
|
414
|
+
/** Basename of the DSH-owned multi-provider OAuth document. */
|
|
415
|
+
declare const PI_LOGIN_AUTH_FILENAME = ".dsh-oauth-auth.json";
|
|
416
|
+
/** Legacy DSH filename accepted during the one-time storage migration. */
|
|
417
|
+
declare const LEGACY_PI_LOGIN_AUTH_FILENAME = ".pi-login-auth.json";
|
|
418
|
+
/** Prefix for harness routes so they never collide with catalog / other plugins. */
|
|
419
|
+
declare const PI_LOGIN_ROUTE_PREFIX = "pi-";
|
|
420
|
+
/** Provider idle ceiling used by every composite route. */
|
|
421
|
+
declare const PI_LOGIN_STREAM_IDLE_TIMEOUT_MS = 300000;
|
|
422
|
+
/** Startup line `dshx verify` looks for. */
|
|
423
|
+
declare const PI_LOGIN_BOOT_MARKER = "[my-plugins/dsh-oauth-login] loaded";
|
|
424
|
+
//#endregion
|
|
425
|
+
//#region src/model-error-hint.d.ts
|
|
426
|
+
/**
|
|
427
|
+
* Default Harness `retryPolicy` codes. Keep aligned with
|
|
428
|
+
* `resolveRetryPolicy(undefined)` in `@deepseek-ai/dsh-llm`.
|
|
429
|
+
*/
|
|
430
|
+
declare const TRANSIENT_MODEL_CODES: readonly string[];
|
|
431
|
+
declare const QUOTA_HINT = "This is account quota or credits, not a temporary busy signal. Automatic retry will not refill it. Check the plan, usage window, or balance.";
|
|
432
|
+
declare const RATE_LIMIT_HINT = "This is a request-rate or peak-busy limit. A 429 is often this, not an empty balance. After automatic retries end, wait and send another message. If Continue fails or the composer stays stuck, start a new chat.";
|
|
433
|
+
declare const TRANSIENT_HINT = "After this turn ends, send another message to try again. If Continue fails or the composer stays stuck, start a new chat.";
|
|
434
|
+
/** Stable Chat copy for one official `LlmError` code. Does not invent 5h vs weekly vs billing. */
|
|
435
|
+
declare function hintForCode(code: string): string | undefined;
|
|
436
|
+
/** Normalize known provider gaps before the official retry executor receives this failure. */
|
|
437
|
+
declare function hintFailure(failure: LlmFailure, provider?: string): LlmFailure;
|
|
438
|
+
/** Apply the same provider correction and hint to thrown failures, preserving diagnostics. */
|
|
439
|
+
declare function withModelErrorHint(error: unknown, provider?: string): unknown;
|
|
440
|
+
//#endregion
|
|
441
|
+
//#region src/provider.d.ts
|
|
442
|
+
declare function catalogProvider(id: string): Provider;
|
|
443
|
+
declare function harnessModels(spec: PiLoginProvider, catalog?: OpenRouterCatalog): Model<Api>[];
|
|
444
|
+
declare function preferredModel(spec: PiLoginProvider, models?: readonly {
|
|
445
|
+
id: string;
|
|
446
|
+
}[]): string;
|
|
447
|
+
declare function harnessProvider(spec: PiLoginProvider, native?: NativeToolPolicy, catalog?: OpenRouterCatalog): Provider;
|
|
448
|
+
//#endregion
|
|
449
|
+
//#region src/redact.d.ts
|
|
450
|
+
/** Remove token-like strings from an external OAuth diagnostic. */
|
|
451
|
+
declare function safeMessage(error: unknown): string;
|
|
452
|
+
/** Only this provider's official HTTPS hosts may be opened for login. */
|
|
453
|
+
declare function isSafeAuthUrl(raw: string, provider: PiLoginProvider): boolean;
|
|
454
|
+
//#endregion
|
|
455
|
+
//#region src/index.d.ts
|
|
456
|
+
type NativeAssembly = {
|
|
457
|
+
tools: {
|
|
458
|
+
name: string;
|
|
459
|
+
}[];
|
|
460
|
+
sections: {
|
|
461
|
+
name: string;
|
|
462
|
+
text: string;
|
|
463
|
+
}[];
|
|
464
|
+
};
|
|
465
|
+
type NativeAssembleContext = {
|
|
466
|
+
agent?: {
|
|
467
|
+
options?: {
|
|
468
|
+
provider?: string;
|
|
469
|
+
model?: string;
|
|
470
|
+
};
|
|
471
|
+
};
|
|
472
|
+
};
|
|
473
|
+
declare module '@deepseek-ai/cordis' {
|
|
474
|
+
interface Events {
|
|
475
|
+
'system-prompt/assemble'(assembly: NativeAssembly, context: NativeAssembleContext, next: () => Promise<NativeAssembly>): Promise<NativeAssembly>;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
declare const name = "llm-oauth-login";
|
|
479
|
+
declare const inject: string[];
|
|
480
|
+
declare function apply(ctx: Context$1, config: Config): void;
|
|
481
|
+
//#endregion
|
|
482
|
+
export { Config, type Config as PluginConfig, DEFAULT_NATIVE_TOOL_POLICY, LEGACY_PI_LOGIN_AUTH_FILENAME, type LoginChallenge, type LoginInputChallenge, type NativeToolPlan, type NativeToolPolicy, OAUTH_REFRESH_POLL_MS, OAUTH_REFRESH_SOON_MS, OX_ALPHA_DEFAULT_EFFORT, OX_ALPHA_MODEL_ID, PI_LOGIN_AUTH_CANCEL_PATH, PI_LOGIN_AUTH_COMPLETE_PATH, PI_LOGIN_AUTH_FILENAME, PI_LOGIN_AUTH_LOGIN_PATH, PI_LOGIN_AUTH_LOGOUT_PATH, PI_LOGIN_AUTH_STATUS_PATH, PI_LOGIN_BOOT_MARKER, PI_LOGIN_PROVIDERS, PI_LOGIN_ROUTE_PREFIX, PI_LOGIN_STREAM_IDLE_TIMEOUT_MS, type PiLoginAdapterOptions, type PiLoginAuthStatus, PiLoginCredentialStore, type PiLoginProvider, type PiLoginProviderStatus, PiLoginSession, QUOTA_HINT, RATE_LIMIT_HINT, TRANSIENT_HINT, TRANSIENT_MODEL_CODES, apply, applyNativeToolsToPayload, catalogProvider, collectHostedImagesFromEvent, createPiLoginAdapter, decodeHostedImage, defaultReasoningEffortFor, extraModelsFor, filterHostedServerToolTraces, filterXaiServerToolTraces, grantNeedsRefresh, harnessModels, harnessProvider, hintFailure, hintForCode, inject, injectHostedImages, isHostedSearchReasoningReplay, isHostedServerToolCall, isSafeAuthUrl, isXaiServerXSearchCall, loginPiProvider, loginPiProviderSession, logoutPiProvider, name, nativePlan, nativePlanForRoute, piLoginAuthPath, piLoginProvider, piLoginRoutes, piLoginStatus, preferredModel, prepareNativeToolRequest, registerPiLoginAuthRoutes, safeMessage, sniffImageMediaType, stripAssistantImages, withModelErrorHint };
|