dsh-plugin-subscriptions 0.5.2 → 0.6.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 +79 -5
- package/README.zh.md +78 -4
- package/lib/auth/rpc.d.ts +64 -13
- package/lib/auth/rpc.js +75 -10
- package/lib/auth/store.d.ts +75 -17
- package/lib/auth/store.js +148 -27
- package/lib/client/ImageGenerateToolview.d.ts +1 -1
- package/lib/client/SpeedSelect.d.ts +25 -2
- package/lib/client/SpeedSelect.js +10 -6
- package/lib/client/SubscriptionsSection.d.ts +83 -3
- package/lib/client/SubscriptionsSection.js +411 -62
- package/lib/client/VideoGenerateToolview.d.ts +1 -1
- package/lib/client/index.d.ts +1 -9
- package/lib/client/index.js +7 -4
- package/lib/client/locales.d.ts +46 -10
- package/lib/client/locales.js +46 -10
- package/lib/client.js +703 -132
- package/lib/client.js.map +1 -1
- package/lib/compat.d.ts +36 -0
- package/lib/compat.js +20 -0
- package/lib/index.d.ts +26 -1
- package/lib/index.js +2377 -309
- package/lib/model-defaults.d.ts +23 -0
- package/lib/model-defaults.js +237 -0
- package/lib/providers/accounts.d.ts +102 -0
- package/lib/providers/accounts.js +123 -0
- package/lib/providers/claude.d.ts +46 -7
- package/lib/providers/claude.js +125 -34
- package/lib/providers/codex.d.ts +45 -3
- package/lib/providers/codex.js +152 -26
- package/lib/providers/common.d.ts +87 -6
- package/lib/providers/common.js +185 -22
- package/lib/providers/copilot.d.ts +32 -3
- package/lib/providers/copilot.js +111 -19
- package/lib/providers/grok.d.ts +45 -4
- package/lib/providers/grok.js +136 -20
- package/lib/providers/pool-family.d.ts +56 -0
- package/lib/providers/pool-family.js +45 -0
- package/lib/providers/pool-health.d.ts +74 -0
- package/lib/providers/pool-health.js +148 -0
- package/lib/providers/pool-usage.d.ts +78 -0
- package/lib/providers/pool-usage.js +185 -0
- package/lib/providers/pool.d.ts +107 -0
- package/lib/providers/pool.js +371 -0
- package/lib/providers/rate-limit.d.ts +192 -0
- package/lib/providers/rate-limit.js +338 -0
- package/lib/tools/image-generate.d.ts +3 -3
- package/lib/tools/image-generate.js +2 -1
- package/lib/tools/video-generate.d.ts +2 -2
- package/lib/tools/video-generate.js +2 -1
- package/lib/tools/x-search.d.ts +2 -2
- package/lib/tools/x-search.js +2 -1
- package/lib/translate/anthropic.js +5 -4
- package/lib/translate/chat-completions.js +5 -4
- package/lib/translate/responses.js +5 -4
- package/package.json +21 -21
- package/lib/providers/antigravity.d.ts +0 -90
- package/lib/providers/antigravity.js +0 -392
- package/lib/translate/antigravity.d.ts +0 -110
- package/lib/translate/antigravity.js +0 -303
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Google Antigravity subscription provider. This is intentionally separate
|
|
3
|
-
* from Gemini CLI: it uses Antigravity OAuth scopes, project discovery, and
|
|
4
|
-
* the daily-cloudcode-pa v1internal request envelope.
|
|
5
|
-
*/
|
|
6
|
-
import { LlmAdapter } from '@deepseek-ai/dsh-llm';
|
|
7
|
-
import type { GenerateOptions, LlmModelInfo, LlmProviderInfo, LlmResolvedModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
8
|
-
import type { AttachmentStore } from '@deepseek-ai/dsh-attachment';
|
|
9
|
-
import type { FlowSpec } from '../auth/oauth-flow.js';
|
|
10
|
-
import type { AntigravitySession } from '../auth/store.js';
|
|
11
|
-
import type { AntigravityRequest } from '../translate/antigravity.js';
|
|
12
|
-
import { TokenManager } from './common.js';
|
|
13
|
-
import type { CatalogPersistence, DiscoveredModel, FetchFn, ModelEntry, ProviderUsage } from './common.js';
|
|
14
|
-
export declare const ANTIGRAVITY_AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
15
|
-
export declare const ANTIGRAVITY_TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
16
|
-
export declare const ANTIGRAVITY_USERINFO_URL = "https://www.googleapis.com/oauth2/v2/userinfo";
|
|
17
|
-
export declare const ANTIGRAVITY_DEFAULT_BASE_URL = "https://daily-cloudcode-pa.googleapis.com";
|
|
18
|
-
export declare const ANTIGRAVITY_PROD_BASE_URL = "https://cloudcode-pa.googleapis.com";
|
|
19
|
-
export declare const ANTIGRAVITY_DEFAULT_USER_AGENT = "antigravity/1.104.0 dsh-plugin-subscriptions";
|
|
20
|
-
export declare const ANTIGRAVITY_PREEMPT_MS: number;
|
|
21
|
-
/** Antigravity, not Gemini CLI, OAuth scopes from the local reference clients. */
|
|
22
|
-
export declare const ANTIGRAVITY_SCOPES: readonly ["openid", "https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/cclog", "https://www.googleapis.com/auth/experimentsandconfigs"];
|
|
23
|
-
/** OAuth client configuration. Values must come from config/environment. */
|
|
24
|
-
export interface AntigravityOAuthConfig {
|
|
25
|
-
clientId: string;
|
|
26
|
-
clientSecret?: string;
|
|
27
|
-
}
|
|
28
|
-
/** Runtime endpoint configuration. */
|
|
29
|
-
export interface AntigravityRuntimeConfig {
|
|
30
|
-
baseURL?: string;
|
|
31
|
-
userAgent?: string;
|
|
32
|
-
/** Activate an eligible account when loadCodeAssist has no project yet. */
|
|
33
|
-
onboard?: boolean;
|
|
34
|
-
}
|
|
35
|
-
/** Resolve and validate a user-supplied OAuth config without embedded credentials. */
|
|
36
|
-
export declare function resolveAntigravityOAuthConfig(config?: Partial<AntigravityOAuthConfig>): AntigravityOAuthConfig;
|
|
37
|
-
/** Normalize the configured API origin and reject paths/credentials. */
|
|
38
|
-
export declare function antigravityBaseURL(value?: string): string;
|
|
39
|
-
/** Google authorization-code + PKCE flow for Antigravity. */
|
|
40
|
-
export declare function antigravityFlow(oauth: AntigravityOAuthConfig): FlowSpec;
|
|
41
|
-
interface AntigravityAccountInfo {
|
|
42
|
-
projectId: string;
|
|
43
|
-
account?: string;
|
|
44
|
-
plan?: string;
|
|
45
|
-
}
|
|
46
|
-
/** Shared Antigravity API headers. */
|
|
47
|
-
export declare function antigravityHeaders(accessToken: string, userAgent?: string): Record<string, string>;
|
|
48
|
-
/** Read (and, when enabled, initialize) the Antigravity project/account. */
|
|
49
|
-
export declare function discoverAntigravityAccount(accessToken: string, runtime?: AntigravityRuntimeConfig, fetchFn?: FetchFn): Promise<AntigravityAccountInfo>;
|
|
50
|
-
/** Exchange a Google OAuth authorization code and discover the Antigravity project. */
|
|
51
|
-
export declare function exchangeAntigravityCode(code: string, verifier: string, redirectUri: string, oauth: AntigravityOAuthConfig, runtime?: AntigravityRuntimeConfig, fetchFn?: FetchFn): Promise<AntigravitySession>;
|
|
52
|
-
/** Refresh a stored Antigravity Google token, preserving project/account metadata. */
|
|
53
|
-
export declare function refreshAntigravity(session: AntigravitySession, oauth: AntigravityOAuthConfig, fetchFn?: FetchFn): Promise<AntigravitySession>;
|
|
54
|
-
/** Refresh failures that require a fresh Google consent grant. */
|
|
55
|
-
export declare function isAntigravityPermanentRefreshError(error: unknown): boolean;
|
|
56
|
-
/** Fetch the authenticated account's live Antigravity model catalog. */
|
|
57
|
-
export declare function fetchAntigravityModels(session: AntigravitySession, runtime?: AntigravityRuntimeConfig, fetchFn?: FetchFn): Promise<DiscoveredModel[]>;
|
|
58
|
-
/** Fetch plan and per-model quota windows when the upstream exposes them. */
|
|
59
|
-
export declare function fetchAntigravityUsage(session: AntigravitySession, runtime?: AntigravityRuntimeConfig, fetchFn?: FetchFn, signal?: AbortSignal): Promise<ProviderUsage>;
|
|
60
|
-
/** URL for either v1internal generation transport. */
|
|
61
|
-
export declare function antigravityGenerateURL(baseURL: string | undefined, stream: boolean): string;
|
|
62
|
-
/** Forward one already-built payload to generateContent or streamGenerateContent. */
|
|
63
|
-
export declare function requestAntigravityContent(session: AntigravitySession, payload: AntigravityRequest, stream: boolean, runtime?: AntigravityRuntimeConfig, fetchFn?: FetchFn, signal?: AbortSignal): Promise<Response>;
|
|
64
|
-
export interface AntigravityAdapterOptions {
|
|
65
|
-
models: readonly ModelEntry[];
|
|
66
|
-
streamIdleTimeoutMs: number;
|
|
67
|
-
tokens: TokenManager<AntigravitySession>;
|
|
68
|
-
discovery: boolean;
|
|
69
|
-
runtime?: AntigravityRuntimeConfig;
|
|
70
|
-
onWarn?: (message: string) => void;
|
|
71
|
-
fetchFn?: FetchFn;
|
|
72
|
-
resolveAttachments?: () => AttachmentStore | undefined;
|
|
73
|
-
catalogStore?: CatalogPersistence;
|
|
74
|
-
}
|
|
75
|
-
/** DSH provider adapter for the `antigravity` route. */
|
|
76
|
-
export declare class AntigravityAdapter extends LlmAdapter {
|
|
77
|
-
private readonly options;
|
|
78
|
-
private readonly catalog;
|
|
79
|
-
constructor(options: AntigravityAdapterOptions);
|
|
80
|
-
providerInfo(provider: string): LlmProviderInfo;
|
|
81
|
-
private staticModels;
|
|
82
|
-
private fetchCatalog;
|
|
83
|
-
listModels(provider: string): Promise<readonly LlmModelInfo[]>;
|
|
84
|
-
private discovered;
|
|
85
|
-
resolveModel(provider: string, model: string): Promise<LlmResolvedModelInfo>;
|
|
86
|
-
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
87
|
-
/** Non-stream forwarding seam used by tests and future DSH complete calls. */
|
|
88
|
-
generate(options: GenerateOptions): Promise<StreamChunk[]>;
|
|
89
|
-
}
|
|
90
|
-
export {};
|
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Google Antigravity subscription provider. This is intentionally separate
|
|
3
|
-
* from Gemini CLI: it uses Antigravity OAuth scopes, project discovery, and
|
|
4
|
-
* the daily-cloudcode-pa v1internal request envelope.
|
|
5
|
-
*/
|
|
6
|
-
import { errorChain, EMPTY_RESPONSE_CODE, LlmAdapter, LlmError } from '@deepseek-ai/dsh-llm';
|
|
7
|
-
import { resolveImages } from '../translate/resolved.js';
|
|
8
|
-
import { parseAntigravityResponse, streamAntigravity, toAntigravityRequest, } from '../translate/antigravity.js';
|
|
9
|
-
import { httpLlmError, idleWatchdog, mapFetchFailure, ModelCatalogCache, discoverOrRetryAuth, isMissingOrInvalidCredential, oauthEndpointError, OAuthEndpointError, TokenManager, } from './common.js';
|
|
10
|
-
import { proxiedFetch } from '../http.js';
|
|
11
|
-
export const ANTIGRAVITY_AUTHORIZE_URL = 'https://accounts.google.com/o/oauth2/v2/auth';
|
|
12
|
-
export const ANTIGRAVITY_TOKEN_URL = 'https://oauth2.googleapis.com/token';
|
|
13
|
-
export const ANTIGRAVITY_USERINFO_URL = 'https://www.googleapis.com/oauth2/v2/userinfo';
|
|
14
|
-
export const ANTIGRAVITY_DEFAULT_BASE_URL = 'https://daily-cloudcode-pa.googleapis.com';
|
|
15
|
-
export const ANTIGRAVITY_PROD_BASE_URL = 'https://cloudcode-pa.googleapis.com';
|
|
16
|
-
export const ANTIGRAVITY_DEFAULT_USER_AGENT = 'antigravity/1.104.0 dsh-plugin-subscriptions';
|
|
17
|
-
export const ANTIGRAVITY_PREEMPT_MS = 5 * 60_000;
|
|
18
|
-
const ANTIGRAVITY_CALLBACK_PATH = '/oauth-callback';
|
|
19
|
-
const ANTIGRAVITY_CONTEXT_WINDOW = 1_024_000;
|
|
20
|
-
const ANTIGRAVITY_DEFAULT_MAX_TOKENS = 65_536;
|
|
21
|
-
/** Antigravity, not Gemini CLI, OAuth scopes from the local reference clients. */
|
|
22
|
-
export const ANTIGRAVITY_SCOPES = [
|
|
23
|
-
'openid',
|
|
24
|
-
'https://www.googleapis.com/auth/cloud-platform',
|
|
25
|
-
'https://www.googleapis.com/auth/userinfo.email',
|
|
26
|
-
'https://www.googleapis.com/auth/userinfo.profile',
|
|
27
|
-
'https://www.googleapis.com/auth/cclog',
|
|
28
|
-
'https://www.googleapis.com/auth/experimentsandconfigs',
|
|
29
|
-
];
|
|
30
|
-
/** Resolve and validate a user-supplied OAuth config without embedded credentials. */
|
|
31
|
-
export function resolveAntigravityOAuthConfig(config) {
|
|
32
|
-
const clientId = config?.clientId?.trim() || process.env.ANTIGRAVITY_CLIENT_ID?.trim() || '';
|
|
33
|
-
const clientSecret = config?.clientSecret?.trim() || process.env.ANTIGRAVITY_CLIENT_SECRET?.trim();
|
|
34
|
-
if (clientId.length === 0) {
|
|
35
|
-
throw new Error('Antigravity OAuth is not configured; set config.antigravity.clientId or ANTIGRAVITY_CLIENT_ID '
|
|
36
|
-
+ '(and clientSecret/ANTIGRAVITY_CLIENT_SECRET when required by the Google OAuth client)');
|
|
37
|
-
}
|
|
38
|
-
return { clientId, ...clientSecret === undefined || clientSecret.length === 0 ? {} : { clientSecret } };
|
|
39
|
-
}
|
|
40
|
-
/** Normalize the configured API origin and reject paths/credentials. */
|
|
41
|
-
export function antigravityBaseURL(value) {
|
|
42
|
-
const parsed = new URL(value?.trim() || ANTIGRAVITY_DEFAULT_BASE_URL);
|
|
43
|
-
if (parsed.protocol !== 'https:' || parsed.username.length > 0 || parsed.password.length > 0) {
|
|
44
|
-
throw new Error('config.antigravity.baseURL must be an HTTPS origin without credentials');
|
|
45
|
-
}
|
|
46
|
-
if (parsed.pathname !== '/' || parsed.search.length > 0 || parsed.hash.length > 0) {
|
|
47
|
-
throw new Error('config.antigravity.baseURL must not contain a path, query, or fragment');
|
|
48
|
-
}
|
|
49
|
-
return parsed.origin;
|
|
50
|
-
}
|
|
51
|
-
/** Google authorization-code + PKCE flow for Antigravity. */
|
|
52
|
-
export function antigravityFlow(oauth) {
|
|
53
|
-
return {
|
|
54
|
-
callbackPath: ANTIGRAVITY_CALLBACK_PATH,
|
|
55
|
-
listen: { host: 'localhost', ports: [51121, 0] },
|
|
56
|
-
timeoutMs: 5 * 60_000,
|
|
57
|
-
buildAuthorizeUrl({ redirectUri, state, pkce }) {
|
|
58
|
-
const params = new URLSearchParams({
|
|
59
|
-
access_type: 'offline',
|
|
60
|
-
client_id: oauth.clientId,
|
|
61
|
-
code_challenge: pkce.challenge,
|
|
62
|
-
code_challenge_method: 'S256',
|
|
63
|
-
include_granted_scopes: 'true',
|
|
64
|
-
prompt: 'consent',
|
|
65
|
-
redirect_uri: redirectUri,
|
|
66
|
-
response_type: 'code',
|
|
67
|
-
scope: ANTIGRAVITY_SCOPES.join(' '),
|
|
68
|
-
state,
|
|
69
|
-
});
|
|
70
|
-
return `${ANTIGRAVITY_AUTHORIZE_URL}?${params.toString()}`;
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
/** Shared Antigravity API headers. */
|
|
75
|
-
export function antigravityHeaders(accessToken, userAgent = ANTIGRAVITY_DEFAULT_USER_AGENT) {
|
|
76
|
-
return {
|
|
77
|
-
'authorization': `Bearer ${accessToken}`,
|
|
78
|
-
'content-type': 'application/json',
|
|
79
|
-
'user-agent': userAgent,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
/** POST a v1internal JSON method and classify non-2xx responses. */
|
|
83
|
-
async function callInternal(method, body, accessToken, runtime, fetchFn, signal) {
|
|
84
|
-
const response = await fetchFn(`${antigravityBaseURL(runtime.baseURL)}/v1internal:${method}`, {
|
|
85
|
-
method: 'POST',
|
|
86
|
-
headers: antigravityHeaders(accessToken, runtime.userAgent),
|
|
87
|
-
body: JSON.stringify(body),
|
|
88
|
-
...signal === undefined ? {} : { signal },
|
|
89
|
-
});
|
|
90
|
-
if (!response.ok)
|
|
91
|
-
throw await httpLlmError(response, `Antigravity ${method}`);
|
|
92
|
-
return response.json();
|
|
93
|
-
}
|
|
94
|
-
function projectIdOf(value) {
|
|
95
|
-
if (typeof value === 'string' && value.length > 0)
|
|
96
|
-
return value;
|
|
97
|
-
if (typeof value === 'object' && value !== null) {
|
|
98
|
-
const id = value.id;
|
|
99
|
-
if (typeof id === 'string' && id.length > 0)
|
|
100
|
-
return id;
|
|
101
|
-
}
|
|
102
|
-
return undefined;
|
|
103
|
-
}
|
|
104
|
-
/** Read (and, when enabled, initialize) the Antigravity project/account. */
|
|
105
|
-
export async function discoverAntigravityAccount(accessToken, runtime = {}, fetchFn = proxiedFetch) {
|
|
106
|
-
const metadata = { ideType: 'ANTIGRAVITY', platform: 'PLATFORM_UNSPECIFIED', pluginType: 'GEMINI' };
|
|
107
|
-
const load = await callInternal('loadCodeAssist', { metadata }, accessToken, runtime, fetchFn);
|
|
108
|
-
let projectId = projectIdOf(load.cloudaicompanionProject);
|
|
109
|
-
if (projectId === undefined && runtime.onboard !== false) {
|
|
110
|
-
const tierId = load.allowedTiers?.find(tier => tier.isDefault)?.id ?? 'LEGACY';
|
|
111
|
-
const onboardBody = { tierId, metadata };
|
|
112
|
-
for (let attempt = 0; attempt < 10; attempt++) {
|
|
113
|
-
const result = await callInternal('onboardUser', onboardBody, accessToken, runtime, fetchFn);
|
|
114
|
-
if (result.done === true) {
|
|
115
|
-
projectId = projectIdOf(result.response?.cloudaicompanionProject);
|
|
116
|
-
break;
|
|
117
|
-
}
|
|
118
|
-
await new Promise(resolve => setTimeout(resolve, 1_000));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
if (projectId === undefined) {
|
|
122
|
-
throw new Error('Antigravity account has no Cloud AI Companion project; open Antigravity and complete onboarding, then log in again');
|
|
123
|
-
}
|
|
124
|
-
let account;
|
|
125
|
-
try {
|
|
126
|
-
const profileResponse = await fetchFn(ANTIGRAVITY_USERINFO_URL, {
|
|
127
|
-
headers: { authorization: `Bearer ${accessToken}`, accept: 'application/json' },
|
|
128
|
-
});
|
|
129
|
-
if (profileResponse.ok) {
|
|
130
|
-
const profile = await profileResponse.json();
|
|
131
|
-
if (typeof profile.email === 'string' && profile.email.length > 0)
|
|
132
|
-
account = profile.email;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
// Identity is display-only; project discovery is the login boundary.
|
|
137
|
-
}
|
|
138
|
-
const plan = load.paidTier?.name ?? load.paidTier?.id ?? load.currentTier?.name ?? load.currentTier?.id;
|
|
139
|
-
return {
|
|
140
|
-
projectId,
|
|
141
|
-
...account === undefined ? {} : { account },
|
|
142
|
-
...typeof plan !== 'string' || plan.length === 0 ? {} : { plan },
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
function sessionFromTokens(tokens, account, fallback) {
|
|
146
|
-
if (typeof tokens.access_token !== 'string' || tokens.access_token.length === 0) {
|
|
147
|
-
throw new Error('Antigravity token endpoint returned no access token');
|
|
148
|
-
}
|
|
149
|
-
const refreshToken = tokens.refresh_token ?? fallback?.refreshToken;
|
|
150
|
-
if (refreshToken === undefined || refreshToken.length === 0) {
|
|
151
|
-
throw new Error('Antigravity token endpoint returned no refresh token; revoke the app grant and log in again');
|
|
152
|
-
}
|
|
153
|
-
if (typeof tokens.expires_in !== 'number' || tokens.expires_in <= 0) {
|
|
154
|
-
throw new Error('Antigravity token endpoint returned no usable expiry');
|
|
155
|
-
}
|
|
156
|
-
return {
|
|
157
|
-
accessToken: tokens.access_token,
|
|
158
|
-
refreshToken,
|
|
159
|
-
expiresAt: Date.now() + tokens.expires_in * 1000,
|
|
160
|
-
projectId: account.projectId,
|
|
161
|
-
...tokens.scope === undefined ? {} : { scopes: tokens.scope },
|
|
162
|
-
...account.account === undefined ? {} : { account: account.account },
|
|
163
|
-
...account.plan === undefined ? {} : { plan: account.plan },
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
/** Exchange a Google OAuth authorization code and discover the Antigravity project. */
|
|
167
|
-
export async function exchangeAntigravityCode(code, verifier, redirectUri, oauth, runtime = {}, fetchFn = proxiedFetch) {
|
|
168
|
-
const body = new URLSearchParams({
|
|
169
|
-
grant_type: 'authorization_code',
|
|
170
|
-
code,
|
|
171
|
-
redirect_uri: redirectUri,
|
|
172
|
-
client_id: oauth.clientId,
|
|
173
|
-
code_verifier: verifier,
|
|
174
|
-
...oauth.clientSecret === undefined ? {} : { client_secret: oauth.clientSecret },
|
|
175
|
-
});
|
|
176
|
-
const response = await fetchFn(ANTIGRAVITY_TOKEN_URL, {
|
|
177
|
-
method: 'POST',
|
|
178
|
-
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
179
|
-
body: body.toString(),
|
|
180
|
-
});
|
|
181
|
-
if (!response.ok)
|
|
182
|
-
throw await oauthEndpointError(response, 'Antigravity');
|
|
183
|
-
const tokens = await response.json();
|
|
184
|
-
if (typeof tokens.access_token !== 'string')
|
|
185
|
-
throw new Error('Antigravity token endpoint returned no access token');
|
|
186
|
-
const account = await discoverAntigravityAccount(tokens.access_token, runtime, fetchFn);
|
|
187
|
-
return sessionFromTokens(tokens, account);
|
|
188
|
-
}
|
|
189
|
-
/** Refresh a stored Antigravity Google token, preserving project/account metadata. */
|
|
190
|
-
export async function refreshAntigravity(session, oauth, fetchFn = proxiedFetch) {
|
|
191
|
-
const body = new URLSearchParams({
|
|
192
|
-
grant_type: 'refresh_token',
|
|
193
|
-
refresh_token: session.refreshToken,
|
|
194
|
-
client_id: oauth.clientId,
|
|
195
|
-
...oauth.clientSecret === undefined ? {} : { client_secret: oauth.clientSecret },
|
|
196
|
-
});
|
|
197
|
-
const response = await fetchFn(ANTIGRAVITY_TOKEN_URL, {
|
|
198
|
-
method: 'POST',
|
|
199
|
-
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
200
|
-
body: body.toString(),
|
|
201
|
-
});
|
|
202
|
-
if (!response.ok)
|
|
203
|
-
throw await oauthEndpointError(response, 'Antigravity');
|
|
204
|
-
return sessionFromTokens(await response.json(), {
|
|
205
|
-
projectId: session.projectId,
|
|
206
|
-
...session.account === undefined ? {} : { account: session.account },
|
|
207
|
-
...session.plan === undefined ? {} : { plan: session.plan },
|
|
208
|
-
}, session);
|
|
209
|
-
}
|
|
210
|
-
/** Refresh failures that require a fresh Google consent grant. */
|
|
211
|
-
export function isAntigravityPermanentRefreshError(error) {
|
|
212
|
-
return error instanceof OAuthEndpointError
|
|
213
|
-
&& (error.status === 400 || error.status === 401 || error.status === 403)
|
|
214
|
-
&& (error.oauthCode === 'invalid_grant' || error.status !== 400);
|
|
215
|
-
}
|
|
216
|
-
/** Fetch the authenticated account's live Antigravity model catalog. */
|
|
217
|
-
export async function fetchAntigravityModels(session, runtime = {}, fetchFn = proxiedFetch) {
|
|
218
|
-
const payload = await callInternal('fetchAvailableModels', { project: session.projectId }, session.accessToken, runtime, fetchFn);
|
|
219
|
-
if (typeof payload.models !== 'object' || payload.models === null) {
|
|
220
|
-
throw new Error('Antigravity models endpoint returned no models object');
|
|
221
|
-
}
|
|
222
|
-
const models = Object.entries(payload.models).map(([id, model]) => ({
|
|
223
|
-
id,
|
|
224
|
-
name: model.displayName ?? id.split('-').map(word => word.length === 0 ? word : word[0].toUpperCase() + word.slice(1)).join(' '),
|
|
225
|
-
...model.description === undefined ? {} : { description: model.description },
|
|
226
|
-
contextWindow: model.inputTokenLimit ?? model.maxInputTokens ?? ANTIGRAVITY_CONTEXT_WINDOW,
|
|
227
|
-
inputModalities: ['text', 'image'],
|
|
228
|
-
}));
|
|
229
|
-
if (models.length === 0)
|
|
230
|
-
throw new Error('Antigravity models endpoint returned an empty catalog');
|
|
231
|
-
return models;
|
|
232
|
-
}
|
|
233
|
-
function resetTime(value) {
|
|
234
|
-
if (typeof value !== 'string')
|
|
235
|
-
return undefined;
|
|
236
|
-
const parsed = Date.parse(value);
|
|
237
|
-
return Number.isFinite(parsed) ? parsed : undefined;
|
|
238
|
-
}
|
|
239
|
-
function usageWindow(kind, scope, quota) {
|
|
240
|
-
const remaining = quota?.remainingFraction;
|
|
241
|
-
if (typeof remaining !== 'number' || !Number.isFinite(remaining))
|
|
242
|
-
return undefined;
|
|
243
|
-
const resetsAt = resetTime(quota?.resetTime);
|
|
244
|
-
return {
|
|
245
|
-
kind,
|
|
246
|
-
scope,
|
|
247
|
-
usedPercent: Math.max(0, Math.min(100, (1 - remaining) * 100)),
|
|
248
|
-
...resetsAt === undefined ? {} : { resetsAt },
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
/** Fetch plan and per-model quota windows when the upstream exposes them. */
|
|
252
|
-
export async function fetchAntigravityUsage(session, runtime = {}, fetchFn = proxiedFetch, signal) {
|
|
253
|
-
const metadata = { ideType: 'ANTIGRAVITY', platform: 'PLATFORM_UNSPECIFIED', pluginType: 'GEMINI' };
|
|
254
|
-
const [models, account] = await Promise.all([
|
|
255
|
-
callInternal('fetchAvailableModels', { project: session.projectId }, session.accessToken, runtime, fetchFn, signal),
|
|
256
|
-
callInternal('loadCodeAssist', { metadata }, session.accessToken, runtime, fetchFn, signal),
|
|
257
|
-
]);
|
|
258
|
-
const windows = [];
|
|
259
|
-
for (const [modelId, model] of Object.entries(models.models ?? {})) {
|
|
260
|
-
const ordinary = usageWindow('other', modelId, model.quotaInfo);
|
|
261
|
-
const weekly = usageWindow('weekly', modelId, model.weeklyQuotaInfo ?? model.weeklyQuota);
|
|
262
|
-
if (ordinary !== undefined)
|
|
263
|
-
windows.push(ordinary);
|
|
264
|
-
if (weekly !== undefined)
|
|
265
|
-
windows.push(weekly);
|
|
266
|
-
}
|
|
267
|
-
const plan = account.paidTier?.name ?? account.paidTier?.id
|
|
268
|
-
?? account.currentTier?.name ?? account.currentTier?.id ?? session.plan;
|
|
269
|
-
const credits = account.paidTier?.availableCredits?.[0]?.creditAmount;
|
|
270
|
-
const displayPlan = credits === undefined ? plan : `${plan ?? 'Antigravity'} · ${String(credits)} credits`;
|
|
271
|
-
return {
|
|
272
|
-
supported: true,
|
|
273
|
-
windows,
|
|
274
|
-
...displayPlan === undefined ? {} : { plan: displayPlan },
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
/** URL for either v1internal generation transport. */
|
|
278
|
-
export function antigravityGenerateURL(baseURL, stream) {
|
|
279
|
-
return `${antigravityBaseURL(baseURL)}/v1internal:${stream ? 'streamGenerateContent?alt=sse' : 'generateContent'}`;
|
|
280
|
-
}
|
|
281
|
-
/** Forward one already-built payload to generateContent or streamGenerateContent. */
|
|
282
|
-
export async function requestAntigravityContent(session, payload, stream, runtime = {}, fetchFn = proxiedFetch, signal) {
|
|
283
|
-
return fetchFn(antigravityGenerateURL(runtime.baseURL, stream), {
|
|
284
|
-
method: 'POST',
|
|
285
|
-
headers: {
|
|
286
|
-
...antigravityHeaders(session.accessToken, runtime.userAgent),
|
|
287
|
-
accept: stream ? 'text/event-stream' : 'application/json',
|
|
288
|
-
},
|
|
289
|
-
body: JSON.stringify(payload),
|
|
290
|
-
...signal === undefined ? {} : { signal },
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
/** DSH provider adapter for the `antigravity` route. */
|
|
294
|
-
export class AntigravityAdapter extends LlmAdapter {
|
|
295
|
-
options;
|
|
296
|
-
catalog;
|
|
297
|
-
constructor(options) {
|
|
298
|
-
super();
|
|
299
|
-
this.options = options;
|
|
300
|
-
this.catalog = new ModelCatalogCache(options.catalogStore);
|
|
301
|
-
}
|
|
302
|
-
providerInfo(provider) {
|
|
303
|
-
return { id: provider, name: 'Google Antigravity' };
|
|
304
|
-
}
|
|
305
|
-
staticModels(provider) {
|
|
306
|
-
return this.options.models.map(model => ({
|
|
307
|
-
provider,
|
|
308
|
-
id: model.id,
|
|
309
|
-
name: model.name ?? model.id,
|
|
310
|
-
inputModalities: model.inputModalities ?? ['text', 'image'],
|
|
311
|
-
}));
|
|
312
|
-
}
|
|
313
|
-
fetchCatalog() {
|
|
314
|
-
return this.options.tokens.session().then(session => fetchAntigravityModels(session, this.options.runtime, this.options.fetchFn));
|
|
315
|
-
}
|
|
316
|
-
async listModels(provider) {
|
|
317
|
-
if (await this.options.tokens.peek() === undefined)
|
|
318
|
-
return [];
|
|
319
|
-
if (!this.options.discovery)
|
|
320
|
-
return this.staticModels(provider);
|
|
321
|
-
try {
|
|
322
|
-
const models = await discoverOrRetryAuth(force => this.options.tokens.session(force), this.catalog, () => this.catalog.get(() => this.fetchCatalog()));
|
|
323
|
-
return models.map(model => ({
|
|
324
|
-
provider,
|
|
325
|
-
id: model.id,
|
|
326
|
-
name: model.name,
|
|
327
|
-
...model.description === undefined ? {} : { description: model.description },
|
|
328
|
-
inputModalities: model.inputModalities ?? ['text', 'image'],
|
|
329
|
-
}));
|
|
330
|
-
}
|
|
331
|
-
catch (error) {
|
|
332
|
-
if (isMissingOrInvalidCredential(error))
|
|
333
|
-
return [];
|
|
334
|
-
this.options.onWarn?.(`Antigravity model discovery failed; using the built-in catalog (${errorChain(error)})`);
|
|
335
|
-
return this.staticModels(provider);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
async discovered(model) {
|
|
339
|
-
if (!this.options.discovery)
|
|
340
|
-
return undefined;
|
|
341
|
-
const models = await this.catalog.resolve(() => this.fetchCatalog());
|
|
342
|
-
return models?.find(entry => entry.id === model);
|
|
343
|
-
}
|
|
344
|
-
async resolveModel(provider, model) {
|
|
345
|
-
const discovered = await this.discovered(model);
|
|
346
|
-
const configured = this.options.models.find(entry => entry.id === model);
|
|
347
|
-
return {
|
|
348
|
-
provider,
|
|
349
|
-
id: model,
|
|
350
|
-
name: discovered?.name ?? configured?.name ?? model,
|
|
351
|
-
...discovered?.description === undefined ? {} : { description: discovered.description },
|
|
352
|
-
inputModalities: discovered?.inputModalities ?? configured?.inputModalities ?? ['text', 'image'],
|
|
353
|
-
context: { contextWindow: discovered?.contextWindow ?? configured?.contextWindow ?? ANTIGRAVITY_CONTEXT_WINDOW },
|
|
354
|
-
defaultMaxTokens: configured?.maxTokens ?? ANTIGRAVITY_DEFAULT_MAX_TOKENS,
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
async *stream(options) {
|
|
358
|
-
const watchdog = idleWatchdog(options.signal, this.options.streamIdleTimeoutMs);
|
|
359
|
-
try {
|
|
360
|
-
let session = await this.options.tokens.session();
|
|
361
|
-
const messages = await resolveImages(options.messages, this.options.resolveAttachments?.(), watchdog.signal);
|
|
362
|
-
const payload = toAntigravityRequest(options, messages, session.projectId);
|
|
363
|
-
let response = await requestAntigravityContent(session, payload, true, this.options.runtime, this.options.fetchFn, watchdog.signal);
|
|
364
|
-
if (response.status === 401) {
|
|
365
|
-
this.catalog.invalidate();
|
|
366
|
-
session = await this.options.tokens.session(true);
|
|
367
|
-
response = await requestAntigravityContent(session, payload, true, this.options.runtime, this.options.fetchFn, watchdog.signal);
|
|
368
|
-
}
|
|
369
|
-
if (!response.ok)
|
|
370
|
-
throw await httpLlmError(response, 'Antigravity API');
|
|
371
|
-
if (response.body === null) {
|
|
372
|
-
throw new LlmError('Antigravity API returned no response body', EMPTY_RESPONSE_CODE);
|
|
373
|
-
}
|
|
374
|
-
yield* streamAntigravity(response.body, () => { watchdog.pulse(); });
|
|
375
|
-
}
|
|
376
|
-
catch (error) {
|
|
377
|
-
throw mapFetchFailure('Antigravity API', error, watchdog, options.signal);
|
|
378
|
-
}
|
|
379
|
-
finally {
|
|
380
|
-
watchdog.stop();
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
/** Non-stream forwarding seam used by tests and future DSH complete calls. */
|
|
384
|
-
async generate(options) {
|
|
385
|
-
const session = await this.options.tokens.session();
|
|
386
|
-
const messages = await resolveImages(options.messages, this.options.resolveAttachments?.(), options.signal);
|
|
387
|
-
const response = await requestAntigravityContent(session, toAntigravityRequest(options, messages, session.projectId), false, this.options.runtime, this.options.fetchFn, options.signal);
|
|
388
|
-
if (!response.ok)
|
|
389
|
-
throw await httpLlmError(response, 'Antigravity API');
|
|
390
|
-
return parseAntigravityResponse(await response.json());
|
|
391
|
-
}
|
|
392
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DeepSeek Harness message/tool vocabulary to Antigravity's Gemini-shaped
|
|
3
|
-
* v1internal request envelope, plus response/SSE translation back to the
|
|
4
|
-
* harness streaming contract.
|
|
5
|
-
*/
|
|
6
|
-
import type { GenerateOptions, StreamChunk, TokenUsage, ToolSchema } from '@deepseek-ai/dsh-llm';
|
|
7
|
-
import type { TranslatableMessage } from './resolved.js';
|
|
8
|
-
/** Minimal Gemini part shape used by v1internal. */
|
|
9
|
-
export interface AntigravityPart {
|
|
10
|
-
text?: string;
|
|
11
|
-
thought?: boolean;
|
|
12
|
-
thoughtSignature?: string;
|
|
13
|
-
inlineData?: {
|
|
14
|
-
mimeType: string;
|
|
15
|
-
data: string;
|
|
16
|
-
};
|
|
17
|
-
functionCall?: {
|
|
18
|
-
id?: string;
|
|
19
|
-
name?: string;
|
|
20
|
-
args?: unknown;
|
|
21
|
-
};
|
|
22
|
-
functionResponse?: {
|
|
23
|
-
id: string;
|
|
24
|
-
name: string;
|
|
25
|
-
response: unknown;
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
/** Full Antigravity request envelope. */
|
|
29
|
-
export interface AntigravityRequest {
|
|
30
|
-
project: string;
|
|
31
|
-
requestId: string;
|
|
32
|
-
model: string;
|
|
33
|
-
userAgent: 'antigravity';
|
|
34
|
-
requestType: 'agent';
|
|
35
|
-
request: {
|
|
36
|
-
contents: {
|
|
37
|
-
role: 'user' | 'model';
|
|
38
|
-
parts: AntigravityPart[];
|
|
39
|
-
}[];
|
|
40
|
-
sessionId: string;
|
|
41
|
-
systemInstruction?: {
|
|
42
|
-
parts: {
|
|
43
|
-
text: string;
|
|
44
|
-
}[];
|
|
45
|
-
};
|
|
46
|
-
tools?: {
|
|
47
|
-
functionDeclarations: Record<string, unknown>[];
|
|
48
|
-
}[];
|
|
49
|
-
toolConfig?: {
|
|
50
|
-
functionCallingConfig: {
|
|
51
|
-
mode: 'VALIDATED';
|
|
52
|
-
};
|
|
53
|
-
};
|
|
54
|
-
generationConfig?: Record<string, unknown>;
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
/** Map harness tool schemas to Gemini function declarations. */
|
|
58
|
-
export declare function toAntigravityTools(tools: readonly ToolSchema[]): {
|
|
59
|
-
functionDeclarations: Record<string, unknown>[];
|
|
60
|
-
}[];
|
|
61
|
-
/**
|
|
62
|
-
* Convert resolved harness messages into Gemini contents. Function response
|
|
63
|
-
* names are recovered from prior tool calls because DSH correlates results by
|
|
64
|
-
* id while the Gemini wire requires both id and name.
|
|
65
|
-
*/
|
|
66
|
-
export declare function toAntigravityContents(messages: readonly TranslatableMessage[]): {
|
|
67
|
-
role: 'user' | 'model';
|
|
68
|
-
parts: AntigravityPart[];
|
|
69
|
-
}[];
|
|
70
|
-
/** Build one v1internal generateContent/streamGenerateContent request. */
|
|
71
|
-
export declare function toAntigravityRequest(options: GenerateOptions, messages: readonly TranslatableMessage[], projectId: string): AntigravityRequest;
|
|
72
|
-
/** Antigravity SSE/non-stream response subset. */
|
|
73
|
-
export interface AntigravityResponseEvent {
|
|
74
|
-
response?: {
|
|
75
|
-
candidates?: {
|
|
76
|
-
content?: {
|
|
77
|
-
parts?: AntigravityPart[];
|
|
78
|
-
};
|
|
79
|
-
finishReason?: string;
|
|
80
|
-
}[];
|
|
81
|
-
usageMetadata?: {
|
|
82
|
-
promptTokenCount?: number;
|
|
83
|
-
candidatesTokenCount?: number;
|
|
84
|
-
thoughtsTokenCount?: number;
|
|
85
|
-
totalTokenCount?: number;
|
|
86
|
-
cachedContentTokenCount?: number;
|
|
87
|
-
};
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
/** Map Gemini usage metadata to the harness's disjoint counters. */
|
|
91
|
-
export declare function mapAntigravityUsage(metadata: NonNullable<NonNullable<AntigravityResponseEvent['response']>['usageMetadata']>): TokenUsage;
|
|
92
|
-
/** Push translator for both parsed SSE events and one non-stream response. */
|
|
93
|
-
export declare class AntigravityStreamTranslator {
|
|
94
|
-
private blocks;
|
|
95
|
-
private closed;
|
|
96
|
-
private nextIndex;
|
|
97
|
-
private sawContent;
|
|
98
|
-
private sawToolCall;
|
|
99
|
-
terminated: boolean;
|
|
100
|
-
private open;
|
|
101
|
-
private close;
|
|
102
|
-
private closeAll;
|
|
103
|
-
private finish;
|
|
104
|
-
/** Process one decoded Antigravity response frame. */
|
|
105
|
-
push(event: AntigravityResponseEvent): StreamChunk[];
|
|
106
|
-
}
|
|
107
|
-
/** Consume Antigravity's SSE response into the DSH streaming contract. */
|
|
108
|
-
export declare function streamAntigravity(stream: ReadableStream<Uint8Array>, onActivity?: () => void): AsyncGenerator<StreamChunk>;
|
|
109
|
-
/** Translate a non-stream generateContent response using the same state machine. */
|
|
110
|
-
export declare function parseAntigravityResponse(event: AntigravityResponseEvent): StreamChunk[];
|