@providerkit/core 0.24.0 → 0.25.1
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 -0
- package/dist/auth/device.d.ts +3 -2
- package/dist/auth/device.d.ts.map +1 -1
- package/dist/auth/device.js +5 -2
- package/dist/auth/device.js.map +1 -1
- package/dist/auth/flows.d.ts +5 -1
- package/dist/auth/flows.d.ts.map +1 -1
- package/dist/auth/flows.js +237 -0
- package/dist/auth/flows.js.map +1 -1
- package/dist/auth/oauth.d.ts +4 -2
- package/dist/auth/oauth.d.ts.map +1 -1
- package/dist/auth/oauth.js +4 -3
- package/dist/auth/oauth.js.map +1 -1
- package/dist/auth/with-token.js +5 -3
- package/dist/auth/with-token.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -0
- package/dist/errors.js.map +1 -1
- package/dist/presets.d.ts +53 -0
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +100 -0
- package/dist/presets.js.map +1 -1
- package/dist/providers/factory.d.ts +16 -1
- package/dist/providers/factory.d.ts.map +1 -1
- package/dist/providers/factory.js +176 -18
- package/dist/providers/factory.js.map +1 -1
- package/dist/providers/gemini.d.ts +23 -5
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +247 -119
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +4 -3
- package/dist/providers/openai.js.map +1 -1
- package/dist/schema.d.ts +27 -9
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +197 -62
- package/dist/schema.js.map +1 -1
- package/package.json +1 -1
- package/src/auth/device.ts +8 -4
- package/src/auth/flows.ts +288 -1
- package/src/auth/oauth.ts +8 -3
- package/src/auth/with-token.ts +5 -3
- package/src/errors.ts +3 -0
- package/src/presets.ts +100 -0
- package/src/providers/factory.ts +233 -20
- package/src/providers/gemini.ts +280 -124
- package/src/providers/openai.ts +5 -3
- package/src/schema.ts +200 -72
package/src/auth/flows.ts
CHANGED
|
@@ -40,7 +40,14 @@ export interface AuthFlow {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export type AuthFlowId =
|
|
43
|
-
|
|
43
|
+
| "chatgpt"
|
|
44
|
+
| "kimi-plan"
|
|
45
|
+
| "grok"
|
|
46
|
+
| "github-copilot"
|
|
47
|
+
| "meta"
|
|
48
|
+
| "openrouter"
|
|
49
|
+
| "opencode-zen"
|
|
50
|
+
| "antigravity";
|
|
44
51
|
|
|
45
52
|
export function createAuthFlow(id: AuthFlowId, host: AuthHost): AuthFlow {
|
|
46
53
|
switch (id) {
|
|
@@ -66,6 +73,10 @@ export function createAuthFlow(id: AuthFlowId, host: AuthHost): AuthFlow {
|
|
|
66
73
|
);
|
|
67
74
|
case "openrouter":
|
|
68
75
|
return openrouterFlow(host);
|
|
76
|
+
case "opencode-zen":
|
|
77
|
+
return deviceFlow(host, OPENCODE_ZEN_DEVICE, opencodeZenCredential, opencodeZenRefresh(host));
|
|
78
|
+
case "antigravity":
|
|
79
|
+
return antigravityFlow(host);
|
|
69
80
|
}
|
|
70
81
|
}
|
|
71
82
|
|
|
@@ -518,6 +529,282 @@ function openrouterFlow(host: AuthHost): AuthFlow {
|
|
|
518
529
|
};
|
|
519
530
|
}
|
|
520
531
|
|
|
532
|
+
// ── OpenCode Console (Zen / Go): device code ──────────────────────────────
|
|
533
|
+
// Matches `opencode auth login opencode` in OpenCode v2 (`packages/core/src/plugin/provider/opencode.ts`)
|
|
534
|
+
// and `cc-proxy auth login opencode-zen --device`. The Console returns a relative
|
|
535
|
+
// `verification_uri_complete` (`/console/device?user_code=…&client_id=opencode-cli`),
|
|
536
|
+
// which `requestDeviceCode` resolves against `deviceUrl`.
|
|
537
|
+
|
|
538
|
+
const OPENCODE_ZEN_DEVICE: DeviceEndpoint = {
|
|
539
|
+
clientId: "opencode-cli",
|
|
540
|
+
deviceUrl: "https://opencode.ai/console/auth/device/code",
|
|
541
|
+
tokenUrl: "https://opencode.ai/console/auth/device/token",
|
|
542
|
+
extra: { supports_org_scope: true },
|
|
543
|
+
encode: "json",
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
function opencodeZenCredential(
|
|
547
|
+
body: Record<string, unknown>,
|
|
548
|
+
fallbackRefresh?: string,
|
|
549
|
+
): Credential {
|
|
550
|
+
const accessToken = str(body.access_token);
|
|
551
|
+
if (!accessToken) {
|
|
552
|
+
throw authError("token_incomplete", "OpenCode Console's reply has no access token.");
|
|
553
|
+
}
|
|
554
|
+
const refreshToken = str(body.refresh_token) ?? fallbackRefresh ?? "";
|
|
555
|
+
const expiresIn = num(body.expires_in);
|
|
556
|
+
const expiresAt =
|
|
557
|
+
refreshToken && expiresIn !== undefined
|
|
558
|
+
? Date.now() + expiresIn * 1000 - REFRESH_SKEW_MS
|
|
559
|
+
: NEVER;
|
|
560
|
+
const account = str(body.org_id) ?? accountFromToken(accessToken, "email", "sub");
|
|
561
|
+
return {
|
|
562
|
+
accessToken,
|
|
563
|
+
refreshToken,
|
|
564
|
+
expiresAt,
|
|
565
|
+
...(account ? { account } : {}),
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function opencodeZenRefresh(host: AuthHost): AuthFlow["refresh"] {
|
|
570
|
+
return async (credential) => {
|
|
571
|
+
if (!credential.refreshToken) return credential;
|
|
572
|
+
const body = await postToken(
|
|
573
|
+
host,
|
|
574
|
+
OPENCODE_ZEN_DEVICE.tokenUrl,
|
|
575
|
+
{
|
|
576
|
+
client_id: OPENCODE_ZEN_DEVICE.clientId,
|
|
577
|
+
grant_type: "refresh_token",
|
|
578
|
+
refresh_token: credential.refreshToken,
|
|
579
|
+
},
|
|
580
|
+
{ encode: "json" },
|
|
581
|
+
);
|
|
582
|
+
const fresh = opencodeZenCredential(body, credential.refreshToken);
|
|
583
|
+
return credential.account && !fresh.account ? { ...fresh, account: credential.account } : fresh;
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// ── Google Antigravity (Cloud Code Assist): PKCE + project discovery ──────
|
|
588
|
+
// Mirrors `cc-proxy/src/providers/antigravity.rs` and `opencodex/src/oauth/google-antigravity.ts`.
|
|
589
|
+
// Signs in with Google OAuth PKCE using the public Antigravity desktop client,
|
|
590
|
+
// then discovers the Cloud Code Assist `projectId` via `loadCodeAssist` (with
|
|
591
|
+
// `onboardUser` fallback for accounts without a project yet).
|
|
592
|
+
|
|
593
|
+
const ANTIGRAVITY = {
|
|
594
|
+
clientId: [
|
|
595
|
+
"1071006060591-",
|
|
596
|
+
"tmhssin2h21lcre235vtolojh4g403ep",
|
|
597
|
+
".apps.google",
|
|
598
|
+
"usercontent.com",
|
|
599
|
+
].join(""),
|
|
600
|
+
clientSecret: ["GOCS", "PX-", "K58FWR486LdL", "J1mLB8sXC4z6qDAf"].join(""),
|
|
601
|
+
authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
602
|
+
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
603
|
+
redirectUri: "http://127.0.0.1:51121/callback",
|
|
604
|
+
prodApi: "https://cloudcode-pa.googleapis.com",
|
|
605
|
+
dailyApi: "https://daily-cloudcode-pa.googleapis.com",
|
|
606
|
+
apiVersion: "v1internal",
|
|
607
|
+
ideUserAgent:
|
|
608
|
+
"antigravity/ide/2.5.5 (os_type=windows; arch=amd64; aidev_client; auth_method=oauth)",
|
|
609
|
+
scopes: [
|
|
610
|
+
"https://www.googleapis.com/auth/cloud-platform",
|
|
611
|
+
"https://www.googleapis.com/auth/userinfo.email",
|
|
612
|
+
"https://www.googleapis.com/auth/userinfo.profile",
|
|
613
|
+
"https://www.googleapis.com/auth/cclog",
|
|
614
|
+
"https://www.googleapis.com/auth/experimentsandconfigs",
|
|
615
|
+
].join(" "),
|
|
616
|
+
onboardAttempts: 5,
|
|
617
|
+
onboardPollMs: 2_000,
|
|
618
|
+
} as const;
|
|
619
|
+
|
|
620
|
+
/** The authorize URL to open for Google Antigravity. Exported so tests can pin the exact params. */
|
|
621
|
+
export function antigravityAuthorizeUrl(challenge: string, state: string): string {
|
|
622
|
+
const params = new URLSearchParams({
|
|
623
|
+
response_type: "code",
|
|
624
|
+
client_id: ANTIGRAVITY.clientId,
|
|
625
|
+
redirect_uri: ANTIGRAVITY.redirectUri,
|
|
626
|
+
scope: ANTIGRAVITY.scopes,
|
|
627
|
+
code_challenge: challenge,
|
|
628
|
+
code_challenge_method: "S256",
|
|
629
|
+
access_type: "offline",
|
|
630
|
+
prompt: "consent",
|
|
631
|
+
state,
|
|
632
|
+
});
|
|
633
|
+
return `${ANTIGRAVITY.authorizeUrl}?${params.toString()}`;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function extractAntigravityProjectId(data: Record<string, unknown>): string | undefined {
|
|
637
|
+
for (const key of ["cloudaicompanionProject", "projectId", "project"]) {
|
|
638
|
+
const val = data[key];
|
|
639
|
+
const direct = str(val);
|
|
640
|
+
if (direct) return direct;
|
|
641
|
+
const nested = str(asRecord(val).id);
|
|
642
|
+
if (nested) return nested;
|
|
643
|
+
}
|
|
644
|
+
return undefined;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/** Discover the Cloud Code Assist project for an Antigravity access token. */
|
|
648
|
+
export async function discoverAntigravityProject(
|
|
649
|
+
host: AuthHost,
|
|
650
|
+
accessToken: string,
|
|
651
|
+
signal?: AbortSignal,
|
|
652
|
+
): Promise<string | undefined> {
|
|
653
|
+
const headers = {
|
|
654
|
+
Authorization: `Bearer ${accessToken}`,
|
|
655
|
+
Accept: "application/json",
|
|
656
|
+
"Content-Type": "application/json",
|
|
657
|
+
"User-Agent": ANTIGRAVITY.ideUserAgent,
|
|
658
|
+
};
|
|
659
|
+
try {
|
|
660
|
+
const loadRes = await authFetch(
|
|
661
|
+
host,
|
|
662
|
+
`${ANTIGRAVITY.prodApi}/${ANTIGRAVITY.apiVersion}:loadCodeAssist`,
|
|
663
|
+
{
|
|
664
|
+
method: "POST",
|
|
665
|
+
headers,
|
|
666
|
+
body: JSON.stringify({ metadata: { ideType: "ANTIGRAVITY" } }),
|
|
667
|
+
...(signal ? { signal } : {}),
|
|
668
|
+
},
|
|
669
|
+
);
|
|
670
|
+
if (loadRes.ok) {
|
|
671
|
+
const payload = asRecord(parseJson(await loadRes.text().catch(() => "")));
|
|
672
|
+
const found = extractAntigravityProjectId(payload);
|
|
673
|
+
if (found) return found;
|
|
674
|
+
}
|
|
675
|
+
} catch (err) {
|
|
676
|
+
if (signal?.aborted) throw err;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
for (let attempt = 0; attempt < ANTIGRAVITY.onboardAttempts; attempt++) {
|
|
680
|
+
if (signal?.aborted) throw signal.reason ?? new Error("Aborted");
|
|
681
|
+
try {
|
|
682
|
+
const onboardRes = await authFetch(
|
|
683
|
+
host,
|
|
684
|
+
`${ANTIGRAVITY.dailyApi}/${ANTIGRAVITY.apiVersion}:onboardUser`,
|
|
685
|
+
{
|
|
686
|
+
method: "POST",
|
|
687
|
+
headers,
|
|
688
|
+
body: JSON.stringify({
|
|
689
|
+
tier_id: "free-tier",
|
|
690
|
+
metadata: {
|
|
691
|
+
ide_type: "ANTIGRAVITY",
|
|
692
|
+
ide_name: "antigravity",
|
|
693
|
+
ide_version: "2.5.5",
|
|
694
|
+
},
|
|
695
|
+
}),
|
|
696
|
+
...(signal ? { signal } : {}),
|
|
697
|
+
},
|
|
698
|
+
);
|
|
699
|
+
if (onboardRes.ok) {
|
|
700
|
+
const payload = asRecord(parseJson(await onboardRes.text().catch(() => "")));
|
|
701
|
+
if (payload.done === true) {
|
|
702
|
+
const found = extractAntigravityProjectId(asRecord(payload.response));
|
|
703
|
+
if (found) return found;
|
|
704
|
+
}
|
|
705
|
+
} else if (onboardRes.status !== 429 && onboardRes.status < 500) {
|
|
706
|
+
return undefined;
|
|
707
|
+
}
|
|
708
|
+
} catch (err) {
|
|
709
|
+
if (signal?.aborted) throw err;
|
|
710
|
+
}
|
|
711
|
+
if (attempt + 1 < ANTIGRAVITY.onboardAttempts) {
|
|
712
|
+
await waitMs(ANTIGRAVITY.onboardPollMs, signal);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
return undefined;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
function waitMs(ms: number, signal?: AbortSignal): Promise<void> {
|
|
719
|
+
return new Promise((resolve, reject) => {
|
|
720
|
+
if (signal?.aborted) {
|
|
721
|
+
reject(signal.reason ?? new Error("Aborted"));
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
const timer = setTimeout(() => {
|
|
725
|
+
signal?.removeEventListener("abort", onAbort);
|
|
726
|
+
resolve();
|
|
727
|
+
}, ms);
|
|
728
|
+
const onAbort = () => {
|
|
729
|
+
clearTimeout(timer);
|
|
730
|
+
reject(signal?.reason ?? new Error("Aborted"));
|
|
731
|
+
};
|
|
732
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
function antigravityFlow(host: AuthHost): AuthFlow {
|
|
737
|
+
const tokenRequest = (params: Record<string, string>) =>
|
|
738
|
+
postToken(
|
|
739
|
+
host,
|
|
740
|
+
ANTIGRAVITY.tokenUrl,
|
|
741
|
+
{
|
|
742
|
+
client_id: ANTIGRAVITY.clientId,
|
|
743
|
+
client_secret: ANTIGRAVITY.clientSecret,
|
|
744
|
+
...params,
|
|
745
|
+
},
|
|
746
|
+
{ encode: "form" },
|
|
747
|
+
);
|
|
748
|
+
|
|
749
|
+
return {
|
|
750
|
+
async signIn(signal, onPrompt) {
|
|
751
|
+
const { verifier, challenge } = await generatePKCE();
|
|
752
|
+
const state = randomState();
|
|
753
|
+
const authorizeUrl = antigravityAuthorizeUrl(challenge, state);
|
|
754
|
+
onPrompt({ url: authorizeUrl });
|
|
755
|
+
const code = await host.captureRedirect({
|
|
756
|
+
authorizeUrl,
|
|
757
|
+
redirectUri: ANTIGRAVITY.redirectUri,
|
|
758
|
+
state,
|
|
759
|
+
signal,
|
|
760
|
+
});
|
|
761
|
+
const body = await tokenRequest({
|
|
762
|
+
grant_type: "authorization_code",
|
|
763
|
+
code,
|
|
764
|
+
redirect_uri: ANTIGRAVITY.redirectUri,
|
|
765
|
+
code_verifier: verifier,
|
|
766
|
+
});
|
|
767
|
+
const credential = antigravityCredential(body);
|
|
768
|
+
const projectId = await discoverAntigravityProject(host, credential.accessToken, signal);
|
|
769
|
+
if (!projectId) {
|
|
770
|
+
throw authError(
|
|
771
|
+
"setup_required",
|
|
772
|
+
"Antigravity login could not discover a Cloud Code Assist project for this Google account.",
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
return { ...credential, projectId };
|
|
776
|
+
},
|
|
777
|
+
async refresh(credential) {
|
|
778
|
+
const body = await tokenRequest({
|
|
779
|
+
grant_type: "refresh_token",
|
|
780
|
+
refresh_token: credential.refreshToken,
|
|
781
|
+
});
|
|
782
|
+
const fresh = antigravityCredential(body, credential.refreshToken, credential.account);
|
|
783
|
+
const projectId =
|
|
784
|
+
credential.projectId ??
|
|
785
|
+
(await discoverAntigravityProject(host, fresh.accessToken).catch(() => undefined));
|
|
786
|
+
return projectId ? { ...fresh, projectId } : fresh;
|
|
787
|
+
},
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
function antigravityCredential(
|
|
792
|
+
body: Record<string, unknown>,
|
|
793
|
+
fallbackRefresh?: string,
|
|
794
|
+
fallbackAccount?: string,
|
|
795
|
+
): Credential {
|
|
796
|
+
const credential = toCredential(
|
|
797
|
+
{ ...body, expires_in: num(body.expires_in) ?? GROK_DEFAULT_LIFETIME_SEC },
|
|
798
|
+
fallbackRefresh,
|
|
799
|
+
);
|
|
800
|
+
const idToken = str(body.id_token);
|
|
801
|
+
const account =
|
|
802
|
+
accountFromToken(idToken, "email") ??
|
|
803
|
+
accountFromToken(credential.accessToken, "email") ??
|
|
804
|
+
fallbackAccount;
|
|
805
|
+
return account ? { ...credential, account } : credential;
|
|
806
|
+
}
|
|
807
|
+
|
|
521
808
|
function parseJson(text: string): unknown {
|
|
522
809
|
try {
|
|
523
810
|
return JSON.parse(text);
|
package/src/auth/oauth.ts
CHANGED
|
@@ -42,6 +42,8 @@ export interface Credential {
|
|
|
42
42
|
account?: string;
|
|
43
43
|
/** ChatGPT only: send it as the `ChatGPT-Account-Id` header. */
|
|
44
44
|
chatgptAccountId?: string;
|
|
45
|
+
/** Google Antigravity only: the Cloud Code Assist project id for the envelope. */
|
|
46
|
+
projectId?: string;
|
|
45
47
|
/** Set when the vendor gives each account its own host (Copilot). */
|
|
46
48
|
baseUrl?: string;
|
|
47
49
|
}
|
|
@@ -137,17 +139,19 @@ function toBase64Url(bytes: Uint8Array): string {
|
|
|
137
139
|
export async function postToken(
|
|
138
140
|
host: AuthHost,
|
|
139
141
|
url: string,
|
|
140
|
-
params: Record<string, string>,
|
|
142
|
+
params: Record<string, string | boolean>,
|
|
141
143
|
opts: { encode: "json" | "form"; allowErrorBody?: boolean },
|
|
142
144
|
): Promise<Record<string, unknown>> {
|
|
143
145
|
const json = opts.encode === "json";
|
|
146
|
+
const formEntries = () =>
|
|
147
|
+
Object.entries(params).map(([k, v]): [string, string] => [k, String(v)]);
|
|
144
148
|
const res = await authFetch(host, url, {
|
|
145
149
|
method: "POST",
|
|
146
150
|
headers: {
|
|
147
151
|
"Content-Type": json ? "application/json" : "application/x-www-form-urlencoded",
|
|
148
152
|
Accept: "application/json",
|
|
149
153
|
},
|
|
150
|
-
body: json ? JSON.stringify(params) : new URLSearchParams(
|
|
154
|
+
body: json ? JSON.stringify(params) : new URLSearchParams(formEntries()).toString(),
|
|
151
155
|
});
|
|
152
156
|
const text = await res.text().catch(() => "");
|
|
153
157
|
const record = asRecord(safeJson(text));
|
|
@@ -237,10 +241,11 @@ export function accountFromToken(
|
|
|
237
241
|
export function webUrl(
|
|
238
242
|
value: string | undefined,
|
|
239
243
|
protocols = ["https:", "http:"],
|
|
244
|
+
base?: string,
|
|
240
245
|
): string | undefined {
|
|
241
246
|
if (!value) return undefined;
|
|
242
247
|
try {
|
|
243
|
-
const url = new URL(value);
|
|
248
|
+
const url = base ? new URL(value, base) : new URL(value);
|
|
244
249
|
return protocols.includes(url.protocol) ? url.href : undefined;
|
|
245
250
|
} catch {
|
|
246
251
|
return undefined;
|
package/src/auth/with-token.ts
CHANGED
|
@@ -71,12 +71,14 @@ export function withToken<C extends Credential>(
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
function authOf(credential: Credential): TokenAuth {
|
|
74
|
+
const headers: Record<string, string> = {
|
|
75
|
+
...(credential.chatgptAccountId ? { "ChatGPT-Account-Id": credential.chatgptAccountId } : {}),
|
|
76
|
+
...(credential.projectId ? { "x-antigravity-project": credential.projectId } : {}),
|
|
77
|
+
};
|
|
74
78
|
return {
|
|
75
79
|
apiKey: credential.accessToken,
|
|
76
80
|
...(credential.baseUrl ? { baseUrl: credential.baseUrl } : {}),
|
|
77
|
-
...(
|
|
78
|
-
? { headers: { "ChatGPT-Account-Id": credential.chatgptAccountId } }
|
|
79
|
-
: {}),
|
|
81
|
+
...(Object.keys(headers).length > 0 ? { headers } : {}),
|
|
80
82
|
};
|
|
81
83
|
}
|
|
82
84
|
|
package/src/errors.ts
CHANGED
|
@@ -349,6 +349,9 @@ const CONTEXT_PATTERNS: readonly RegExp[] = [
|
|
|
349
349
|
// shipped the same two patterns for the same reason (0.1.51).
|
|
350
350
|
/model_max_prompt_tokens_exceeded/i,
|
|
351
351
|
/prompt token count of \d+ exceeds the limit/i,
|
|
352
|
+
// Gemini: "The input token count exceeds the maximum number of tokens allowed 1048576."
|
|
353
|
+
// The generic pattern below stops at "maximum number", so this read as `invalid`.
|
|
354
|
+
/input token count exceeds the maximum number of tokens/i,
|
|
352
355
|
// Scoped to the thing that overflowed: a bare "exceeds the maximum" also
|
|
353
356
|
// covers image counts and per-minute token rates, which compaction can't fix.
|
|
354
357
|
/exceeds? the (?:model'?s? )?maximum (?:input |prompt |context )?(?:tokens?|length|context)/i,
|
package/src/presets.ts
CHANGED
|
@@ -431,6 +431,82 @@ export const PROVIDER_PRESETS = {
|
|
|
431
431
|
// privacy setting, and answers 500 without it.
|
|
432
432
|
rotation: ["mimo-v2.6-flash", "mimo-v2.5", "glm-5.3-flash", "qwen3.8-flash", "longcat-2.0"],
|
|
433
433
|
},
|
|
434
|
+
/**
|
|
435
|
+
* OpenCode Zen: free and pay-as-you-go models on `https://opencode.ai/zen/v1`,
|
|
436
|
+
* matching cc-proxy's `opencode-zen` provider.
|
|
437
|
+
*
|
|
438
|
+
* Free models (`big-pickle` and every `-free` id) lead the list and the default
|
|
439
|
+
* rotation. Zen's free tier requires the OpenCode CLI headers, a `ses_` session
|
|
440
|
+
* id and a `read` tool on the request; the factory adds those automatically and
|
|
441
|
+
* retries a free model anonymously if a stale key answers 401.
|
|
442
|
+
*
|
|
443
|
+
* `routes` picks each model's wire from its id: `claude-` and Qwen (except
|
|
444
|
+
* `qwen3.8-max`) on Anthropic `/v1/messages`, `gpt-`, `grok-` and `muse-` on
|
|
445
|
+
* `/v1/responses`, `gemini-` on `/v1/models/<id>:streamGenerateContent?alt=sse`,
|
|
446
|
+
* and everything else on `/v1/chat/completions`.
|
|
447
|
+
*/
|
|
448
|
+
"opencode-zen": {
|
|
449
|
+
shape: "openai",
|
|
450
|
+
baseUrl: "https://opencode.ai/zen/v1",
|
|
451
|
+
auth: "bearer",
|
|
452
|
+
defaultModel: "minimax-m3.1-flash-free",
|
|
453
|
+
models: [
|
|
454
|
+
"minimax-m3.1-flash-free",
|
|
455
|
+
"mimo-v2.6-flash-free",
|
|
456
|
+
"deepseek-v4.1-flash-free",
|
|
457
|
+
"glm-5.3-flash-free",
|
|
458
|
+
"big-pickle",
|
|
459
|
+
"mimo-v2.5-free",
|
|
460
|
+
"nemotron-3.5-super-vl-free",
|
|
461
|
+
"nemotron-3.5-lightning-free",
|
|
462
|
+
"longcat-2.5-preview-free",
|
|
463
|
+
"beam-free",
|
|
464
|
+
"ll-alpha-free",
|
|
465
|
+
"exo-free",
|
|
466
|
+
"nemotron-3-ultra-free",
|
|
467
|
+
"claude-sonnet-5-5",
|
|
468
|
+
"claude-opus-5-5",
|
|
469
|
+
"claude-fable-5-1",
|
|
470
|
+
"claude-haiku-5-5",
|
|
471
|
+
"gpt-6-sol",
|
|
472
|
+
"gpt-5.6-luna",
|
|
473
|
+
"gemini-4-argon",
|
|
474
|
+
"gemini-3.8-flash",
|
|
475
|
+
"grok-4.7",
|
|
476
|
+
"glm-5.3-flash",
|
|
477
|
+
"deepseek-v4.1-flash",
|
|
478
|
+
"kimi-k3",
|
|
479
|
+
"minimax-m3",
|
|
480
|
+
"qwen3.8-flash",
|
|
481
|
+
],
|
|
482
|
+
sessionHeader: "x-opencode-session",
|
|
483
|
+
routes: [
|
|
484
|
+
{
|
|
485
|
+
prefixes: ["claude-", "qwen3.8-flash", "qwen3.7", "qwen3.6", "qwen3.5"],
|
|
486
|
+
shape: "anthropic",
|
|
487
|
+
baseUrl: "https://opencode.ai/zen",
|
|
488
|
+
auth: "key",
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
prefixes: ["gpt-", "grok-", "muse-"],
|
|
492
|
+
shape: "responses",
|
|
493
|
+
baseUrl: "https://opencode.ai/zen",
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
prefixes: ["gemini-"],
|
|
497
|
+
shape: "gemini",
|
|
498
|
+
baseUrl: "https://opencode.ai/zen/v1",
|
|
499
|
+
auth: "key",
|
|
500
|
+
},
|
|
501
|
+
],
|
|
502
|
+
rotation: [
|
|
503
|
+
"minimax-m3.1-flash-free",
|
|
504
|
+
"mimo-v2.6-flash-free",
|
|
505
|
+
"deepseek-v4.1-flash-free",
|
|
506
|
+
"big-pickle",
|
|
507
|
+
"glm-5.3-flash-free",
|
|
508
|
+
],
|
|
509
|
+
},
|
|
434
510
|
kimi: {
|
|
435
511
|
shape: "anthropic",
|
|
436
512
|
baseUrl: "https://api.kimi.ai/coding",
|
|
@@ -617,6 +693,30 @@ export const PROVIDER_PRESETS = {
|
|
|
617
693
|
},
|
|
618
694
|
initiatorHeader: true,
|
|
619
695
|
},
|
|
696
|
+
/**
|
|
697
|
+
* Google Antigravity (Cloud Code Assist) OAuth, matching cc-proxy's
|
|
698
|
+
* `antigravity` provider. Sign in with `createAuthFlow("antigravity", host)`
|
|
699
|
+
* from `@providerkit/core/auth`, which discovers the Cloud Code Assist
|
|
700
|
+
* `projectId` and stores it on the credential; `withToken` and `createRegistry`
|
|
701
|
+
* forward it automatically.
|
|
702
|
+
*/
|
|
703
|
+
antigravity: {
|
|
704
|
+
shape: "gemini",
|
|
705
|
+
baseUrl: "https://daily-cloudcode-pa.googleapis.com",
|
|
706
|
+
path: "/v1internal:streamGenerateContent?alt=sse",
|
|
707
|
+
auth: "oauth",
|
|
708
|
+
defaultModel: "gemini-4-argon",
|
|
709
|
+
models: [
|
|
710
|
+
"gemini-4-argon",
|
|
711
|
+
"gemini-3.8-flash",
|
|
712
|
+
"gemini-3.7-flash",
|
|
713
|
+
"gemini-3.1-pro",
|
|
714
|
+
"claude-opus-5-5",
|
|
715
|
+
"claude-sonnet-5-5",
|
|
716
|
+
"claude-sonnet-4-6",
|
|
717
|
+
"claude-opus-4-6-thinking",
|
|
718
|
+
],
|
|
719
|
+
},
|
|
620
720
|
} as const satisfies Record<string, ProviderPreset>;
|
|
621
721
|
|
|
622
722
|
export type ProviderPresetId = keyof typeof PROVIDER_PRESETS;
|