@gajae-code/ai 0.18.11 → 0.19.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/CHANGELOG.md +103 -0
- package/README.md +1 -1
- package/dist/types/auth-broker/wire-schemas.d.ts +30 -0
- package/dist/types/auth-storage.d.ts +98 -13
- package/dist/types/bedrock-claude-cache-policy.d.ts +1 -1
- package/dist/types/model-cache.d.ts +6 -4
- package/dist/types/model-manager.d.ts +2 -0
- package/dist/types/model-pricing.d.ts +8 -0
- package/dist/types/model-thinking.d.ts +11 -0
- package/dist/types/openai-completions-compat.d.ts +2 -1
- package/dist/types/provider-models/google.d.ts +2 -0
- package/dist/types/providers/amazon-bedrock.d.ts +17 -2
- package/dist/types/providers/anthropic.d.ts +25 -0
- package/dist/types/providers/aws-credential-config.d.ts +5 -0
- package/dist/types/providers/google-auth.d.ts +7 -0
- package/dist/types/providers/google-gemini-headers.d.ts +11 -6
- package/dist/types/providers/kiro-api-key.d.ts +5 -0
- package/dist/types/providers/openai-chat-server-schema.d.ts +2 -1
- package/dist/types/providers/openai-completions.d.ts +1 -1
- package/dist/types/providers/openai-responses-shared.d.ts +2 -1
- package/dist/types/stream.d.ts +33 -1
- package/dist/types/types.d.ts +26 -3
- package/dist/types/usage.d.ts +3 -0
- package/dist/types/utils/discovery/antigravity.d.ts +16 -1
- package/dist/types/utils/idle-iterator.d.ts +3 -2
- package/dist/types/utils/oauth/glm-zcode.d.ts +0 -30
- package/dist/types/utils/oauth/types.d.ts +9 -0
- package/package.json +4 -4
- package/src/auth-broker/remote-store.ts +62 -11
- package/src/auth-broker/wire-schemas.ts +2 -0
- package/src/auth-gateway/server.ts +3 -2
- package/src/auth-storage.ts +908 -246
- package/src/bedrock-claude-cache-policy.d.ts +1 -1
- package/src/bedrock-claude-cache-policy.ts +2 -2
- package/src/model-cache.ts +45 -10
- package/src/model-manager.ts +18 -6
- package/src/model-pricing.d.ts +8 -0
- package/src/model-pricing.ts +87 -0
- package/src/model-thinking.d.ts +11 -0
- package/src/model-thinking.ts +97 -12
- package/src/models.json +3176 -1670
- package/src/models.ts +10 -3
- package/src/openai-completions-compat.d.ts +2 -1
- package/src/openai-completions-compat.ts +5 -0
- package/src/provider-models/google.ts +11 -1
- package/src/provider-models/openai-compat.ts +26 -0
- package/src/providers/amazon-bedrock.d.ts +17 -2
- package/src/providers/amazon-bedrock.ts +76 -16
- package/src/providers/anthropic.d.ts +25 -0
- package/src/providers/anthropic.ts +230 -18
- package/src/providers/aws-credential-config.d.ts +5 -0
- package/src/providers/aws-credential-config.ts +29 -1
- package/src/providers/google-auth.d.ts +7 -0
- package/src/providers/google-auth.ts +165 -4
- package/src/providers/google-gemini-headers.d.ts +11 -6
- package/src/providers/google-gemini-headers.ts +16 -11
- package/src/providers/google-vertex.ts +2 -4
- package/src/providers/kiro-api-key.d.ts +5 -0
- package/src/providers/kiro-api-key.ts +379 -68
- package/src/providers/ollama.ts +19 -9
- package/src/providers/openai-anthropic-shim.ts +1 -0
- package/src/providers/openai-chat-server-schema.ts +1 -1
- package/src/providers/openai-chat-server.ts +14 -2
- package/src/providers/openai-codex-responses.ts +21 -14
- package/src/providers/openai-completions.d.ts +1 -1
- package/src/providers/openai-completions.ts +65 -4
- package/src/providers/openai-responses-server.ts +10 -1
- package/src/providers/openai-responses-shared.d.ts +2 -1
- package/src/providers/openai-responses-shared.ts +42 -1
- package/src/providers/openai-responses.ts +51 -10
- package/src/providers/pi-native-server.ts +1 -1
- package/src/providers/transform-messages.ts +32 -1
- package/src/stream.d.ts +33 -1
- package/src/stream.ts +111 -17
- package/src/types.d.ts +26 -3
- package/src/types.ts +55 -2
- package/src/usage/claude.ts +4 -2
- package/src/usage.ts +3 -0
- package/src/utils/discovery/antigravity.ts +192 -7
- package/src/utils/idle-iterator.d.ts +3 -2
- package/src/utils/idle-iterator.ts +30 -10
- package/src/utils/oauth/anthropic.ts +23 -22
- package/src/utils/oauth/api-key-validation.ts +34 -11
- package/src/utils/oauth/glm-zcode.d.ts +0 -30
- package/src/utils/oauth/glm-zcode.ts +15 -4
- package/src/utils/oauth/openai-codex.ts +41 -6
- package/src/utils/oauth/types.d.ts +9 -0
- package/src/utils/oauth/types.ts +9 -0
- package/src/utils/parse-bind.d.ts +35 -0
- package/src/utils/proxy.ts +35 -6
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { Buffer } from "node:buffer";
|
|
18
|
+
import * as fs from "node:fs/promises";
|
|
18
19
|
import * as path from "node:path";
|
|
19
20
|
import { $credentialEnv, $envpos, getTrustedHomeDir, isEnoent, logger } from "@gajae-code/utils";
|
|
20
21
|
import type { FetchImpl } from "../types";
|
|
@@ -22,6 +23,10 @@ import type { FetchImpl } from "../types";
|
|
|
22
23
|
const OAUTH_TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
23
24
|
const STS_TOKEN_URL = "https://sts.googleapis.com/v1/token";
|
|
24
25
|
const METADATA_TOKEN_URL = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token";
|
|
26
|
+
const METADATA_PROJECT_ID_URL = "http://metadata.google.internal/computeMetadata/v1/project/project-id";
|
|
27
|
+
const METADATA_SERVICE_ACCOUNT_EMAIL_URL =
|
|
28
|
+
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email";
|
|
29
|
+
const VERTEX_LOCATION_RE = /^[a-z0-9-]+$/;
|
|
25
30
|
const CLOUD_PLATFORM_SCOPE = "https://www.googleapis.com/auth/cloud-platform";
|
|
26
31
|
const JWT_BEARER_GRANT = "urn:ietf:params:oauth:grant-type:jwt-bearer";
|
|
27
32
|
const TOKEN_EXCHANGE_GRANT = "urn:ietf:params:oauth:grant-type:token-exchange";
|
|
@@ -37,6 +42,8 @@ interface CachedToken {
|
|
|
37
42
|
expiresAtMs: number;
|
|
38
43
|
}
|
|
39
44
|
|
|
45
|
+
export type VertexCredentialSource = "explicit-file" | "default-file" | "metadata-server";
|
|
46
|
+
|
|
40
47
|
interface ServiceAccountCredentials {
|
|
41
48
|
type: "service_account";
|
|
42
49
|
client_email: string;
|
|
@@ -115,6 +122,11 @@ interface TokenResponse {
|
|
|
115
122
|
const tokenCache = new Map<string, CachedToken>();
|
|
116
123
|
const inflight = new Map<string, Promise<string>>();
|
|
117
124
|
|
|
125
|
+
/** Match the region-label constraint used before Vertex interpolates a location into the request host. */
|
|
126
|
+
export function isValidVertexLocation(location: string): boolean {
|
|
127
|
+
return VERTEX_LOCATION_RE.test(location);
|
|
128
|
+
}
|
|
129
|
+
|
|
118
130
|
function getRefreshSkewMs(): number {
|
|
119
131
|
return $envpos("GOOGLE_VERTEX_REFRESH_SKEW_MS", 60_000);
|
|
120
132
|
}
|
|
@@ -132,6 +144,82 @@ async function readJsonFile<T>(filePath: string): Promise<T | undefined> {
|
|
|
132
144
|
}
|
|
133
145
|
}
|
|
134
146
|
|
|
147
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
148
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function isNonEmptyString(value: unknown): value is string {
|
|
152
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function isSubjectTokenFormat(value: unknown): value is SubjectTokenFormat {
|
|
156
|
+
if (!isRecord(value)) return false;
|
|
157
|
+
if (value.type !== undefined && value.type !== "text" && value.type !== "json") return false;
|
|
158
|
+
if (value.subject_token_field_name !== undefined && !isNonEmptyString(value.subject_token_field_name)) return false;
|
|
159
|
+
return value.type !== "json" || isNonEmptyString(value.subject_token_field_name);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function isCredentialSource(value: unknown): value is CredentialSource {
|
|
163
|
+
if (!isRecord(value)) return false;
|
|
164
|
+
if ("file" in value) {
|
|
165
|
+
return isNonEmptyString(value.file) && (value.format === undefined || isSubjectTokenFormat(value.format));
|
|
166
|
+
}
|
|
167
|
+
if ("url" in value) {
|
|
168
|
+
if (!isNonEmptyString(value.url) || (value.format !== undefined && !isSubjectTokenFormat(value.format)))
|
|
169
|
+
return false;
|
|
170
|
+
if (value.headers === undefined) return true;
|
|
171
|
+
return isRecord(value.headers) && Object.values(value.headers).every(header => typeof header === "string");
|
|
172
|
+
}
|
|
173
|
+
if ("executable" in value) {
|
|
174
|
+
const executable = value.executable;
|
|
175
|
+
if (!isRecord(executable) || !isNonEmptyString(executable.command)) return false;
|
|
176
|
+
if (executable.timeout_millis !== undefined && typeof executable.timeout_millis !== "number") {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
return executable.output_file === undefined || typeof executable.output_file === "string";
|
|
180
|
+
}
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Validate the credential fields required by the ADC resolvers supported here. */
|
|
185
|
+
function isSupportedAdcFileCredentials(value: unknown): value is AdcFileCredentials {
|
|
186
|
+
if (!isRecord(value)) return false;
|
|
187
|
+
switch (value.type) {
|
|
188
|
+
case "service_account":
|
|
189
|
+
return isNonEmptyString(value.client_email) && isNonEmptyString(value.private_key);
|
|
190
|
+
case "authorized_user":
|
|
191
|
+
return (
|
|
192
|
+
isNonEmptyString(value.client_id) &&
|
|
193
|
+
isNonEmptyString(value.client_secret) &&
|
|
194
|
+
isNonEmptyString(value.refresh_token)
|
|
195
|
+
);
|
|
196
|
+
case "external_account":
|
|
197
|
+
return (
|
|
198
|
+
isNonEmptyString(value.audience) &&
|
|
199
|
+
isNonEmptyString(value.subject_token_type) &&
|
|
200
|
+
isCredentialSource(value.credential_source)
|
|
201
|
+
);
|
|
202
|
+
default:
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function isAvailableAdcFileCredentialSource(credentials: AdcFileCredentials): Promise<boolean> {
|
|
208
|
+
if (credentials.type !== "external_account") return true;
|
|
209
|
+
const source = credentials.credential_source;
|
|
210
|
+
if ("executable" in source) return $credentialEnv("GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES") === "1";
|
|
211
|
+
if ("file" in source) {
|
|
212
|
+
try {
|
|
213
|
+
if (!(await fs.stat(source.file)).isFile()) return false;
|
|
214
|
+
extractSubjectToken(await fs.readFile(source.file, "utf8"), source.format, `file ${source.file}`);
|
|
215
|
+
return true;
|
|
216
|
+
} catch {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
|
|
135
223
|
/** Test seam: the ADC credentials file path as resolved from trusted env. */
|
|
136
224
|
export function resolveAdcCredentialsPathForTest(): string | undefined {
|
|
137
225
|
return $credentialEnv("GOOGLE_APPLICATION_CREDENTIALS");
|
|
@@ -146,15 +234,25 @@ async function loadAdcCredentials(): Promise<{ source: string; creds: AdcFileCre
|
|
|
146
234
|
// `stream.ts` already resolves the same variable through `$credentialEnv`.
|
|
147
235
|
const gacPath = $credentialEnv("GOOGLE_APPLICATION_CREDENTIALS");
|
|
148
236
|
if (gacPath) {
|
|
149
|
-
const
|
|
237
|
+
const value = await readJsonFile<unknown>(gacPath);
|
|
238
|
+
const creds = isSupportedAdcFileCredentials(value) ? value : undefined;
|
|
150
239
|
if (!creds) {
|
|
151
|
-
|
|
240
|
+
if (
|
|
241
|
+
isRecord(value) &&
|
|
242
|
+
typeof value.type === "string" &&
|
|
243
|
+
value.type !== "service_account" &&
|
|
244
|
+
value.type !== "authorized_user" &&
|
|
245
|
+
value.type !== "external_account"
|
|
246
|
+
) {
|
|
247
|
+
throw new Error(`Unsupported Google credential type "${value.type}"`);
|
|
248
|
+
}
|
|
249
|
+
throw new Error(`GOOGLE_APPLICATION_CREDENTIALS does not contain supported credentials: ${gacPath}`);
|
|
152
250
|
}
|
|
153
251
|
return { source: `gac:${gacPath}`, creds };
|
|
154
252
|
}
|
|
155
253
|
const userPath = userAdcPath();
|
|
156
|
-
const
|
|
157
|
-
if (
|
|
254
|
+
const value = await readJsonFile<unknown>(userPath);
|
|
255
|
+
if (isSupportedAdcFileCredentials(value)) return { source: `user:${userPath}`, creds: value };
|
|
158
256
|
return undefined;
|
|
159
257
|
}
|
|
160
258
|
|
|
@@ -244,6 +342,69 @@ async function fetchMetadataToken(
|
|
|
244
342
|
}
|
|
245
343
|
}
|
|
246
344
|
|
|
345
|
+
async function hasMetadataServer(fetchImpl: FetchImpl): Promise<boolean> {
|
|
346
|
+
const timeout = AbortSignal.timeout(1000);
|
|
347
|
+
try {
|
|
348
|
+
const projectResponse = await fetchImpl(METADATA_PROJECT_ID_URL, {
|
|
349
|
+
method: "GET",
|
|
350
|
+
headers: { "Metadata-Flavor": "Google" },
|
|
351
|
+
redirect: "error",
|
|
352
|
+
signal: timeout,
|
|
353
|
+
});
|
|
354
|
+
if (
|
|
355
|
+
!projectResponse.ok ||
|
|
356
|
+
projectResponse.headers.get("Metadata-Flavor")?.toLowerCase() !== "google" ||
|
|
357
|
+
!(await projectResponse.text()).trim()
|
|
358
|
+
) {
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
const identityResponse = await fetchImpl(METADATA_SERVICE_ACCOUNT_EMAIL_URL, {
|
|
362
|
+
method: "GET",
|
|
363
|
+
headers: { "Metadata-Flavor": "Google" },
|
|
364
|
+
redirect: "error",
|
|
365
|
+
signal: timeout,
|
|
366
|
+
});
|
|
367
|
+
return (
|
|
368
|
+
identityResponse.ok &&
|
|
369
|
+
identityResponse.headers.get("Metadata-Flavor")?.toLowerCase() === "google" &&
|
|
370
|
+
Boolean((await identityResponse.text()).trim())
|
|
371
|
+
);
|
|
372
|
+
} catch {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function classifyCredentialSource(source: string): VertexCredentialSource | undefined {
|
|
378
|
+
if (source === "metadata") return "metadata-server";
|
|
379
|
+
if (source.startsWith("gac:")) return "explicit-file";
|
|
380
|
+
if (source.startsWith("user:")) return "default-file";
|
|
381
|
+
return undefined;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/** Resolve the source of a currently usable ADC credential without acquiring an access token. */
|
|
385
|
+
export async function getVertexCredentialSource(options?: {
|
|
386
|
+
fetch?: FetchImpl;
|
|
387
|
+
}): Promise<VertexCredentialSource | undefined> {
|
|
388
|
+
const now = Date.now();
|
|
389
|
+
const skew = getRefreshSkewMs();
|
|
390
|
+
for (const [source, cached] of tokenCache) {
|
|
391
|
+
if (cached.expiresAtMs - skew > now) return classifyCredentialSource(source);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
let adc: { source: string; creds: AdcFileCredentials } | undefined;
|
|
395
|
+
try {
|
|
396
|
+
adc = await loadAdcCredentials();
|
|
397
|
+
} catch {
|
|
398
|
+
return undefined;
|
|
399
|
+
}
|
|
400
|
+
if (adc) {
|
|
401
|
+
return (await isAvailableAdcFileCredentialSource(adc.creds)) ? classifyCredentialSource(adc.source) : undefined;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const fetchImpl = options?.fetch ?? globalThis.fetch.bind(globalThis);
|
|
405
|
+
return (await hasMetadataServer(fetchImpl)) ? "metadata-server" : undefined;
|
|
406
|
+
}
|
|
407
|
+
|
|
247
408
|
async function postForToken(
|
|
248
409
|
url: string,
|
|
249
410
|
body: URLSearchParams,
|
|
@@ -29,15 +29,20 @@ export declare const ANTIGRAVITY_SYSTEM_INSTRUCTION = "You are Antigravity, a po
|
|
|
29
29
|
/**
|
|
30
30
|
* Antigravity / Cloud Code Assist user agent.
|
|
31
31
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
32
|
+
* Field-evidence-based default: A/B/A test on Windows+Ultra (subscriber) confirmed that
|
|
33
|
+
* 'antigravity/cli/1.3.4 (os_type=darwin; arch=arm64; aidev_client; auth_method=oauth)'
|
|
34
|
+
* unlocks Gemini 4 Argon (low/medium/high) and Gemini 3.8 Flash (low/medium/high) models,
|
|
35
|
+
* plus Opus 5.5. Reverting to 'antigravity-ide' hides Argon models again. Pro accounts
|
|
36
|
+
* receive 'gemini-4-argon-disabled' with disabled:true, confirming the UA gates model
|
|
37
|
+
* visibility by account tier. The darwin/arm64 values were tested on Windows and worked,
|
|
38
|
+
* suggesting this is not platform-specific but rather a client identity string.
|
|
34
39
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
40
|
+
* Historical note: Disassembly (0x5ecb1dd) showed the IDE binary loads 'antigravity-ide';
|
|
41
|
+
* this appears to be outdated or a fallback for older clients.
|
|
37
42
|
*
|
|
38
|
-
*
|
|
43
|
+
* Overridable via PI_AI_ANTIGRAVITY_USER_AGENT environment variable.
|
|
39
44
|
*/
|
|
40
|
-
export declare
|
|
45
|
+
export declare function getAntigravityUserAgent(): string;
|
|
41
46
|
export declare const getAntigravityRequestHeaders: () => {
|
|
42
47
|
"User-Agent": string;
|
|
43
48
|
};
|
|
@@ -80,20 +80,25 @@ This means you do **NOT** need to poll in a loop while waiting for messages or u
|
|
|
80
80
|
/**
|
|
81
81
|
* Antigravity / Cloud Code Assist user agent.
|
|
82
82
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
83
|
+
* Field-evidence-based default: A/B/A test on Windows+Ultra (subscriber) confirmed that
|
|
84
|
+
* 'antigravity/cli/1.3.4 (os_type=darwin; arch=arm64; aidev_client; auth_method=oauth)'
|
|
85
|
+
* unlocks Gemini 4 Argon (low/medium/high) and Gemini 3.8 Flash (low/medium/high) models,
|
|
86
|
+
* plus Opus 5.5. Reverting to 'antigravity-ide' hides Argon models again. Pro accounts
|
|
87
|
+
* receive 'gemini-4-argon-disabled' with disabled:true, confirming the UA gates model
|
|
88
|
+
* visibility by account tier. The darwin/arm64 values were tested on Windows and worked,
|
|
89
|
+
* suggesting this is not platform-specific but rather a client identity string.
|
|
85
90
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
91
|
+
* Historical note: Disassembly (0x5ecb1dd) showed the IDE binary loads 'antigravity-ide';
|
|
92
|
+
* this appears to be outdated or a fallback for older clients.
|
|
88
93
|
*
|
|
89
|
-
*
|
|
94
|
+
* Overridable via PI_AI_ANTIGRAVITY_USER_AGENT environment variable.
|
|
90
95
|
*/
|
|
91
|
-
export
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
96
|
+
export function getAntigravityUserAgent(): string {
|
|
97
|
+
return (
|
|
98
|
+
process.env.PI_AI_ANTIGRAVITY_USER_AGENT ||
|
|
99
|
+
"antigravity/cli/1.3.4 (os_type=darwin; arch=arm64; aidev_client; auth_method=oauth)"
|
|
100
|
+
);
|
|
101
|
+
}
|
|
97
102
|
|
|
98
103
|
export const getAntigravityRequestHeaders = () => ({
|
|
99
104
|
"User-Agent": getAntigravityUserAgent(),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { $credentialEnv, $pickCredentialEnv } from "@gajae-code/utils";
|
|
2
2
|
import type { Context, Model, StreamFunction } from "../types";
|
|
3
3
|
import type { AssistantMessageEventStream } from "../utils/event-stream";
|
|
4
|
-
import { getVertexAccessToken } from "./google-auth";
|
|
4
|
+
import { getVertexAccessToken, isValidVertexLocation } from "./google-auth";
|
|
5
5
|
import {
|
|
6
6
|
buildGoogleGenerateContentParams,
|
|
7
7
|
type GoogleGenAIRequestPlan,
|
|
@@ -99,10 +99,8 @@ function resolveEndpointHost(location: string): string {
|
|
|
99
99
|
* Both halves are needed: trusted resolution keeps a repository from setting it,
|
|
100
100
|
* and the shape check keeps any source from turning a region into an authority.
|
|
101
101
|
*/
|
|
102
|
-
const VERTEX_LOCATION_RE = /^[a-z0-9-]+$/;
|
|
103
|
-
|
|
104
102
|
function assertVertexLocation(location: string): string {
|
|
105
|
-
if (!
|
|
103
|
+
if (!isValidVertexLocation(location)) {
|
|
106
104
|
throw new Error(
|
|
107
105
|
`Invalid Vertex AI location ${JSON.stringify(location)}. Expected a region label such as "us-central1" or "global".`,
|
|
108
106
|
);
|