superoc 0.1.24 → 0.1.26

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/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { describeError, is429Error, isStatusMessageRateLimited, shouldRetryForEr
3
3
  import { detectProviderForRequest, getProviderHeaders } from "./provider.js";
4
4
  import { authorizeAntigravity, exchangeAntigravity, getOrRefreshAntigravityAccessToken, getAntigravityHeaders, fetchLiveAntigravityModels, } from "./antigravity.js";
5
5
  import { BASE_ANTIGRAVITY_MODELS, syncOpencodeAuth } from "./opencode-sync.js";
6
+ import { startAntigravityProxy, PROXY_BASE_URL, PROXY_PORT } from "./proxy.js";
6
7
  const PROVIDERS = ["nvidia", "google", "antigravity"];
7
8
  const NIM_BASE_URL = "https://integrate.api.nvidia.com";
8
9
  const GEMINI_BASE_URL = "https://generativelanguage.googleapis.com";
@@ -74,6 +75,207 @@ function findChainIndex(chain, model) {
74
75
  return -1;
75
76
  return chain.findIndex((entry) => entry.id === model.modelID);
76
77
  }
78
+ export function createSseUnwrapTransform() {
79
+ const decoder = new TextDecoder();
80
+ const encoder = new TextEncoder();
81
+ let buffer = "";
82
+ return new TransformStream({
83
+ transform(chunk, controller) {
84
+ buffer += decoder.decode(chunk, { stream: true });
85
+ const lines = buffer.split("\n");
86
+ buffer = lines.pop() || "";
87
+ for (const line of lines) {
88
+ if (line.startsWith("data:")) {
89
+ const jsonStr = line.slice(5).trim();
90
+ if (!jsonStr) {
91
+ controller.enqueue(encoder.encode(line + "\n"));
92
+ continue;
93
+ }
94
+ try {
95
+ const parsed = JSON.parse(jsonStr);
96
+ if (parsed.response !== undefined) {
97
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(parsed.response)}\n`));
98
+ continue;
99
+ }
100
+ }
101
+ catch { }
102
+ }
103
+ controller.enqueue(encoder.encode(line + "\n"));
104
+ }
105
+ },
106
+ flush(controller) {
107
+ if (buffer.length > 0) {
108
+ if (buffer.startsWith("data:")) {
109
+ const jsonStr = buffer.slice(5).trim();
110
+ try {
111
+ const parsed = JSON.parse(jsonStr);
112
+ if (parsed.response !== undefined) {
113
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(parsed.response)}\n`));
114
+ return;
115
+ }
116
+ }
117
+ catch { }
118
+ }
119
+ controller.enqueue(encoder.encode(buffer));
120
+ }
121
+ },
122
+ });
123
+ }
124
+ export function createAntigravityFetch(store, config, reloadFromDisk, safeSaveStore) {
125
+ return async (input, init, fallbackFetch = fetch) => {
126
+ const urlString = typeof input === "string"
127
+ ? input
128
+ : input instanceof URL
129
+ ? input.toString()
130
+ : input.url;
131
+ if (urlString.includes("generativelanguage.googleapis.com") || urlString.includes("antigravity")) {
132
+ const match = urlString.match(/\/models\/([^:]+):(\w+)/);
133
+ const rawModel = match ? match[1] : "";
134
+ const action = match ? match[2] : "streamGenerateContent";
135
+ const isStreaming = action === "streamGenerateContent" || urlString.includes("alt=sse");
136
+ const isAntigravityModel = rawModel.startsWith("antigravity-") ||
137
+ rawModel in BASE_ANTIGRAVITY_MODELS ||
138
+ /claude|gpt-oss|gemini-3|gemini-pro-agent/i.test(rawModel);
139
+ reloadFromDisk();
140
+ const activeAntigravityKeys = getActiveKeys(store, "antigravity");
141
+ if (isAntigravityModel || activeAntigravityKeys.length > 0) {
142
+ if (init?.signal?.aborted) {
143
+ throw new DOMException("The operation was aborted.", "AbortError");
144
+ }
145
+ let attempts = 0;
146
+ let lastResponse = null;
147
+ const maxAttempts = Math.max(1, activeAntigravityKeys.length);
148
+ while (attempts < maxAttempts) {
149
+ if (init?.signal?.aborted) {
150
+ throw new DOMException("The operation was aborted.", "AbortError");
151
+ }
152
+ attempts++;
153
+ const next = getNextKey(store, config, rawModel, "antigravity");
154
+ if (!next)
155
+ break;
156
+ const authRes = await getOrRefreshAntigravityAccessToken(next.key.key);
157
+ if (!authRes) {
158
+ continue;
159
+ }
160
+ if (init?.signal?.aborted) {
161
+ throw new DOMException("The operation was aborted.", "AbortError");
162
+ }
163
+ const effectiveModel = rawModel.replace(/^antigravity-/, "");
164
+ const candidateModels = [effectiveModel];
165
+ if (!effectiveModel.endsWith("-tiered") &&
166
+ (effectiveModel.includes("flash") || effectiveModel.includes("pro"))) {
167
+ candidateModels.push(`${effectiveModel}-tiered`);
168
+ }
169
+ else if (effectiveModel.endsWith("-tiered")) {
170
+ candidateModels.push(effectiveModel.replace(/-tiered$/, ""));
171
+ }
172
+ let bodyStr = init?.body;
173
+ let parsedBody = typeof bodyStr === "string" ? JSON.parse(bodyStr) : bodyStr;
174
+ const headers = new Headers(init?.headers ?? {});
175
+ headers.set("Authorization", `Bearer ${authRes.accessToken}`);
176
+ headers.set("User-Agent", `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Antigravity/1.18.3 Chrome/138.0.7204.235 Electron/37.3.1 Safari/537.36`);
177
+ headers.set("X-Goog-Api-Client", "google-cloud-sdk vscode_cloudshelleditor/0.1");
178
+ headers.set("Client-Metadata", `{"ideType":"ANTIGRAVITY","platform":"WINDOWS","pluginType":"GEMINI"}`);
179
+ headers.delete("x-goog-api-key");
180
+ headers.delete("x-api-key");
181
+ headers.delete("x-goog-user-project");
182
+ headers.delete("host");
183
+ headers.delete("content-length");
184
+ headers.delete("connection");
185
+ headers.delete("transfer-encoding");
186
+ const endpoints = [
187
+ "https://daily-cloudcode-pa.sandbox.googleapis.com",
188
+ "https://cloudcode-pa.googleapis.com",
189
+ ];
190
+ let gotRes = null;
191
+ endpointLoop: for (const ep of endpoints) {
192
+ if (init?.signal?.aborted) {
193
+ throw new DOMException("The operation was aborted.", "AbortError");
194
+ }
195
+ for (const candidate of candidateModels) {
196
+ if (init?.signal?.aborted) {
197
+ throw new DOMException("The operation was aborted.", "AbortError");
198
+ }
199
+ const transformedUrl = `${ep}/v1internal:${action}${isStreaming ? "?alt=sse" : ""}`;
200
+ const wrappedBody = JSON.stringify({
201
+ project: authRes.projectId || "rising-fact-p41fc",
202
+ model: candidate,
203
+ request: parsedBody,
204
+ requestType: "agent",
205
+ userAgent: "antigravity",
206
+ });
207
+ try {
208
+ const r = await fetch(transformedUrl, {
209
+ ...init,
210
+ headers,
211
+ body: wrappedBody,
212
+ });
213
+ if (r.ok) {
214
+ gotRes = r;
215
+ break endpointLoop;
216
+ }
217
+ if (r.status === 429) {
218
+ gotRes = r;
219
+ }
220
+ }
221
+ catch (netErr) {
222
+ if (netErr?.name === "AbortError" || init?.signal?.aborted) {
223
+ throw netErr;
224
+ }
225
+ if (process.env.SUPEROC_DEBUG === "true") {
226
+ console.warn(`[superoc] Endpoint ${ep} socket/network error:`, netErr);
227
+ }
228
+ }
229
+ }
230
+ }
231
+ if (gotRes) {
232
+ lastResponse = gotRes;
233
+ }
234
+ if (gotRes && gotRes.ok) {
235
+ if (isStreaming && gotRes.body) {
236
+ const transformedStream = gotRes.body.pipeThrough(createSseUnwrapTransform());
237
+ return new Response(transformedStream, {
238
+ status: gotRes.status,
239
+ statusText: gotRes.statusText,
240
+ headers: gotRes.headers,
241
+ });
242
+ }
243
+ return gotRes;
244
+ }
245
+ if (gotRes && gotRes.status === 429) {
246
+ recordRateLimit(store, next.key.id);
247
+ recordModelRateLimit(store, next.key.id, rawModel);
248
+ safeSaveStore();
249
+ continue;
250
+ }
251
+ if (gotRes)
252
+ return gotRes;
253
+ }
254
+ if (isAntigravityModel) {
255
+ if (lastResponse)
256
+ return lastResponse;
257
+ return new Response(JSON.stringify({
258
+ error: {
259
+ code: 429,
260
+ message: "All Antigravity accounts are currently rate limited or exhausted.",
261
+ status: "RESOURCE_EXHAUSTED",
262
+ },
263
+ }), { status: 429, headers: { "Content-Type": "application/json" } });
264
+ }
265
+ }
266
+ }
267
+ return (fallbackFetch || fetch)(input, init);
268
+ };
269
+ }
270
+ export function installGlobalFetchInterceptor(fetchHandler) {
271
+ if (!globalThis.__superoc_fetch_installed) {
272
+ globalThis.__superoc_fetch_installed = true;
273
+ const origFetch = globalThis.fetch;
274
+ globalThis.fetch = async function (input, init) {
275
+ return fetchHandler(input, init, origFetch);
276
+ };
277
+ }
278
+ }
77
279
  export const SuperocPlugin = async (input, options) => {
78
280
  const client = input.client;
79
281
  const config = {
@@ -428,52 +630,6 @@ export const SuperocPlugin = async (input, options) => {
428
630
  const reason = `Rate limited (429) — ${state.rateLimitCount}/${store.maxRateLimitFailures} consecutive`;
429
631
  await triggerRetry(sessionID, state, reason);
430
632
  };
431
- function createSseUnwrapTransform() {
432
- const decoder = new TextDecoder();
433
- const encoder = new TextEncoder();
434
- let buffer = "";
435
- return new TransformStream({
436
- transform(chunk, controller) {
437
- buffer += decoder.decode(chunk, { stream: true });
438
- const lines = buffer.split("\n");
439
- buffer = lines.pop() || "";
440
- for (const line of lines) {
441
- if (line.startsWith("data:")) {
442
- const jsonStr = line.slice(5).trim();
443
- if (!jsonStr) {
444
- controller.enqueue(encoder.encode(line + "\n"));
445
- continue;
446
- }
447
- try {
448
- const parsed = JSON.parse(jsonStr);
449
- if (parsed.response !== undefined) {
450
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(parsed.response)}\n`));
451
- continue;
452
- }
453
- }
454
- catch { }
455
- }
456
- controller.enqueue(encoder.encode(line + "\n"));
457
- }
458
- },
459
- flush(controller) {
460
- if (buffer.length > 0) {
461
- if (buffer.startsWith("data:")) {
462
- const jsonStr = buffer.slice(5).trim();
463
- try {
464
- const parsed = JSON.parse(jsonStr);
465
- if (parsed.response !== undefined) {
466
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(parsed.response)}\n`));
467
- return;
468
- }
469
- }
470
- catch { }
471
- }
472
- controller.enqueue(encoder.encode(buffer));
473
- }
474
- },
475
- });
476
- }
477
633
  if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
