dsh-plugin-subscription-oauth 0.2.1 → 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 +14 -1
- package/README.zh.md +371 -0
- package/lib/auth/ark-control.d.ts +180 -0
- package/lib/auth/ark-control.js +304 -0
- package/lib/auth/ark-flow.d.ts +134 -0
- package/lib/auth/ark-flow.js +239 -0
- package/lib/client/SubscriptionsSection.js +1 -9
- package/lib/client.js +1 -5
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.js +15 -2
- package/lib/providers/ark-provider.d.ts +42 -0
- package/lib/providers/ark-provider.js +166 -0
- package/lib/providers/ark.d.ts +154 -0
- package/lib/providers/ark.js +412 -0
- package/lib/providers/auto.js +16 -0
- package/lib/providers/usage.js +49 -4
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -21,15 +21,16 @@ import { createAntigravityProvider } from './providers/antigravity.js';
|
|
|
21
21
|
import { createGrokProvider } from './providers/grok.js';
|
|
22
22
|
import { createKimiProvider } from './providers/kimi-provider.js';
|
|
23
23
|
import { createGlmProvider } from './providers/glm-provider.js';
|
|
24
|
+
import { createArkProvider } from './providers/ark-provider.js';
|
|
24
25
|
import { ModelPreferences } from './settings.js';
|
|
25
26
|
/** Plugin id; also the name every effect label and log line is prefixed with. */
|
|
26
27
|
export const name = 'dsh-plugin-subscription-oauth';
|
|
27
28
|
/** The provider routes need the LLM runtime; everything else is optional. */
|
|
28
29
|
export const inject = ['llm'];
|
|
29
30
|
/** Every route key this plugin accepts in configuration. */
|
|
30
|
-
export const PROVIDER_IDS = ['kimi', 'grok', 'antigravity', 'glm'];
|
|
31
|
+
export const PROVIDER_IDS = ['kimi', 'grok', 'antigravity', 'glm', 'ark'];
|
|
31
32
|
/** The routes this build can actually register. */
|
|
32
|
-
export const IMPLEMENTED_PROVIDER_IDS = ['kimi', 'grok', 'antigravity', 'glm'];
|
|
33
|
+
export const IMPLEMENTED_PROVIDER_IDS = ['kimi', 'grok', 'antigravity', 'glm', 'ark'];
|
|
33
34
|
/** Configuration schema, with the config file's own defaults applied. */
|
|
34
35
|
export const Config = z.object({
|
|
35
36
|
providers: z.array(z.union([...PROVIDER_IDS])).default([...IMPLEMENTED_PROVIDER_IDS]),
|
|
@@ -123,6 +124,18 @@ export function apply(ctx, config = {}) {
|
|
|
123
124
|
fetchFn: proxiedFetch,
|
|
124
125
|
}));
|
|
125
126
|
break;
|
|
127
|
+
case 'ark':
|
|
128
|
+
routes.push(createArkProvider({
|
|
129
|
+
credentialFile,
|
|
130
|
+
discovery: config.discovery ?? true,
|
|
131
|
+
streamIdleTimeoutMs,
|
|
132
|
+
preferences,
|
|
133
|
+
resolveAttachments: () => ctx.get('attachments'),
|
|
134
|
+
onCatalogChanged: () => { reannounce('ark'); },
|
|
135
|
+
onWarn,
|
|
136
|
+
fetchFn: proxiedFetch,
|
|
137
|
+
}));
|
|
138
|
+
break;
|
|
126
139
|
default:
|
|
127
140
|
// A configured route with no module yet must not silently disappear.
|
|
128
141
|
onWarn(`provider ${id} is configured but not implemented in this build`);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `ark` provider route's wiring: ZCode-style SSO sign-in, the control plane that
|
|
3
|
+
* mints the plan's API key, the model catalog, and the Settings card facts.
|
|
4
|
+
*
|
|
5
|
+
* Ark splits its API in two, and the route has to satisfy both:
|
|
6
|
+
*
|
|
7
|
+
* - the **data plane** (`ark.cn-beijing.volces.com`) serves the models and accepts
|
|
8
|
+
* only an ordinary **API key** as a plain bearer — it refuses STS credentials
|
|
9
|
+
* outright;
|
|
10
|
+
* - the **control plane** (`ark.cn-beijing.volcengineapi.com`) is signed with the
|
|
11
|
+
* temporary **STS** credentials the SSO token response carries, and is where the
|
|
12
|
+
* plan's API key and its allowance come from.
|
|
13
|
+
*
|
|
14
|
+
* So a sign-in produces both: the key for requests, the STS set for quota.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-plugin-subscription-oauth/providers/ark-provider
|
|
17
|
+
*/
|
|
18
|
+
import type { ProviderRoute } from '../auth/registry.js';
|
|
19
|
+
import type { ModelPreferences } from '../settings.js';
|
|
20
|
+
import type { FetchFn } from '../http.js';
|
|
21
|
+
import type { AttachmentStore } from '@deepseek-ai/dsh-attachment';
|
|
22
|
+
/** Everything the Ark route needs from the plugin configuration. */
|
|
23
|
+
export interface ArkProviderOptions {
|
|
24
|
+
credentialFile: string;
|
|
25
|
+
apiBase?: string;
|
|
26
|
+
discovery: boolean;
|
|
27
|
+
streamIdleTimeoutMs: number;
|
|
28
|
+
defaultModel?: string;
|
|
29
|
+
extraModels?: readonly string[];
|
|
30
|
+
preferences: ModelPreferences;
|
|
31
|
+
resolveAttachments?: () => AttachmentStore | undefined;
|
|
32
|
+
onCatalogChanged?: () => void;
|
|
33
|
+
onWarn?: (message: string) => void;
|
|
34
|
+
fetchFn?: FetchFn;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build the `ark` route.
|
|
38
|
+
*
|
|
39
|
+
* @param options - resolved endpoints, paths, and shared services.
|
|
40
|
+
* @returns the route, ready to register and to serve over RPC.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createArkProvider(options: ArkProviderOptions): ProviderRoute;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `ark` provider route's wiring: ZCode-style SSO sign-in, the control plane that
|
|
3
|
+
* mints the plan's API key, the model catalog, and the Settings card facts.
|
|
4
|
+
*
|
|
5
|
+
* Ark splits its API in two, and the route has to satisfy both:
|
|
6
|
+
*
|
|
7
|
+
* - the **data plane** (`ark.cn-beijing.volces.com`) serves the models and accepts
|
|
8
|
+
* only an ordinary **API key** as a plain bearer — it refuses STS credentials
|
|
9
|
+
* outright;
|
|
10
|
+
* - the **control plane** (`ark.cn-beijing.volcengineapi.com`) is signed with the
|
|
11
|
+
* temporary **STS** credentials the SSO token response carries, and is where the
|
|
12
|
+
* plan's API key and its allowance come from.
|
|
13
|
+
*
|
|
14
|
+
* So a sign-in produces both: the key for requests, the STS set for quota.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-plugin-subscription-oauth/providers/ark-provider
|
|
17
|
+
*/
|
|
18
|
+
import { REAUTH_REQUIRED, ProviderError } from '../errors.js';
|
|
19
|
+
import { TokenStore } from '../auth/store.js';
|
|
20
|
+
import { TokenManager } from '../auth/tokens.js';
|
|
21
|
+
import { LoopbackFlow } from '../auth/pkce-flow.js';
|
|
22
|
+
import { ARK_CALLBACK_PATH, ARK_CALLBACK_PORTS, buildArkAuthorizeUrl, exchangeArkCode, refreshArkToken } from '../auth/ark-flow.js';
|
|
23
|
+
import { createArkApiKey, listArkApiKeys, readArkApiKey } from '../auth/ark-control.js';
|
|
24
|
+
import { ARK_API_BASE, ARK_CODE_URL, ARK_CONTEXT_WINDOW, ARK_DEFAULT_MODEL, ARK_PROVIDER_ID, ARK_PROVIDER_NAME, ArkAdapter, parseArkSession, readArkUsage, } from './ark.js';
|
|
25
|
+
import { ProviderController } from '../auth/provider-controller.js';
|
|
26
|
+
import { proxiedFetch } from '../http.js';
|
|
27
|
+
/** The name the minted key is created under, so it is recognisable in the console. */
|
|
28
|
+
const MINTED_KEY_NAME = 'dsh-plugin-subscription-oauth';
|
|
29
|
+
/**
|
|
30
|
+
* Build the `ark` route.
|
|
31
|
+
*
|
|
32
|
+
* @param options - resolved endpoints, paths, and shared services.
|
|
33
|
+
* @returns the route, ready to register and to serve over RPC.
|
|
34
|
+
*/
|
|
35
|
+
export function createArkProvider(options) {
|
|
36
|
+
const fetchFn = options.fetchFn ?? proxiedFetch;
|
|
37
|
+
const apiBase = options.apiBase ?? ARK_API_BASE;
|
|
38
|
+
const store = new TokenStore(options.credentialFile, ARK_PROVIDER_ID, parseArkSession);
|
|
39
|
+
/**
|
|
40
|
+
* Turn a completed sign-in into a usable session.
|
|
41
|
+
*
|
|
42
|
+
* The API key is the credential the data plane takes, and the STS set is what
|
|
43
|
+
* mints it. An account that already holds a key this plugin created reuses it
|
|
44
|
+
* rather than piling up one per sign-in.
|
|
45
|
+
*/
|
|
46
|
+
const toSession = async (tokens) => {
|
|
47
|
+
const sts = tokens.sts;
|
|
48
|
+
if (sts === undefined) {
|
|
49
|
+
throw new ProviderError('Ark sign-in returned no STS credentials, so the plan API key cannot be obtained', REAUTH_REQUIRED);
|
|
50
|
+
}
|
|
51
|
+
const existing = await listArkApiKeys({ credentials: sts, fetchFn })
|
|
52
|
+
.then((keys) => keys.find((key) => key.name === MINTED_KEY_NAME))
|
|
53
|
+
.catch((error) => {
|
|
54
|
+
options.onWarn?.(`Ark could not list existing keys (${error instanceof Error ? error.message : String(error)})`);
|
|
55
|
+
return undefined;
|
|
56
|
+
});
|
|
57
|
+
const id = existing?.id ?? await createArkApiKey({ credentials: sts, fetchFn, name: MINTED_KEY_NAME });
|
|
58
|
+
const apiKey = await readArkApiKey({ credentials: sts, fetchFn, id });
|
|
59
|
+
return {
|
|
60
|
+
accessToken: apiKey,
|
|
61
|
+
apiKey,
|
|
62
|
+
sts,
|
|
63
|
+
idToken: tokens.idToken,
|
|
64
|
+
expiresAt: tokens.expiresAt,
|
|
65
|
+
apiBase,
|
|
66
|
+
...tokens.refreshToken === undefined ? {} : { refreshToken: tokens.refreshToken },
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
const flow = new LoopbackFlow(ARK_PROVIDER_ID, {
|
|
70
|
+
ports: ARK_CALLBACK_PORTS,
|
|
71
|
+
callbackPath: ARK_CALLBACK_PATH,
|
|
72
|
+
buildAuthorizeUrl: ({ redirectUri, state, pkce }) => buildArkAuthorizeUrl({ redirectUri, state, pkce }),
|
|
73
|
+
exchange: async ({ code, redirectUri, pkce, signal }) => toSession(await exchangeArkCode({ fetchFn, code, redirectUri, pkce, signal })),
|
|
74
|
+
});
|
|
75
|
+
const tokens = new TokenManager({
|
|
76
|
+
store,
|
|
77
|
+
displayName: ARK_PROVIDER_NAME,
|
|
78
|
+
// The identity token lives fifteen minutes, so a session has to renew to stay
|
|
79
|
+
// usable; the refresh grant returns a fresh id token and a fresh STS set.
|
|
80
|
+
preemptMs: 5 * 60 * 1000,
|
|
81
|
+
refresh: async (session) => {
|
|
82
|
+
const refreshToken = session.refreshToken;
|
|
83
|
+
if (refreshToken === undefined) {
|
|
84
|
+
throw new ProviderError(`${ARK_PROVIDER_NAME} account has no refresh token; sign in again`, REAUTH_REQUIRED);
|
|
85
|
+
}
|
|
86
|
+
const renewed = await refreshArkToken({ fetchFn, refreshToken });
|
|
87
|
+
// The API key outlives the identity token, so a renewal only has to carry the
|
|
88
|
+
// new STS set forward for the quota; the key itself is unchanged.
|
|
89
|
+
return {
|
|
90
|
+
accessToken: session.apiKey,
|
|
91
|
+
apiKey: session.apiKey,
|
|
92
|
+
expiresAt: renewed.expiresAt,
|
|
93
|
+
...renewed.sts === undefined ? {} : { sts: renewed.sts },
|
|
94
|
+
...renewed.refreshToken === undefined ? {} : { refreshToken: renewed.refreshToken },
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
const adapter = new ArkAdapter({
|
|
99
|
+
apiBase,
|
|
100
|
+
discovery: options.discovery,
|
|
101
|
+
streamIdleTimeoutMs: options.streamIdleTimeoutMs,
|
|
102
|
+
tokens,
|
|
103
|
+
...options.onWarn === undefined ? {} : { onWarn: options.onWarn },
|
|
104
|
+
...options.resolveAttachments === undefined ? {} : { resolveAttachments: options.resolveAttachments },
|
|
105
|
+
hiddenModels: () => options.preferences.hiddenIds(ARK_PROVIDER_ID),
|
|
106
|
+
userModels: () => options.preferences.extraIds(ARK_PROVIDER_ID),
|
|
107
|
+
...options.extraModels === undefined ? {} : { extraModels: options.extraModels },
|
|
108
|
+
fetchFn,
|
|
109
|
+
});
|
|
110
|
+
const spec = {
|
|
111
|
+
id: ARK_PROVIDER_ID,
|
|
112
|
+
displayName: ARK_PROVIDER_NAME,
|
|
113
|
+
codeUrl: ARK_CODE_URL,
|
|
114
|
+
credentialFile: options.credentialFile,
|
|
115
|
+
discovery: options.discovery,
|
|
116
|
+
defaultModel: options.defaultModel ?? ARK_DEFAULT_MODEL,
|
|
117
|
+
catalog: () => adapter.catalogEntries(),
|
|
118
|
+
catalogOwn: () => adapter.ownCatalogEntries(),
|
|
119
|
+
fallbackContextWindow: ARK_CONTEXT_WINDOW,
|
|
120
|
+
discover: (apiKey) => adapter.fetchCatalog(apiKey),
|
|
121
|
+
// The allowance is read with the STS credentials, not the data-plane key.
|
|
122
|
+
usage: async () => {
|
|
123
|
+
const held = await tokens.session();
|
|
124
|
+
const sts = held?.session.sts;
|
|
125
|
+
if (sts === undefined)
|
|
126
|
+
return { windows: [] };
|
|
127
|
+
return await readArkUsage({ credentials: sts, fetchFn });
|
|
128
|
+
},
|
|
129
|
+
details: () => [
|
|
130
|
+
{ key: 'apiBase', value: apiBase },
|
|
131
|
+
{ key: 'controlPlane', value: 'https://ark.cn-beijing.volcengineapi.com' },
|
|
132
|
+
{ key: 'credentialFile', value: options.credentialFile },
|
|
133
|
+
],
|
|
134
|
+
applyDiscovery: (ids) => { adapter.discover(ids); },
|
|
135
|
+
};
|
|
136
|
+
const controller = new ProviderController({
|
|
137
|
+
spec,
|
|
138
|
+
store,
|
|
139
|
+
tokens,
|
|
140
|
+
flow,
|
|
141
|
+
preferences: options.preferences,
|
|
142
|
+
...options.onCatalogChanged === undefined ? {} : { onCatalogChanged: options.onCatalogChanged },
|
|
143
|
+
...options.onWarn === undefined ? {} : { onWarn: options.onWarn },
|
|
144
|
+
});
|
|
145
|
+
// An explicit façade, not a spread: a spread would copy own properties and drop
|
|
146
|
+
// the class prototype, leaving every method undefined.
|
|
147
|
+
return {
|
|
148
|
+
id: controller.id,
|
|
149
|
+
displayName: controller.displayName,
|
|
150
|
+
credentialFile: controller.credentialFile,
|
|
151
|
+
adapter,
|
|
152
|
+
status: () => controller.status(),
|
|
153
|
+
login: (account) => controller.login(account),
|
|
154
|
+
cancel: () => controller.cancel(),
|
|
155
|
+
logout: (account) => controller.logout(account),
|
|
156
|
+
setDefault: (account) => controller.setDefault(account),
|
|
157
|
+
refresh: (account) => controller.refresh(account),
|
|
158
|
+
discover: (force) => controller.discover(force),
|
|
159
|
+
setModelVisible: (id, visible) => controller.setModelVisible(id, visible),
|
|
160
|
+
setModelOrder: (ids) => controller.setModelOrder(ids),
|
|
161
|
+
addModel: (id) => controller.addModel(id),
|
|
162
|
+
removeModel: (id) => controller.removeModel(id),
|
|
163
|
+
usage: (force) => controller.usage(force),
|
|
164
|
+
reload: () => controller.reload(),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `ark` route: Volcengine Ark's Coding Plan over the OpenAI Responses wire.
|
|
3
|
+
*
|
|
4
|
+
* Everything in this module is pinned to what the endpoints themselves said:
|
|
5
|
+
*
|
|
6
|
+
* - `POST /api/coding/v3/responses` exists and wants a credential (401).
|
|
7
|
+
* - It accepts a **bearer Ark API key** and nothing else. An SSO identity token in
|
|
8
|
+
* the same header is refused with `403 Unsupported zti authentication method`,
|
|
9
|
+
* and an AK/SK signature with `403 Unsupported aksk authentication method`, while
|
|
10
|
+
* a UUID-shaped key is looked up (`401 The API key doesn't exist`) and a
|
|
11
|
+
* malformed one is told so (`401 The API key format is incorrect`). So the
|
|
12
|
+
* credential is a UUID key, sent as a plain bearer — no request signing.
|
|
13
|
+
* - `/api/coding/v3` is documented by the official CLI as "OpenTOP + CodingPlan
|
|
14
|
+
* API", and the catalogue below is the plan's roster.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-plugin-subscription-oauth/providers/ark
|
|
17
|
+
*/
|
|
18
|
+
import { LlmAdapter } from '@deepseek-ai/dsh-llm';
|
|
19
|
+
import type { GenerateOptions, LlmModelInfo, LlmProviderInfo, LlmResolvedModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
20
|
+
import type { SessionBase } from '../auth/store.js';
|
|
21
|
+
import type { TokenManager } from '../auth/tokens.js';
|
|
22
|
+
import type { ArkStsCredentials } from '../auth/ark-control.js';
|
|
23
|
+
import type { FetchFn } from '../http.js';
|
|
24
|
+
import type { AttachmentStore } from '@deepseek-ai/dsh-attachment';
|
|
25
|
+
import type { CatalogEntry } from './catalog.js';
|
|
26
|
+
import type { UsageRead } from './usage.js';
|
|
27
|
+
/** Provider route this module serves. */
|
|
28
|
+
export declare const ARK_PROVIDER_ID = "ark";
|
|
29
|
+
/** Display name for the picker group and the Settings card. */
|
|
30
|
+
export declare const ARK_PROVIDER_NAME = "Volcengine Ark";
|
|
31
|
+
/** Page a user opens to manage the plan. */
|
|
32
|
+
export declare const ARK_CODE_URL = "https://console.volcengine.com/ark/region:ark+cn-beijing/overview";
|
|
33
|
+
/** Coding-plan base; the Responses endpoint is `<base>/responses`. */
|
|
34
|
+
export declare const ARK_API_BASE = "https://ark.cn-beijing.volces.com/api/coding/v3";
|
|
35
|
+
/** Origin the account-level endpoints hang off. */
|
|
36
|
+
export declare const ARK_ORIGIN = "https://ark.cn-beijing.volces.com";
|
|
37
|
+
/** Path appended to the API base for a streaming request. */
|
|
38
|
+
export declare const ARK_RESPONSES_PATH = "/responses";
|
|
39
|
+
/** Model the picker preselects: the plan's own alias for its coding model. */
|
|
40
|
+
export declare const ARK_DEFAULT_MODEL = "ark-code-latest";
|
|
41
|
+
/**
|
|
42
|
+
* Context capacity advertised for the plan's models.
|
|
43
|
+
*
|
|
44
|
+
* The Coding Plan is a curated, text-first roster and states no window per model;
|
|
45
|
+
* discovery refines this where the endpoint reports one.
|
|
46
|
+
*/
|
|
47
|
+
export declare const ARK_CONTEXT_WINDOW = 262144;
|
|
48
|
+
/** Output budget used when the caller sets no cap. */
|
|
49
|
+
export declare const ARK_DEFAULT_MAX_TOKENS = 32000;
|
|
50
|
+
/** The plan's model roster, as the reference registry records it. */
|
|
51
|
+
export declare const ARK_MODELS: readonly CatalogEntry[];
|
|
52
|
+
/** One signed-in Ark account. */
|
|
53
|
+
export interface ArkSession extends SessionBase {
|
|
54
|
+
/**
|
|
55
|
+
* The plan's API key.
|
|
56
|
+
*
|
|
57
|
+
* The data plane takes this as a plain bearer; the SSO identity token authorises
|
|
58
|
+
* the control plane that mints it, so the key — not the identity token — is what
|
|
59
|
+
* every model request carries.
|
|
60
|
+
*/
|
|
61
|
+
apiKey: string;
|
|
62
|
+
/**
|
|
63
|
+
* Temporary STS credentials, used to sign control-plane calls.
|
|
64
|
+
*
|
|
65
|
+
* The SSO endpoint returns these in its `access_token`, which is where the plan
|
|
66
|
+
* allowance is read from; without them the route still serves models but states
|
|
67
|
+
* no quota.
|
|
68
|
+
*/
|
|
69
|
+
sts?: ArkStsCredentials;
|
|
70
|
+
/** Identity token the key was minted under, for the control plane. */
|
|
71
|
+
idToken?: string;
|
|
72
|
+
/** API base recorded at login time (diagnostics only). */
|
|
73
|
+
apiBase?: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Coerce one decoded credential entry into an Ark session.
|
|
77
|
+
*
|
|
78
|
+
* @param value - decoded JSON value for one account.
|
|
79
|
+
* @returns the session, or undefined when required fields are missing.
|
|
80
|
+
*/
|
|
81
|
+
export declare function parseArkSession(value: unknown): ArkSession | undefined;
|
|
82
|
+
/** Everything the adapter needs from the route. */
|
|
83
|
+
export interface ArkAdapterOptions {
|
|
84
|
+
apiBase: string;
|
|
85
|
+
discovery: boolean;
|
|
86
|
+
streamIdleTimeoutMs: number;
|
|
87
|
+
tokens: TokenManager<ArkSession>;
|
|
88
|
+
hiddenModels?: () => Promise<ReadonlySet<string>> | ReadonlySet<string>;
|
|
89
|
+
userModels?: () => Promise<readonly string[]> | readonly string[];
|
|
90
|
+
extraModels?: readonly string[];
|
|
91
|
+
resolveAttachments?: () => AttachmentStore | undefined;
|
|
92
|
+
onWarn?: (message: string) => void;
|
|
93
|
+
onCredentialRejected?: (account: string) => void;
|
|
94
|
+
fetchFn?: FetchFn;
|
|
95
|
+
}
|
|
96
|
+
/** The adapter behind the `ark` route. */
|
|
97
|
+
export declare class ArkAdapter extends LlmAdapter {
|
|
98
|
+
private readonly options;
|
|
99
|
+
private live;
|
|
100
|
+
constructor(options: ArkAdapterOptions);
|
|
101
|
+
providerInfo(provider: string): LlmProviderInfo;
|
|
102
|
+
providerRetryPolicy(): undefined;
|
|
103
|
+
listModels(_provider: string): Promise<readonly LlmModelInfo[]>;
|
|
104
|
+
resolveModel(_provider: string, model: string): Promise<LlmResolvedModelInfo>;
|
|
105
|
+
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
106
|
+
/** Translate an auth failure into the message a user can act on. */
|
|
107
|
+
private refreshHint;
|
|
108
|
+
private catalog;
|
|
109
|
+
private shippedCatalog;
|
|
110
|
+
private addedEntries;
|
|
111
|
+
private hidden;
|
|
112
|
+
/** Adopt the endpoint's live catalog. */
|
|
113
|
+
discover(ids: readonly string[]): void;
|
|
114
|
+
/**
|
|
115
|
+
* Read the plan's live model list.
|
|
116
|
+
*
|
|
117
|
+
* The Coding Plan answers the OpenAI models shape on its own base; an endpoint
|
|
118
|
+
* that does not serve it leaves the shipped roster in place.
|
|
119
|
+
*/
|
|
120
|
+
fetchCatalog(apiKey: string, signal?: AbortSignal): Promise<readonly string[] | undefined>;
|
|
121
|
+
/** Send one streaming request over the Responses wire. */
|
|
122
|
+
private request;
|
|
123
|
+
/** Resolve image blocks through the attachment service, when it is present. */
|
|
124
|
+
private imageResolver;
|
|
125
|
+
/** The catalog the controller publishes without hand-added ids. */
|
|
126
|
+
ownCatalogEntries(): readonly CatalogEntry[];
|
|
127
|
+
/** The catalog the controller publishes. */
|
|
128
|
+
catalogEntries(): readonly CatalogEntry[];
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Read the plan's allowance.
|
|
132
|
+
*
|
|
133
|
+
* Two allowances exist, and both live on the **control plane** — a different host
|
|
134
|
+
* from the data plane, reached with the STS AK/SK the SSO identity was exchanged
|
|
135
|
+
* for (see `auth/ark-control.ts`) rather than with the plan API key:
|
|
136
|
+
*
|
|
137
|
+
* - the **subscription** periods (`GetCodingPlanUsage` → `coding_usage.periods[]`,
|
|
138
|
+
* each `{ label, used, total, percent, reset_at }`), which an account without a
|
|
139
|
+
* plan answers as `Status: Reclaimed`;
|
|
140
|
+
* - the **free inference allowance** per model (`ListModelChargeItems` →
|
|
141
|
+
* `InferenceFreeUsage { Consumed, Total }`), which exists with no subscription.
|
|
142
|
+
*
|
|
143
|
+
* The free allowance is what a plan-less account actually has, so it is reported
|
|
144
|
+
* even when the subscription is absent — otherwise the card would say "no quota"
|
|
145
|
+
* while the account still had tokens to spend.
|
|
146
|
+
*
|
|
147
|
+
* @param input - the signed control-plane client.
|
|
148
|
+
* @returns the windows the service stated, subscription first.
|
|
149
|
+
*/
|
|
150
|
+
export declare function readArkUsage(input: {
|
|
151
|
+
credentials: ArkStsCredentials;
|
|
152
|
+
fetchFn: FetchFn;
|
|
153
|
+
signal?: AbortSignal;
|
|
154
|
+
}): Promise<UsageRead>;
|