superoc 0.1.23 → 0.1.25

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
@@ -74,6 +74,203 @@ function findChainIndex(chain, model) {
74
74
  return -1;
75
75
  return chain.findIndex((entry) => entry.id === model.modelID);
76
76
  }
77
+ function createSseUnwrapTransform() {
78
+ const decoder = new TextDecoder();
79
+ const encoder = new TextEncoder();
80
+ let buffer = "";
81
+ return new TransformStream({
82
+ transform(chunk, controller) {
83
+ buffer += decoder.decode(chunk, { stream: true });
84
+ const lines = buffer.split("\n");
85
+ buffer = lines.pop() || "";
86
+ for (const line of lines) {
87
+ if (line.startsWith("data:")) {
88
+ const jsonStr = line.slice(5).trim();
89
+ if (!jsonStr) {
90
+ controller.enqueue(encoder.encode(line + "\n"));
91
+ continue;
92
+ }
93
+ try {
94
+ const parsed = JSON.parse(jsonStr);
95
+ if (parsed.response !== undefined) {
96
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(parsed.response)}\n`));
97
+ continue;
98
+ }
99
+ }
100
+ catch { }
101
+ }
102
+ controller.enqueue(encoder.encode(line + "\n"));
103
+ }
104
+ },
105
+ flush(controller) {
106
+ if (buffer.length > 0) {
107
+ if (buffer.startsWith("data:")) {
108
+ const jsonStr = buffer.slice(5).trim();
109
+ try {
110
+ const parsed = JSON.parse(jsonStr);
111
+ if (parsed.response !== undefined) {
112
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(parsed.response)}\n`));
113
+ return;
114
+ }
115
+ }
116
+ catch { }
117
+ }
118
+ controller.enqueue(encoder.encode(buffer));
119
+ }
120
+ },
121
+ });
122
+ }
123
+ function createAntigravityFetch(store, config, reloadFromDisk, safeSaveStore) {
124
+ return async (input, init, fallbackFetch = fetch) => {
125
+ const urlString = typeof input === "string"
126
+ ? input
127
+ : input instanceof URL
128
+ ? input.toString()
129
+ : input.url;
130
+ if (urlString.includes("generativelanguage.googleapis.com") || urlString.includes("antigravity")) {
131
+ const match = urlString.match(/\/models\/([^:]+):(\w+)/);
132
+ const rawModel = match ? match[1] : "";
133
+ const action = match ? match[2] : "streamGenerateContent";
134
+ const isStreaming = action === "streamGenerateContent" || urlString.includes("alt=sse");
135
+ const isAntigravityModel = rawModel.startsWith("antigravity-") ||
136
+ rawModel in BASE_ANTIGRAVITY_MODELS ||
137
+ /claude|gpt-oss|gemini-3|gemini-pro-agent/i.test(rawModel);
138
+ reloadFromDisk();
139
+ const activeAntigravityKeys = getActiveKeys(store, "antigravity");
140
+ if (isAntigravityModel || activeAntigravityKeys.length > 0) {
141
+ if (init?.signal?.aborted) {
142
+ throw new DOMException("The operation was aborted.", "AbortError");
143
+ }
144
+ let attempts = 0;
145
+ let lastResponse = null;
146
+ const maxAttempts = Math.max(1, activeAntigravityKeys.length);
147
+ while (attempts < maxAttempts) {
148
+ if (init?.signal?.aborted) {
149
+ throw new DOMException("The operation was aborted.", "AbortError");
150
+ }
151
+ attempts++;
152
+ const next = getNextKey(store, config, rawModel, "antigravity");
153
+ if (!next)
154
+ break;
155
+ const authRes = await getOrRefreshAntigravityAccessToken(next.key.key);
156
+ if (!authRes) {
157
+ continue;
158
+ }
159
+ if (init?.signal?.aborted) {
160
+ throw new DOMException("The operation was aborted.", "AbortError");
161
+ }
162
+ const effectiveModel = rawModel.replace(/^antigravity-/, "");
163
+ const candidateModels = [effectiveModel];
164
+ if (!effectiveModel.endsWith("-tiered") &&
165
+ (effectiveModel.includes("flash") || effectiveModel.includes("pro"))) {
166
+ candidateModels.push(`${effectiveModel}-tiered`);
167
+ }
168
+ else if (effectiveModel.endsWith("-tiered")) {
169
+ candidateModels.push(effectiveModel.replace(/-tiered$/, ""));
170
+ }
171
+ let bodyStr = init?.body;
172
+ let parsedBody = typeof bodyStr === "string" ? JSON.parse(bodyStr) : bodyStr;
173
+ const headers = new Headers(init?.headers ?? {});
174
+ headers.set("Authorization", `Bearer ${authRes.accessToken}`);
175
+ 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`);
176
+ headers.set("X-Goog-Api-Client", "google-cloud-sdk vscode_cloudshelleditor/0.1");
177
+ headers.set("Client-Metadata", `{"ideType":"ANTIGRAVITY","platform":"WINDOWS","pluginType":"GEMINI"}`);
178
+ headers.delete("x-goog-api-key");
179
+ headers.delete("x-api-key");
180
+ headers.delete("x-goog-user-project");
181
+ const endpoints = [
182
+ "https://daily-cloudcode-pa.sandbox.googleapis.com",
183
+ "https://cloudcode-pa.googleapis.com",
184
+ ];
185
+ let gotRes = null;
186
+ endpointLoop: for (const ep of endpoints) {
187
+ if (init?.signal?.aborted) {
188
+ throw new DOMException("The operation was aborted.", "AbortError");
189
+ }
190
+ for (const candidate of candidateModels) {
191
+ if (init?.signal?.aborted) {
192
+ throw new DOMException("The operation was aborted.", "AbortError");
193
+ }
194
+ const transformedUrl = `${ep}/v1internal:${action}${isStreaming ? "?alt=sse" : ""}`;
195
+ const wrappedBody = JSON.stringify({
196
+ project: authRes.projectId || "rising-fact-p41fc",
197
+ model: candidate,
198
+ request: parsedBody,
199
+ requestType: "agent",
200
+ userAgent: "antigravity",
201
+ });
202
+ try {
203
+ const r = await fetch(transformedUrl, {
204
+ ...init,
205
+ headers,
206
+ body: wrappedBody,
207
+ });
208
+ if (r.ok) {
209
+ gotRes = r;
210
+ break endpointLoop;
211
+ }
212
+ if (r.status === 429) {
213
+ gotRes = r;
214
+ }
215
+ }
216
+ catch (netErr) {
217
+ if (netErr?.name === "AbortError" || init?.signal?.aborted) {
218
+ throw netErr;
219
+ }
220
+ if (process.env.SUPEROC_DEBUG === "true") {
221
+ console.warn(`[superoc] Endpoint ${ep} socket/network error:`, netErr);
222
+ }
223
+ }
224
+ }
225
+ }
226
+ if (gotRes) {
227
+ lastResponse = gotRes;
228
+ }
229
+ if (gotRes && gotRes.ok) {
230
+ if (isStreaming && gotRes.body) {
231
+ const transformedStream = gotRes.body.pipeThrough(createSseUnwrapTransform());
232
+ return new Response(transformedStream, {
233
+ status: gotRes.status,
234
+ statusText: gotRes.statusText,
235
+ headers: gotRes.headers,
236
+ });
237
+ }
238
+ return gotRes;
239
+ }
240
+ if (gotRes && gotRes.status === 429) {
241
+ recordRateLimit(store, next.key.id);
242
+ recordModelRateLimit(store, next.key.id, rawModel);
243
+ safeSaveStore();
244
+ continue;
245
+ }
246
+ if (gotRes)
247
+ return gotRes;
248
+ }
249
+ if (isAntigravityModel) {
250
+ if (lastResponse)
251
+ return lastResponse;
252
+ return new Response(JSON.stringify({
253
+ error: {
254
+ code: 429,
255
+ message: "All Antigravity accounts are currently rate limited or exhausted.",
256
+ status: "RESOURCE_EXHAUSTED",
257
+ },
258
+ }), { status: 429, headers: { "Content-Type": "application/json" } });
259
+ }
260
+ }
261
+ }
262
+ return (fallbackFetch || fetch)(input, init);
263
+ };
264
+ }
265
+ function installGlobalFetchInterceptor(fetchHandler) {
266
+ if (!globalThis.__superoc_fetch_installed) {
267
+ globalThis.__superoc_fetch_installed = true;
268
+ const origFetch = globalThis.fetch;
269
+ globalThis.fetch = async function (input, init) {
270
+ return fetchHandler(input, init, origFetch);
271
+ };
272
+ }
273
+ }
77
274
  export const SuperocPlugin = async (input, options) => {
78
275
  const client = input.client;
79
276
  const config = {
@@ -428,52 +625,6 @@ export const SuperocPlugin = async (input, options) => {
428
625
  const reason = `Rate limited (429) — ${state.rateLimitCount}/${store.maxRateLimitFailures} consecutive`;
429
626
  await triggerRetry(sessionID, state, reason);
430
627
  };
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
628
  if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
478
629
  process.env.GOOGLE_GENERATIVE_AI_API_KEY = "antigravity-oauth";
479
630
  }
@@ -481,153 +632,8 @@ export const SuperocPlugin = async (input, options) => {
481
632
  process.env.GEMINI_API_KEY = "antigravity-oauth";
482
633
  }
483
634
  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
- }
635
+ const antigravityFetch = createAntigravityFetch(store, config, reloadFromDisk, safeSaveStore);
636
+ installGlobalFetchInterceptor(antigravityFetch);
631
637
  const hooks = {
632
638
  config: async (cfg) => {
633
639
  if (!process.env.OPENCODE_ENABLE_EXA) {
@@ -911,6 +917,274 @@ export const SuperocPlugin = async (input, options) => {
911
917
  };
912
918
  return hooks;
913
919
  };
920
+ export async function setupV2(context) {
921
+ const options = context.options ?? {};
922
+ const config = {
923
+ storePath: options.storePath,
924
+ rotationStrategy: isValidStrategy(options.rotationStrategy)
925
+ ? options.rotationStrategy
926
+ : "round-robin",
927
+ };
928
+ const store = loadStore(config) ?? getDefaultStore();
929
+ if (!store.fallbackChains)
930
+ store.fallbackChains = { nvidia: [], google: [], antigravity: [] };
931
+ const sessions = new Map();
932
+ const reloadFromDisk = () => {
933
+ let fresh = null;
934
+ try {
935
+ fresh = loadStore(config);
936
+ }
937
+ catch (err) {
938
+ console.debug("[superoc] Failed to reload store from disk:", err);
939
+ return;
940
+ }
941
+ if (fresh === null)
942
+ return;
943
+ try {
944
+ store.keys = fresh.keys;
945
+ store.currentIndex = fresh.currentIndex;
946
+ store.rotationStrategy = fresh.rotationStrategy;
947
+ store.updatedAt = fresh.updatedAt;
948
+ store.lastUsedKeyId = fresh.lastUsedKeyId;
949
+ store.fallbackChains = {
950
+ nvidia: Array.isArray(fresh.fallbackChains?.nvidia) ? fresh.fallbackChains.nvidia : [],
951
+ google: Array.isArray(fresh.fallbackChains?.google) ? fresh.fallbackChains.google : [],
952
+ antigravity: Array.isArray(fresh.fallbackChains?.antigravity) ? fresh.fallbackChains.antigravity : [],
953
+ };
954
+ store.maxRateLimitFailures =
955
+ typeof fresh.maxRateLimitFailures === "number" &&
956
+ Number.isFinite(fresh.maxRateLimitFailures) &&
957
+ fresh.maxRateLimitFailures >= 1
958
+ ? fresh.maxRateLimitFailures
959
+ : getDefaultStore().maxRateLimitFailures;
960
+ }
961
+ catch (err) {
962
+ console.debug("[superoc] Failed to apply reloaded store:", err);
963
+ }
964
+ };
965
+ const safeSaveStore = () => {
966
+ try {
967
+ saveStore(store, config);
968
+ }
969
+ catch (err) {
970
+ console.error("[superoc] Failed to save store:", err);
971
+ }
972
+ };
973
+ for (const provider of PROVIDERS) {
974
+ const activeKeys = getActiveKeys(store, provider);
975
+ if (activeKeys.length === 0) {
976
+ const envKey = process.env[getEnvKeyName(provider)];
977
+ if (envKey) {
978
+ const existing = store.keys.find((k) => k.name === "env-default" && k.provider === provider);
979
+ if (!existing) {
980
+ addKey(store, "env-default", envKey, provider);
981
+ safeSaveStore();
982
+ }
983
+ }
984
+ }
985
+ }
986
+ const getState = (sessionID) => {
987
+ const existing = sessions.get(sessionID);
988
+ if (existing)
989
+ return existing;
990
+ const next = {
991
+ attemptIndex: 0,
992
+ inRetry: false,
993
+ aborting: false,
994
+ pendingRetryIndex: undefined,
995
+ lastUserMessageID: undefined,
996
+ activeChainKey: undefined,
997
+ activeChainModelId: undefined,
998
+ rateLimitCount: 0,
999
+ currentModelId: undefined,
1000
+ lastFailedModelId: undefined,
1001
+ lastErrorHandledAt: 0,
1002
+ createdAt: Date.now(),
1003
+ sessionProviderId: undefined,
1004
+ lastUsedKeyId: undefined,
1005
+ };
1006
+ sessions.set(sessionID, next);
1007
+ return next;
1008
+ };
1009
+ // Seed environment variables
1010
+ if (!process.env.OPENCODE_ENABLE_EXA) {
1011
+ process.env.OPENCODE_ENABLE_EXA = "1";
1012
+ }
1013
+ if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
1014
+ process.env.GOOGLE_GENERATIVE_AI_API_KEY = "antigravity-oauth";
1015
+ }
1016
+ if (!process.env.GEMINI_API_KEY) {
1017
+ process.env.GEMINI_API_KEY = "antigravity-oauth";
1018
+ }
1019
+ syncOpencodeAuth();
1020
+ // Install global fetch interceptor
1021
+ const antigravityFetch = createAntigravityFetch(store, config, reloadFromDisk, safeSaveStore);
1022
+ installGlobalFetchInterceptor(antigravityFetch);
1023
+ // Shell hook in V2
1024
+ if (context.shell?.hook) {
1025
+ await context.shell.hook("create.before", async (input) => {
1026
+ if (input?.env) {
1027
+ input.env["OPENCODE_ENABLE_EXA"] = "1";
1028
+ reloadFromDisk();
1029
+ for (const provider of PROVIDERS) {
1030
+ const envKeyName = getEnvKeyName(provider);
1031
+ if (input.env[envKeyName] !== undefined || getActiveKeys(store, provider).length > 0) {
1032
+ const next = getNextKey(store, config, undefined, provider);
1033
+ if (next) {
1034
+ input.env[envKeyName] = next.key.key;
1035
+ safeSaveStore();
1036
+ }
1037
+ }
1038
+ }
1039
+ }
1040
+ });
1041
+ }
1042
+ // Session model.request hook in V2: inject rotated auth headers
1043
+ if (context.session?.hook) {
1044
+ await context.session.hook("model.request", async (input) => {
1045
+ const provider = detectProviderForRequest({
1046
+ provider: { info: { id: input.model?.providerID } },
1047
+ model: { providerID: input.model?.providerID, api: input.model?.modelID },
1048
+ });
1049
+ if (!provider)
1050
+ return;
1051
+ reloadFromDisk();
1052
+ const prevKeyId = store.lastUsedKeyId;
1053
+ const modelId = input.model?.modelID;
1054
+ const next = getNextKey(store, config, modelId, provider);
1055
+ if (next) {
1056
+ if (provider === "antigravity") {
1057
+ const authRes = await getOrRefreshAntigravityAccessToken(next.key.key);
1058
+ if (authRes) {
1059
+ const headers = getAntigravityHeaders(authRes.accessToken, authRes.projectId);
1060
+ input.headers = Object.assign(input.headers || {}, headers);
1061
+ }
1062
+ }
1063
+ else {
1064
+ const headers = getProviderHeaders(provider, next.key.key);
1065
+ input.headers = Object.assign(input.headers || {}, headers);
1066
+ }
1067
+ if (prevKeyId && prevKeyId !== next.key.id) {
1068
+ resetRateLimit(store, prevKeyId);
1069
+ }
1070
+ safeSaveStore();
1071
+ }
1072
+ if (input.sessionID) {
1073
+ const state = getState(input.sessionID);
1074
+ state.currentModelId = modelId;
1075
+ state.sessionProviderId = provider;
1076
+ if (next)
1077
+ state.lastUsedKeyId = next.key.id;
1078
+ }
1079
+ });
1080
+ // Session http.response hook in V2: monitor 429 rate limits
1081
+ await context.session.hook("http.response", async (input) => {
1082
+ if (input.response?.status === 429) {
1083
+ const state = input.sessionID ? sessions.get(input.sessionID) : undefined;
1084
+ const errorKeyId = state?.lastUsedKeyId ?? store.lastUsedKeyId;
1085
+ reloadFromDisk();
1086
+ if (errorKeyId) {
1087
+ recordRateLimit(store, errorKeyId);
1088
+ const modelForBlacklist = state?.currentModelId;
1089
+ if (modelForBlacklist) {
1090
+ recordModelRateLimit(store, errorKeyId, modelForBlacklist);
1091
+ }
1092
+ if (state)
1093
+ state.lastFailedModelId = modelForBlacklist;
1094
+ }
1095
+ safeSaveStore();
1096
+ }
1097
+ });
1098
+ // Session retry hook in V2: fallback model switching
1099
+ await context.session.hook("retry", async (input) => {
1100
+ const sessionID = input.sessionID;
1101
+ if (!sessionID)
1102
+ return;
1103
+ const state = getState(sessionID);
1104
+ const provider = state.sessionProviderId ?? "nvidia";
1105
+ const chain = store.fallbackChains[provider] || [];
1106
+ if (chain.length < 2)
1107
+ return;
1108
+ let nextIndex = (state.attemptIndex + 1) % chain.length;
1109
+ const target = chain[nextIndex];
1110
+ if (target && context.session?.switchModel) {
1111
+ state.attemptIndex = nextIndex;
1112
+ state.currentModelId = target.id;
1113
+ try {
1114
+ await context.session.switchModel({
1115
+ sessionID,
1116
+ model: { providerID: state.sessionProviderId ?? provider, modelID: target.id },
1117
+ });
1118
+ }
1119
+ catch (err) {
1120
+ console.debug("[superoc] switchModel failed:", err);
1121
+ }
1122
+ }
1123
+ });
1124
+ }
1125
+ // Provider & Model transform in V2
1126
+ if (context.provider?.transform) {
1127
+ await context.provider.transform((editor) => {
1128
+ const existing = editor.get?.("antigravity");
1129
+ if (!existing && editor.add) {
1130
+ editor.add({
1131
+ info: {
1132
+ id: "antigravity",
1133
+ name: "Antigravity",
1134
+ package: "aisdk:@ai-sdk/google",
1135
+ settings: {
1136
+ baseURL: "https://generativelanguage.googleapis.com/v1beta",
1137
+ },
1138
+ },
1139
+ models: [],
1140
+ });
1141
+ }
1142
+ });
1143
+ }
1144
+ if (context.model?.transform) {
1145
+ await context.model.transform((editor) => {
1146
+ for (const [id, def] of Object.entries(BASE_ANTIGRAVITY_MODELS)) {
1147
+ if (!editor.get?.("antigravity", id) && editor.update) {
1148
+ editor.update("antigravity", id, (draft) => {
1149
+ Object.assign(draft, {
1150
+ name: def.name,
1151
+ limit: def.limit,
1152
+ capabilities: {
1153
+ tools: true,
1154
+ input: ["text", "image", "pdf"],
1155
+ output: ["text"],
1156
+ },
1157
+ });
1158
+ });
1159
+ }
1160
+ }
1161
+ });
1162
+ }
1163
+ // Query live Antigravity models in background
1164
+ reloadFromDisk();
1165
+ const activeKeys = getActiveKeys(store, "antigravity");
1166
+ if (activeKeys.length > 0) {
1167
+ getOrRefreshAntigravityAccessToken(activeKeys[0].key)
1168
+ .then(async (auth) => {
1169
+ if (auth) {
1170
+ try {
1171
+ await fetchLiveAntigravityModels(auth.accessToken, auth.projectId);
1172
+ }
1173
+ catch { }
1174
+ }
1175
+ })
1176
+ .catch(() => { });
1177
+ }
1178
+ return () => {
1179
+ sessions.clear();
1180
+ };
1181
+ }
1182
+ export const SuperocPluginV2 = {
1183
+ id: "superoc",
1184
+ setup: setupV2,
1185
+ server: SuperocPlugin,
1186
+ };
914
1187
  export const NimSuperPlugin = SuperocPlugin;
915
- export default SuperocPlugin;
1188
+ export { SuperocPlugin as server };
1189
+ export default SuperocPluginV2;
916
1190
  //# sourceMappingURL=index.js.map