pi-antigravity-rotator 2.1.3 → 2.1.4
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 +15 -0
- package/README.md +4 -3
- package/package.json +1 -1
- package/src/compat.ts +88 -7
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [2.1.4] - 2026-05-27
|
|
6
|
+
|
|
7
|
+
### Improved
|
|
8
|
+
- **Less Lossy Schema Collapsing for Claude**: The `sanitizeClaudeViaGeminiSchema` function now handles complex `anyOf`/`oneOf`/`allOf` schemas with significantly less information loss:
|
|
9
|
+
- **Nullable detection (lossless)**: `anyOf: [{type: X}, {type: "null"}]` patterns are now converted to `{type: X, nullable: true}` instead of losing the null variant.
|
|
10
|
+
- **`allOf` deep merge (lossless)**: `allOf` variants are now deep-merged (properties union + required union) instead of picking only the first variant.
|
|
11
|
+
- **`anyOf`/`oneOf` object merge**: When all variants are objects, properties are merged into a union and only fields required in ALL variants remain required, preserving wider input acceptance.
|
|
12
|
+
- The first-variant fallback is still used for truly incompatible mixed-type unions.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- **README: Incorrect model names in Codex section**: Removed references to nonexistent `claude-3-5-sonnet` and `gemini-3-pro` models, replaced with actual supported models (`claude-opus-4-6-thinking`, `gemini-3.1-pro`, `gpt-oss-120b`, etc.).
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **Schema sanitizer tests**: Added test cases for nullable detection, `allOf` deep merge, and `anyOf` object variant merging.
|
|
19
|
+
|
|
5
20
|
## [2.1.3] - 2026-05-27
|
|
6
21
|
|
|
7
22
|
### Fixed
|
package/README.md
CHANGED
|
@@ -500,9 +500,10 @@ To connect Codex to your local rotator:
|
|
|
500
500
|
|
|
501
501
|
3. **Select a Supported Model**:
|
|
502
502
|
Configure Codex to target one of the following models supported by the rotator (which will be mapped to the best available Google Antigravity account/model under the hood):
|
|
503
|
-
- `gemini-3.5-flash` or `gemini-3.5-flash-high` / `gemini-3.5-flash-low` (Recommended for fast general reasoning)
|
|
504
|
-
- `gemini-3-pro` or `gemini-pro-agent` (For deep reasoning)
|
|
505
|
-
- `claude-sonnet-4-6` or `claude-
|
|
503
|
+
- `gemini-3.5-flash` or `gemini-3.5-flash-high` / `gemini-3.5-flash-low` / `gemini-3.5-flash-medium` (Recommended for fast general reasoning)
|
|
504
|
+
- `gemini-3.1-pro` or `gemini-pro-agent` / `gemini-3.1-pro-high` / `gemini-3.1-pro-low` (For deep reasoning)
|
|
505
|
+
- `claude-sonnet-4-6` or `claude-opus-4-6-thinking` (Claude models via Vertex AI)
|
|
506
|
+
- `gpt-oss-120b` or `gpt-oss-120b-medium` (Open-source GPT model)
|
|
506
507
|
|
|
507
508
|
Example Codex configuration entry:
|
|
508
509
|
```json
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-antigravity-rotator",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.4",
|
|
4
4
|
"description": "Multi-account rotation proxy for Google Antigravity with per-model routing, real-time quota tracking, and infringement detection",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/compat.ts
CHANGED
|
@@ -470,17 +470,98 @@ function sanitizeClaudeViaGeminiSchema(schema: unknown): unknown {
|
|
|
470
470
|
}
|
|
471
471
|
}
|
|
472
472
|
|
|
473
|
-
//
|
|
474
|
-
// Gemini's Schema proto serialization corrupts complex anyOf/oneOf
|
|
475
|
-
// during the round-trip to Claude, causing JSON Schema draft 2020-12
|
|
476
|
-
// validation failures. Collapsing is lossy but functional — the tool
|
|
477
|
-
// still works, just with a narrower accepted input type.
|
|
473
|
+
// Sanitize all variants first.
|
|
478
474
|
const cleaned = value.map(sanitizeClaudeViaGeminiSchema).filter(
|
|
479
475
|
(v) => isRecord(v) && Object.keys(v).length > 0,
|
|
476
|
+
) as Record<string, unknown>[];
|
|
477
|
+
|
|
478
|
+
if (cleaned.length === 0) {
|
|
479
|
+
// All variants collapsed to nothing — skip entirely.
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Case 3: nullable pattern — anyOf/oneOf with exactly one {type:"null"}
|
|
484
|
+
// variant and one or more real variants. Convert to the real variant
|
|
485
|
+
// with nullable:true. This is lossless — Gemini's proto supports nullable.
|
|
486
|
+
// e.g. anyOf:[{type:"string"},{type:"null"}] → {type:"string",nullable:true}
|
|
487
|
+
if (key !== "allOf") {
|
|
488
|
+
const nullIdx = cleaned.findIndex((v) => v.type === "null" && Object.keys(v).length === 1);
|
|
489
|
+
if (nullIdx !== -1) {
|
|
490
|
+
const nonNull = cleaned.filter((_, i) => i !== nullIdx);
|
|
491
|
+
if (nonNull.length === 1) {
|
|
492
|
+
Object.assign(out, nonNull[0], { nullable: true });
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
if (nonNull.length > 1) {
|
|
496
|
+
// Multiple non-null variants + null → collapse non-null variants,
|
|
497
|
+
// then mark nullable. Still lossy but preserves nullability.
|
|
498
|
+
Object.assign(out, nonNull[0], { nullable: true });
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Case 4: allOf — deep merge all variants (allOf = intersection).
|
|
505
|
+
// Merging properties from all variants is semantically correct.
|
|
506
|
+
if (key === "allOf") {
|
|
507
|
+
const merged: Record<string, unknown> = {};
|
|
508
|
+
let mergedProperties: Record<string, unknown> = {};
|
|
509
|
+
let mergedRequired: string[] = [];
|
|
510
|
+
for (const variant of cleaned) {
|
|
511
|
+
for (const [vk, vv] of Object.entries(variant)) {
|
|
512
|
+
if (vk === "properties" && isRecord(vv)) {
|
|
513
|
+
mergedProperties = { ...mergedProperties, ...vv };
|
|
514
|
+
} else if (vk === "required" && Array.isArray(vv)) {
|
|
515
|
+
mergedRequired = [...new Set([...mergedRequired, ...vv])];
|
|
516
|
+
} else {
|
|
517
|
+
merged[vk] = vv;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (Object.keys(mergedProperties).length > 0) merged["properties"] = mergedProperties;
|
|
522
|
+
if (mergedRequired.length > 0) merged["required"] = mergedRequired;
|
|
523
|
+
Object.assign(out, merged);
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Case 5: anyOf/oneOf where all variants are objects with properties —
|
|
528
|
+
// merge all properties together, making all optional (union of shapes).
|
|
529
|
+
// This is mildly lossy (accepts wider input) but doesn't reject valid inputs.
|
|
530
|
+
const allObjects = cleaned.every(
|
|
531
|
+
(v) => v.type === "object" && isRecord(v.properties),
|
|
480
532
|
);
|
|
481
|
-
if (cleaned.length
|
|
482
|
-
|
|
533
|
+
if (allObjects && cleaned.length > 1) {
|
|
534
|
+
const unionProperties: Record<string, unknown> = {};
|
|
535
|
+
for (const variant of cleaned) {
|
|
536
|
+
const props = variant.properties as Record<string, unknown>;
|
|
537
|
+
for (const [pk, pv] of Object.entries(props)) {
|
|
538
|
+
if (!(pk in unionProperties)) unionProperties[pk] = pv;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
// Only keep required fields that exist in ALL variants
|
|
542
|
+
const allRequired = cleaned.map((v) =>
|
|
543
|
+
Array.isArray(v.required) ? new Set(v.required as string[]) : new Set<string>(),
|
|
544
|
+
);
|
|
545
|
+
const commonRequired = [...allRequired[0]].filter((r) =>
|
|
546
|
+
allRequired.every((s) => s.has(r)),
|
|
547
|
+
);
|
|
548
|
+
const base = { ...cleaned[0] };
|
|
549
|
+
base["properties"] = unionProperties;
|
|
550
|
+
if (commonRequired.length > 0) {
|
|
551
|
+
base["required"] = commonRequired;
|
|
552
|
+
} else {
|
|
553
|
+
delete base["required"];
|
|
554
|
+
}
|
|
555
|
+
Object.assign(out, base);
|
|
556
|
+
continue;
|
|
483
557
|
}
|
|
558
|
+
|
|
559
|
+
// Fallback: collapse to the first valid variant.
|
|
560
|
+
// Gemini's Schema proto serialization corrupts complex anyOf/oneOf
|
|
561
|
+
// during the round-trip to Claude, causing JSON Schema draft 2020-12
|
|
562
|
+
// validation failures. Collapsing is lossy but functional — the tool
|
|
563
|
+
// still works, just with a narrower accepted input type.
|
|
564
|
+
Object.assign(out, cleaned[0]);
|
|
484
565
|
}
|
|
485
566
|
continue;
|
|
486
567
|
}
|