478
634
  process.env.GOOGLE_GENERATIVE_AI_API_KEY = "antigravity-oauth";
479
635
  }
@@ -481,153 +637,9 @@ export const SuperocPlugin = async (input, options) => {
481
637
  process.env.GEMINI_API_KEY = "antigravity-oauth";
482
638
  }
483
639
  syncOpencodeAuth();
484
- const antigravityFetch = async (input, init, fallbackFetch = fetch) => {
485
- const urlString = typeof input === "string"
486
- ? input
487
- : input instanceof URL
488
- ? input.toString()
489
- : input.url;
490
- if (urlString.includes("generativelanguage.googleapis.com") || urlString.includes("antigravity")) {
491
- const match = urlString.match(/\/models\/([^:]+):(\w+)/);
492
- const rawModel = match ? match[1] : "";
493
- const action = match ? match[2] : "streamGenerateContent";
494
- const isStreaming = action === "streamGenerateContent" || urlString.includes("alt=sse");
495
- const isAntigravityModel = rawModel.startsWith("antigravity-") ||
496
- rawModel in BASE_ANTIGRAVITY_MODELS ||
497
- /claude|gpt-oss|gemini-3|gemini-pro-agent/i.test(rawModel);
498
- reloadFromDisk();
499
- const activeAntigravityKeys = getActiveKeys(store, "antigravity");
500
- if (isAntigravityModel || activeAntigravityKeys.length > 0) {
501
- if (init?.signal?.aborted) {
502
- throw new DOMException("The operation was aborted.", "AbortError");
503
- }
504
- let attempts = 0;
505
- let lastResponse = null;
506
- const maxAttempts = Math.max(1, activeAntigravityKeys.length);
507
- while (attempts < maxAttempts) {
508
- if (init?.signal?.aborted) {
509
- throw new DOMException("The operation was aborted.", "AbortError");
510
- }
511
- attempts++;
512
- const next = getNextKey(store, config, rawModel, "antigravity");
513
- if (!next)
514
- break;
515
- const authRes = await getOrRefreshAntigravityAccessToken(next.key.key);
516
- if (!authRes) {
517
- continue;
518
- }
519
- if (init?.signal?.aborted) {
520
- throw new DOMException("The operation was aborted.", "AbortError");
521
- }
522
- const effectiveModel = rawModel.replace(/^antigravity-/, "");
523
- const candidateModels = [effectiveModel];
524
- if (!effectiveModel.endsWith("-tiered") &&
525
- (effectiveModel.includes("flash") || effectiveModel.includes("pro"))) {
526
- candidateModels.push(`${effectiveModel}-tiered`);
527
- }
528
- else if (effectiveModel.endsWith("-tiered")) {
529
- candidateModels.push(effectiveModel.replace(/-tiered$/, ""));
530
- }
531
- let bodyStr = init?.body;
532
- let parsedBody = typeof bodyStr === "string" ? JSON.parse(bodyStr) : bodyStr;
533
- const headers = new Headers(init?.headers ?? {});
534
- headers.set("Authorization", `Bearer ${authRes.accessToken}`);
535
- headers.set("User-Agent", `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Antigravity/1.18.3 Chrome/138.0.7204.235 Electron/37.3.1 Safari/537.36`);
536
- headers.set("X-Goog-Api-Client", "google-cloud-sdk vscode_cloudshelleditor/0.1");
537
- headers.set("Client-Metadata", `{"ideType":"ANTIGRAVITY","platform":"WINDOWS","pluginType":"GEMINI"}`);
538
- headers.delete("x-goog-api-key");
539
- headers.delete("x-api-key");
540
- headers.delete("x-goog-user-project");
541
- const endpoints = [
542
- "https://daily-cloudcode-pa.sandbox.googleapis.com",
543
- "https://cloudcode-pa.googleapis.com",
544
- ];
545
- let gotRes = null;
546
- endpointLoop: for (const ep of endpoints) {
547
- if (init?.signal?.aborted) {
548
- throw new DOMException("The operation was aborted.", "AbortError");
549
- }
550
- for (const candidate of candidateModels) {
551
- if (init?.signal?.aborted) {
552
- throw new DOMException("The operation was aborted.", "AbortError");
553
- }
554
- const transformedUrl = `${ep}/v1internal:${action}${isStreaming ? "?alt=sse" : ""}`;
555
- const wrappedBody = JSON.stringify({
556
- project: authRes.projectId || "rising-fact-p41fc",
557
- model: candidate,
558
- request: parsedBody,
559
- requestType: "agent",
560
- userAgent: "antigravity",
561
- });
562
- try {
563
- const r = await fetch(transformedUrl, {
564
- ...init,
565
- headers,
566
- body: wrappedBody,
567
- });
568
- if (r.ok) {
569
- gotRes = r;
570
- break endpointLoop;
571
- }
572
- if (r.status === 429) {
573
- gotRes = r;
574
- }
575
- }
576
- catch (netErr) {
577
- if (netErr?.name === "AbortError" || init?.signal?.aborted) {
578
- throw netErr;
579
- }
580
- if (process.env.SUPEROC_DEBUG === "true") {
581
- console.warn(`[superoc] Endpoint ${ep} socket/network error:`, netErr);
582
- }
583
- }
584
- }
585
- }
586
- if (gotRes) {
587
- lastResponse = gotRes;
588
- }
589
- if (gotRes && gotRes.ok) {
590
- if (isStreaming && gotRes.body) {
591
- const transformedStream = gotRes.body.pipeThrough(createSseUnwrapTransform());
592
- return new Response(transformedStream, {
593
- status: gotRes.status,
594
- statusText: gotRes.statusText,
595
- headers: gotRes.headers,
596
- });
597
- }
598
- return gotRes;
599
- }
600
- if (gotRes && gotRes.status === 429) {
601
- recordRateLimit(store, next.key.id);
602
- recordModelRateLimit(store, next.key.id, rawModel);
603
- safeSaveStore();
604
- continue;
605
- }
606
- if (gotRes)
607
- return gotRes;
608
- }
609
- if (isAntigravityModel) {
610
- if (lastResponse)
611
- return lastResponse;
612
- return new Response(JSON.stringify({
613
- error: {
614
- code: 429,
615
- message: "All Antigravity accounts are currently rate limited or exhausted.",
616
- status: "RESOURCE_EXHAUSTED",
617
- },
618
- }), { status: 429, headers: { "Content-Type": "application/json" } });
619
- }
620
- }
621
- }
622
- return (fallbackFetch || fetch)(input, init);
623
- };
624
- if (!globalThis.__superoc_fetch_installed) {
625
- globalThis.__superoc_fetch_installed = true;
626
- const origFetch = globalThis.fetch;
627
- globalThis.fetch = async function (input, init) {
628
- return antigravityFetch(input, init, origFetch);
629
- };
630
- }
640
+ const antigravityFetch = createAntigravityFetch(store, config, reloadFromDisk, safeSaveStore);
641
+ installGlobalFetchInterceptor(antigravityFetch);
642
+ startAntigravityProxy(antigravityFetch);
631
643
  const hooks = {
632
644
  config: async (cfg) => {
633
645
  if (!process.env.OPENCODE_ENABLE_EXA) {
@@ -911,6 +923,281 @@ export const SuperocPlugin = async (input, options) => {
911
923
  };
912
924
  return hooks;
913
925
  };
926
+ export async function setupV2(context) {
927
+ const options = context.options ?? {};
928
+ const config = {
929
+ storePath: options.storePath,
930
+ rotationStrategy: isValidStrategy(options.rotationStrategy)
931
+ ? options.rotationStrategy
932
+ : "round-robin",
933
+ };
934
+ const store = loadStore(config) ?? getDefaultStore();
935
+ if (!store.fallbackChains)
936
+ store.fallbackChains = { nvidia: [], google: [], antigravity: [] };
937
+ const sessions = new Map();
938
+ const reloadFromDisk = () => {
939
+ let fresh = null;
940
+ try {
941
+ fresh = loadStore(config);
942
+ }
943
+ catch (err) {
944
+ console.debug("[superoc] Failed to reload store from disk:", err);
945
+ return;
946
+ }
947
+ if (fresh === null)
948
+ return;
949
+ try {
950
+ store.keys = fresh.keys;
951
+ store.currentIndex = fresh.currentIndex;
952
+ store.rotationStrategy = fresh.rotationStrategy;
953
+ store.updatedAt = fresh.updatedAt;
954
+ store.lastUsedKeyId = fresh.lastUsedKeyId;
955
+ store.fallbackChains = {
956
+ nvidia: Array.isArray(fresh.fallbackChains?.nvidia) ? fresh.fallbackChains.nvidia : [],
957
+ google: Array.isArray(fresh.fallbackChains?.google) ? fresh.fallbackChains.google : [],
958
+ antigravity: Array.isArray(fresh.fallbackChains?.antigravity) ? fresh.fallbackChains.antigravity : [],
959
+ };
960
+ store.maxRateLimitFailures =
961
+ typeof fresh.maxRateLimitFailures === "number" &&
962
+ Number.isFinite(fresh.maxRateLimitFailures) &&
963
+ fresh.maxRateLimitFailures >= 1
964
+ ? fresh.maxRateLimitFailures
965
+ : getDefaultStore().maxRateLimitFailures;
966
+ }
967
+ catch (err) {
968
+ console.debug("[superoc] Failed to apply reloaded store:", err);
969
+ }
970
+ };
971
+ const safeSaveStore = () => {
972
+ try {
973
+ saveStore(store, config);
974
+ }
975
+ catch (err) {
976
+ console.error("[superoc] Failed to save store:", err);
977
+ }
978
+ };
979
+ for (const provider of PROVIDERS) {
980
+ const activeKeys = getActiveKeys(store, provider);
981
+ if (activeKeys.length === 0) {
982
+ const envKey = process.env[getEnvKeyName(provider)];
983
+ if (envKey) {
984
+ const existing = store.keys.find((k) => k.name === "env-default" && k.provider === provider);
985
+ if (!existing) {
986
+ addKey(store, "env-default", envKey, provider);
987
+ safeSaveStore();
988
+ }
989
+ }
990
+ }
991
+ }
992
+ const getState = (sessionID) => {
993
+ const existing = sessions.get(sessionID);
994
+ if (existing)
995
+ return existing;
996
+ const next = {
997
+ attemptIndex: 0,
998
+ inRetry: false,
999
+ aborting: false,
1000
+ pendingRetryIndex: undefined,
1001
+ lastUserMessageID: undefined,
1002
+ activeChainKey: undefined,
1003
+ activeChainModelId: undefined,
1004
+ rateLimitCount: 0,
1005
+ currentModelId: undefined,
1006
+ lastFailedModelId: undefined,
1007
+ lastErrorHandledAt: 0,
1008
+ createdAt: Date.now(),
1009
+ sessionProviderId: undefined,
1010
+ lastUsedKeyId: undefined,
1011
+ };
1012
+ sessions.set(sessionID, next);
1013
+ return next;
1014
+ };
1015
+ // Seed environment variables
1016
+ if (!process.env.OPENCODE_ENABLE_EXA) {
1017
+ process.env.OPENCODE_ENABLE_EXA = "1";
1018
+ }
1019
+ if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
1020
+ process.env.GOOGLE_GENERATIVE_AI_API_KEY = "antigravity-oauth";
1021
+ }
1022
+ if (!process.env.GEMINI_API_KEY) {
1023
+ process.env.GEMINI_API_KEY = "antigravity-oauth";
1024
+ }
1025
+ syncOpencodeAuth();
1026
+ // Install global fetch interceptor & local proxy server
1027
+ const antigravityFetch = createAntigravityFetch(store, config, reloadFromDisk, safeSaveStore);
1028
+ installGlobalFetchInterceptor(antigravityFetch);
1029
+ startAntigravityProxy(antigravityFetch);
1030
+ // Shell hook in V2
1031
+ if (context.shell?.hook) {
1032
+ await context.shell.hook("create.before", async (input) => {
1033
+ if (input?.env) {
1034
+ input.env["OPENCODE_ENABLE_EXA"] = "1";
1035
+ reloadFromDisk();
1036
+ for (const provider of PROVIDERS) {
1037
+ const envKeyName = getEnvKeyName(provider);
1038
+ if (input.env[envKeyName] !== undefined || getActiveKeys(store, provider).length > 0) {
1039
+ const next = getNextKey(store, config, undefined, provider);
1040
+ if (next) {
1041
+ input.env[envKeyName] = next.key.key;
1042
+ safeSaveStore();
1043
+ }
1044
+ }
1045
+ }
1046
+ }
1047
+ });
1048
+ }
1049
+ // Session hooks in V2: http.request redirect and model.request auth injection
1050
+ if (context.session?.hook) {
1051
+ await context.session.hook("http.request", async (input) => {
1052
+ if (input.request?.url && input.request.url.includes("generativelanguage.googleapis.com")) {
1053
+ const newUrl = input.request.url.replace("https://generativelanguage.googleapis.com", `http://127.0.0.1:${PROXY_PORT}`);
1054
+ input.request = new Request(newUrl, input.request);
1055
+ }
1056
+ });
1057
+ await context.session.hook("model.request", async (input) => {
1058
+ const provider = detectProviderForRequest({
1059
+ provider: { info: { id: input.model?.providerID } },
1060
+ model: { providerID: input.model?.providerID, api: input.model?.modelID },
1061
+ });
1062
+ if (!provider)
1063
+ return;
1064
+ reloadFromDisk();
1065
+ const prevKeyId = store.lastUsedKeyId;
1066
+ const modelId = input.model?.modelID;
1067
+ const next = getNextKey(store, config, modelId, provider);
1068
+ if (next) {
1069
+ if (provider === "antigravity") {
1070
+ const authRes = await getOrRefreshAntigravityAccessToken(next.key.key);
1071
+ if (authRes) {
1072
+ const headers = getAntigravityHeaders(authRes.accessToken, authRes.projectId);
1073
+ input.headers = Object.assign(input.headers || {}, headers);
1074
+ }
1075
+ }
1076
+ else {
1077
+ const headers = getProviderHeaders(provider, next.key.key);
1078
+ input.headers = Object.assign(input.headers || {}, headers);
1079
+ }
1080
+ if (prevKeyId && prevKeyId !== next.key.id) {
1081
+ resetRateLimit(store, prevKeyId);
1082
+ }
1083
+ safeSaveStore();
1084
+ }
1085
+ if (input.sessionID) {
1086
+ const state = getState(input.sessionID);
1087
+ state.currentModelId = modelId;
1088
+ state.sessionProviderId = provider;
1089
+ if (next)
1090
+ state.lastUsedKeyId = next.key.id;
1091
+ }
1092
+ });
1093
+ // Session http.response hook in V2: monitor 429 rate limits
1094
+ await context.session.hook("http.response", async (input) => {
1095
+ if (input.response?.status === 429) {
1096
+ const state = input.sessionID ? sessions.get(input.sessionID) : undefined;
1097
+ const errorKeyId = state?.lastUsedKeyId ?? store.lastUsedKeyId;
1098
+ reloadFromDisk();
1099
+ if (errorKeyId) {
1100
+ recordRateLimit(store, errorKeyId);
1101
+ const modelForBlacklist = state?.currentModelId;
1102
+ if (modelForBlacklist) {
1103
+ recordModelRateLimit(store, errorKeyId, modelForBlacklist);
1104
+ }
1105
+ if (state)
1106
+ state.lastFailedModelId = modelForBlacklist;
1107
+ }
1108
+ safeSaveStore();
1109
+ }
1110
+ });
1111
+ // Session retry hook in V2: fallback model switching
1112
+ await context.session.hook("retry", async (input) => {
1113
+ const sessionID = input.sessionID;
1114
+ if (!sessionID)
1115
+ return;
1116
+ const state = getState(sessionID);
1117
+ const provider = state.sessionProviderId ?? "nvidia";
1118
+ const chain = store.fallbackChains[provider] || [];
1119
+ if (chain.length < 2)
1120
+ return;
1121
+ let nextIndex = (state.attemptIndex + 1) % chain.length;
1122
+ const target = chain[nextIndex];
1123
+ if (target && context.session?.switchModel) {
1124
+ state.attemptIndex = nextIndex;
1125
+ state.currentModelId = target.id;
1126
+ try {
1127
+ await context.session.switchModel({
1128
+ sessionID,
1129
+ model: { providerID: state.sessionProviderId ?? provider, modelID: target.id },
1130
+ });
1131
+ }
1132
+ catch (err) {
1133
+ console.debug("[superoc] switchModel failed:", err);
1134
+ }
1135
+ }
1136
+ });
1137
+ }
1138
+ // Provider & Model transform in V2
1139
+ if (context.provider?.transform) {
1140
+ await context.provider.transform((editor) => {
1141
+ const existing = editor.get?.("antigravity");
1142
+ if (!existing && editor.add) {
1143
+ editor.add({
1144
+ info: {
1145
+ id: "antigravity",
1146
+ name: "Antigravity",
1147
+ package: "aisdk:@ai-sdk/google",
1148
+ settings: {
1149
+ baseURL: PROXY_BASE_URL,
1150
+ },
1151
+ },
1152
+ models: [],
1153
+ });
1154
+ }
1155
+ });
1156
+ }
1157
+ if (context.model?.transform) {
1158
+ await context.model.transform((editor) => {
1159
+ for (const [id, def] of Object.entries(BASE_ANTIGRAVITY_MODELS)) {
1160
+ if (!editor.get?.("antigravity", id) && editor.update) {
1161
+ editor.update("antigravity", id, (draft) => {
1162
+ Object.assign(draft, {
1163
+ name: def.name,
1164
+ limit: def.limit,
1165
+ capabilities: {
1166
+ tools: true,
1167
+ input: ["text", "image", "pdf"],
1168
+ output: ["text"],
1169
+ },
1170
+ });
1171
+ });
1172
+ }
1173
+ }
1174
+ });
1175
+ }
1176
+ // Query live Antigravity models in background
1177
+ reloadFromDisk();
1178
+ const activeKeys = getActiveKeys(store, "antigravity");
1179
+ if (activeKeys.length > 0) {
1180
+ getOrRefreshAntigravityAccessToken(activeKeys[0].key)
1181
+ .then(async (auth) => {
1182
+ if (auth) {
1183
+ try {
1184
+ await fetchLiveAntigravityModels(auth.accessToken, auth.projectId);
1185
+ }
1186
+ catch { }
1187
+ }
1188
+ })
1189
+ .catch(() => { });
1190
+ }
1191
+ return () => {
1192
+ sessions.clear();
1193
+ };
1194
+ }
1195
+ export const SuperocPluginV2 = {
1196
+ id: "superoc",
1197
+ setup: setupV2,
1198
+ server: SuperocPlugin,
1199
+ };
914
1200
  export const NimSuperPlugin = SuperocPlugin;
915
- export default SuperocPlugin;
1201
+ export { SuperocPlugin as server };
1202
+ export default SuperocPluginV2;
916
1203
  //# sourceMappingURL=index.js.map