@benjamolina/pi-antigravity-guard 0.4.5 → 0.4.7
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 +3 -3
- package/dist/catalog.d.ts +6 -5
- package/dist/catalog.js +13 -11
- package/dist/context.d.ts +7 -2
- package/dist/context.js +18 -3
- package/dist/tool-context.js +34 -10
- package/dist/tool-schema.d.ts +1 -0
- package/dist/tool-schema.js +31 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,9 +22,9 @@ All seven rows below are registered for text. The exact `antigravity-gemini-3.8-
|
|
|
22
22
|
| `antigravity-gemini-3.7-flash` | off, low, medium, high | Enabled (off, low, medium, high) | pi-json-tool-loop/gemini-3.7-flash-off-v1 |
|
|
23
23
|
| `antigravity-gemini-3.6-flash` | off, low, medium, high | Enabled (off, low, medium, high) | pi-json-tool-loop/gemini-3.6-flash-off-v1 |
|
|
24
24
|
| `antigravity-gemini-3.1-pro` | off, low, high | Enabled (off, low, high) | pi-json-tool-loop/gemini-3.1-pro-off-v1 |
|
|
25
|
-
| `antigravity-claude-sonnet-4.6` | off, high |
|
|
26
|
-
| `antigravity-claude-opus-4.6-thinking` | off, high |
|
|
27
|
-
| `antigravity-gpt-oss-120b` | off, medium |
|
|
25
|
+
| `antigravity-claude-sonnet-4.6` | off, high | Enabled (off, high) | pi-json-tool-loop/claude-sonnet-4.6-off-v1 |
|
|
26
|
+
| `antigravity-claude-opus-4.6-thinking` | off, high | Enabled (off, high) | pi-json-tool-loop/claude-opus-4.6-thinking-off-v1 |
|
|
27
|
+
| `antigravity-gpt-oss-120b` | off, medium | Enabled (off, medium) | pi-json-tool-loop/gpt-oss-120b-off-v1 |
|
|
28
28
|
|
|
29
29
|
`off` is available for every row even though it is omitted from Pi's level map; omitted reasoning also selects that row's `off` route. Unsupported levels are not advertised and are rejected before transport. `antigravity-gemini-3.5-flash` is not registered or advertised as supported because its recorded HTTP-200 response lacks the strict terminal metadata required for admission. A future `fixture-qualified` route remains disabled for ordinary tool use; only separately authorized direct validation for the exact route may make it enabled.
|
|
30
30
|
|
package/dist/catalog.d.ts
CHANGED
|
@@ -8,7 +8,8 @@ export interface ToolEvidenceRef {
|
|
|
8
8
|
readonly wireModel: string;
|
|
9
9
|
}
|
|
10
10
|
export declare const GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE: "gemini-parameters-json-schema";
|
|
11
|
-
export
|
|
11
|
+
export declare const CLAUDE_CUSTOM_PARAMETERS_PROFILE: "claude-custom-parameters";
|
|
12
|
+
export type ToolSchemaProfile = typeof GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE | typeof CLAUDE_CUSTOM_PARAMETERS_PROFILE;
|
|
12
13
|
export type ToolCapability = {
|
|
13
14
|
readonly state: "disabled";
|
|
14
15
|
readonly contractRevision: 1;
|
|
@@ -316,7 +317,7 @@ declare const CATALOG: readonly [{
|
|
|
316
317
|
};
|
|
317
318
|
};
|
|
318
319
|
readonly replay: {
|
|
319
|
-
readonly kind: "
|
|
320
|
+
readonly kind: "same-public-model";
|
|
320
321
|
};
|
|
321
322
|
readonly response: {
|
|
322
323
|
readonly kind: "gemini-envelope";
|
|
@@ -356,7 +357,7 @@ declare const CATALOG: readonly [{
|
|
|
356
357
|
};
|
|
357
358
|
};
|
|
358
359
|
readonly replay: {
|
|
359
|
-
readonly kind: "
|
|
360
|
+
readonly kind: "same-public-model";
|
|
360
361
|
};
|
|
361
362
|
readonly response: {
|
|
362
363
|
readonly kind: "gemini-envelope";
|
|
@@ -394,7 +395,7 @@ declare const CATALOG: readonly [{
|
|
|
394
395
|
};
|
|
395
396
|
};
|
|
396
397
|
readonly replay: {
|
|
397
|
-
readonly kind: "
|
|
398
|
+
readonly kind: "same-public-model";
|
|
398
399
|
};
|
|
399
400
|
readonly response: {
|
|
400
401
|
readonly kind: "gemini-envelope";
|
|
@@ -436,7 +437,7 @@ export declare function toPiModelDescriptor(entry: CatalogEntry): {
|
|
|
436
437
|
medium: string | null;
|
|
437
438
|
minimal: string | null;
|
|
438
439
|
};
|
|
439
|
-
input: "text"[];
|
|
440
|
+
input: ("text" | "image")[];
|
|
440
441
|
cost: {
|
|
441
442
|
input: number;
|
|
442
443
|
output: number;
|
package/dist/catalog.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const ANSWER_RESERVE = 1024;
|
|
2
2
|
export const GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE = "gemini-parameters-json-schema";
|
|
3
|
+
export const CLAUDE_CUSTOM_PARAMETERS_PROFILE = "claude-custom-parameters";
|
|
3
4
|
const CATALOG = freeze(defineCatalog([{
|
|
4
5
|
publicId: "antigravity-gemini-3.8-flash",
|
|
5
6
|
descriptor: {
|
|
@@ -72,10 +73,10 @@ const CATALOG = freeze(defineCatalog([{
|
|
|
72
73
|
maxTokens: 64_000,
|
|
73
74
|
},
|
|
74
75
|
routes: {
|
|
75
|
-
off: { wireModel: "claude-sonnet-4-6", thinking: { kind: "budget", budget: 0, includeThoughts: false }, tools:
|
|
76
|
-
high: { wireModel: "claude-sonnet-4-6", thinking: { kind: "budget", budget: 1024, includeThoughts: true }, tools:
|
|
76
|
+
off: { wireModel: "claude-sonnet-4-6", thinking: { kind: "budget", budget: 0, includeThoughts: false }, tools: enabled({ record: "pi-json-tool-loop", revision: "claude-sonnet-4.6-off-v1", publicModelId: "antigravity-claude-sonnet-4.6", reasoning: "off", wireModel: "claude-sonnet-4-6" }, CLAUDE_CUSTOM_PARAMETERS_PROFILE) },
|
|
77
|
+
high: { wireModel: "claude-sonnet-4-6", thinking: { kind: "budget", budget: 1024, includeThoughts: true }, tools: enabled({ record: "pi-json-tool-loop", revision: "claude-sonnet-4.6-high-v1", publicModelId: "antigravity-claude-sonnet-4.6", reasoning: "high", wireModel: "claude-sonnet-4-6" }, CLAUDE_CUSTOM_PARAMETERS_PROFILE) },
|
|
77
78
|
},
|
|
78
|
-
replay: { kind: "
|
|
79
|
+
replay: { kind: "same-public-model" },
|
|
79
80
|
response: { kind: "gemini-envelope", family: "claude" },
|
|
80
81
|
}, {
|
|
81
82
|
publicId: "antigravity-claude-opus-4.6-thinking",
|
|
@@ -86,10 +87,10 @@ const CATALOG = freeze(defineCatalog([{
|
|
|
86
87
|
maxTokens: 64_000,
|
|
87
88
|
},
|
|
88
89
|
routes: {
|
|
89
|
-
off: { wireModel: "claude-opus-4-6-thinking", thinking: { kind: "budget", budget: 0, includeThoughts: false }, tools:
|
|
90
|
-
high: { wireModel: "claude-opus-4-6-thinking", thinking: { kind: "budget", budget: 1024, includeThoughts: true }, tools:
|
|
90
|
+
off: { wireModel: "claude-opus-4-6-thinking", thinking: { kind: "budget", budget: 0, includeThoughts: false }, tools: enabled({ record: "pi-json-tool-loop", revision: "claude-opus-4.6-thinking-off-v1", publicModelId: "antigravity-claude-opus-4.6-thinking", reasoning: "off", wireModel: "claude-opus-4-6-thinking" }, CLAUDE_CUSTOM_PARAMETERS_PROFILE) },
|
|
91
|
+
high: { wireModel: "claude-opus-4-6-thinking", thinking: { kind: "budget", budget: 1024, includeThoughts: true }, tools: enabled({ record: "pi-json-tool-loop", revision: "claude-opus-4.6-thinking-high-v1", publicModelId: "antigravity-claude-opus-4.6-thinking", reasoning: "high", wireModel: "claude-opus-4-6-thinking" }, CLAUDE_CUSTOM_PARAMETERS_PROFILE) },
|
|
91
92
|
},
|
|
92
|
-
replay: { kind: "
|
|
93
|
+
replay: { kind: "same-public-model" },
|
|
93
94
|
response: { kind: "gemini-envelope", family: "claude" },
|
|
94
95
|
}, {
|
|
95
96
|
publicId: "antigravity-gpt-oss-120b",
|
|
@@ -100,10 +101,10 @@ const CATALOG = freeze(defineCatalog([{
|
|
|
100
101
|
maxTokens: 32_768,
|
|
101
102
|
},
|
|
102
103
|
routes: {
|
|
103
|
-
off: { wireModel: "gpt-oss-120b-medium", thinking: { kind: "omit" }, tools:
|
|
104
|
-
medium: { wireModel: "gpt-oss-120b-medium", thinking: { kind: "budget", budget: 8192, includeThoughts: true }, tools:
|
|
104
|
+
off: { wireModel: "gpt-oss-120b-medium", thinking: { kind: "omit" }, tools: enabled({ record: "pi-json-tool-loop", revision: "gpt-oss-120b-off-v1", publicModelId: "antigravity-gpt-oss-120b", reasoning: "off", wireModel: "gpt-oss-120b-medium" }, CLAUDE_CUSTOM_PARAMETERS_PROFILE) },
|
|
105
|
+
medium: { wireModel: "gpt-oss-120b-medium", thinking: { kind: "budget", budget: 8192, includeThoughts: true }, tools: enabled({ record: "pi-json-tool-loop", revision: "gpt-oss-120b-medium-v1", publicModelId: "antigravity-gpt-oss-120b", reasoning: "medium", wireModel: "gpt-oss-120b-medium" }, CLAUDE_CUSTOM_PARAMETERS_PROFILE) },
|
|
105
106
|
},
|
|
106
|
-
replay: { kind: "
|
|
107
|
+
replay: { kind: "same-public-model" },
|
|
107
108
|
response: { kind: "gemini-envelope", family: "gpt-oss" },
|
|
108
109
|
}]));
|
|
109
110
|
const lookup = new Map(CATALOG.map((entry) => [entry.publicId, entry]));
|
|
@@ -179,12 +180,13 @@ export function resolveToolCapability(capability, publicModelId, reasoning, wire
|
|
|
179
180
|
return capability;
|
|
180
181
|
}
|
|
181
182
|
export function toPiModelDescriptor(entry) {
|
|
183
|
+
const isMultimodal = entry.response.family === "gemini" || entry.response.family === "claude";
|
|
182
184
|
return {
|
|
183
185
|
id: entry.publicId,
|
|
184
|
-
name: entry.descriptor.name,
|
|
186
|
+
name: entry.descriptor.name.replace(", text only", ""),
|
|
185
187
|
reasoning: true,
|
|
186
188
|
thinkingLevelMap: { ...entry.descriptor.thinkingLevelMap },
|
|
187
|
-
input: ["text"],
|
|
189
|
+
input: (isMultimodal ? ["text", "image"] : ["text"]),
|
|
188
190
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
189
191
|
contextWindow: entry.descriptor.contextWindow,
|
|
190
192
|
maxTokens: entry.descriptor.maxTokens,
|
package/dist/context.d.ts
CHANGED
|
@@ -2,9 +2,13 @@ import type { Context, Model, SimpleStreamOptions } from "@earendil-works/pi-ai"
|
|
|
2
2
|
import { type GenerationSelection } from "./catalog.ts";
|
|
3
3
|
import { type ToolReplayDiagnostics } from "./tool-context.ts";
|
|
4
4
|
interface Part {
|
|
5
|
-
text
|
|
5
|
+
text?: string;
|
|
6
6
|
thought?: true;
|
|
7
7
|
thoughtSignature?: string;
|
|
8
|
+
inlineData?: {
|
|
9
|
+
mimeType: string;
|
|
10
|
+
data: string;
|
|
11
|
+
};
|
|
8
12
|
}
|
|
9
13
|
interface Content {
|
|
10
14
|
role: "user" | "model";
|
|
@@ -13,7 +17,8 @@ interface Content {
|
|
|
13
17
|
interface GeminiFunctionDeclaration {
|
|
14
18
|
readonly name: string;
|
|
15
19
|
readonly description: string;
|
|
16
|
-
readonly parametersJsonSchema
|
|
20
|
+
readonly parametersJsonSchema?: object;
|
|
21
|
+
readonly parameters?: object;
|
|
17
22
|
}
|
|
18
23
|
export interface GenerationRequest {
|
|
19
24
|
project: string;
|
package/dist/context.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getCatalogEntry, resolveGenerationSelection } from "./catalog.js";
|
|
1
|
+
import { CLAUDE_CUSTOM_PARAMETERS_PROFILE, getCatalogEntry, resolveGenerationSelection } from "./catalog.js";
|
|
2
|
+
import { normalizeCustomToolSchema } from "./tool-schema.js";
|
|
2
3
|
import { hasToolContext, prepareToolContext, replayToolHistory } from "./tool-context.js";
|
|
3
4
|
const MAX_TEXT_BYTES = 8 * 1024 * 1024;
|
|
4
5
|
const PROVIDER = "antigravity-guard";
|
|
@@ -36,7 +37,13 @@ export function serializeContext(input, injectedSelection, onDiagnostics) {
|
|
|
36
37
|
contents,
|
|
37
38
|
...(systemInstruction ? { systemInstruction } : {}),
|
|
38
39
|
...(prepared ? {
|
|
39
|
-
tools: [{ functionDeclarations: prepared.declarations.map(({ name, description, parameters }) => ({
|
|
40
|
+
tools: [{ functionDeclarations: prepared.declarations.map(({ name, description, parameters }) => ({
|
|
41
|
+
name,
|
|
42
|
+
description,
|
|
43
|
+
...(selection.tools.state === "enabled" && selection.tools.schemaProfile === CLAUDE_CUSTOM_PARAMETERS_PROFILE
|
|
44
|
+
? { parameters: normalizeCustomToolSchema(parameters) }
|
|
45
|
+
: { parametersJsonSchema: parameters }),
|
|
46
|
+
})) }],
|
|
40
47
|
...(prepared.mode === "NONE" ? { toolConfig: { functionCallingConfig: { mode: "NONE" } } } : {}),
|
|
41
48
|
} : {}),
|
|
42
49
|
generationConfig,
|
|
@@ -77,7 +84,7 @@ export function serializeTextContext(input) {
|
|
|
77
84
|
fail("Unsupported context role for this text-only provider.");
|
|
78
85
|
const assistant = role === "assistant";
|
|
79
86
|
const parts = messageParts(field(message, "content", true), assistant, assistant && entry.replay.kind === "same-public-model" && isSameProviderAndModel(message, entry.publicId));
|
|
80
|
-
textBytes += parts.reduce((total, part) => total + byteLength(part.text), 0);
|
|
87
|
+
textBytes += parts.reduce((total, part) => total + (part.text ? byteLength(part.text) : (part.inlineData ? byteLength(part.inlineData.data) : 0)), 0);
|
|
81
88
|
if (textBytes > MAX_TEXT_BYTES)
|
|
82
89
|
fail("Text context is too large.");
|
|
83
90
|
contents.push({ role: role === "assistant" ? "model" : "user", parts });
|
|
@@ -159,6 +166,14 @@ function messagePart(part, assistant, sameProviderAndModel) {
|
|
|
159
166
|
fail("Only text context is supported by this provider.");
|
|
160
167
|
return { text };
|
|
161
168
|
}
|
|
169
|
+
if (type === "image") {
|
|
170
|
+
const rawData = field(part, "data") ?? (isRecord(field(part, "source")) ? field(field(part, "source"), "data") : undefined);
|
|
171
|
+
if (typeof rawData !== "string" || !rawData)
|
|
172
|
+
fail("Invalid image data.");
|
|
173
|
+
const rawMime = field(part, "mimeType") ?? (isRecord(field(part, "source")) ? field(field(part, "source"), "media_type") : undefined);
|
|
174
|
+
const mimeType = typeof rawMime === "string" && rawMime ? rawMime : "image/jpeg";
|
|
175
|
+
return { inlineData: { mimeType, data: rawData } };
|
|
176
|
+
}
|
|
162
177
|
fail("Only text context is supported by this provider.");
|
|
163
178
|
}
|
|
164
179
|
function isSameProviderAndModel(message, publicId) {
|
package/dist/tool-context.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { canonicalJson, ToolPreflightError } from "./tool-contract.js";
|
|
2
|
-
import { GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE } from "./catalog.js";
|
|
2
|
+
import { CLAUDE_CUSTOM_PARAMETERS_PROFILE, GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE } from "./catalog.js";
|
|
3
3
|
import { normalizeToolDeclarations } from "./tool-schema.js";
|
|
4
4
|
export function hasToolContext(context) {
|
|
5
5
|
if (!isRecord(context))
|
|
@@ -18,7 +18,7 @@ export function hasToolContext(context) {
|
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
20
|
export function prepareToolContext(tools, choice, schemaProfile) {
|
|
21
|
-
if (schemaProfile !== GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE)
|
|
21
|
+
if (schemaProfile !== GEMINI_PARAMETERS_JSON_SCHEMA_PROFILE && schemaProfile !== CLAUDE_CUSTOM_PARAMETERS_PROFILE)
|
|
22
22
|
throw new ToolPreflightError("PI_TOOL_SCHEMA_PROFILE_UNSUPPORTED", "tools", "$");
|
|
23
23
|
const declarations = normalizeToolDeclarations(tools ?? []);
|
|
24
24
|
if (!declarations.length) {
|
|
@@ -58,13 +58,17 @@ export function replayToolHistory(messages, serializePart, onDiagnostics, policy
|
|
|
58
58
|
const finalize = () => {
|
|
59
59
|
if (!pending)
|
|
60
60
|
return;
|
|
61
|
-
|
|
61
|
+
const turnParts = pending.calls.map((call) => {
|
|
62
62
|
const actual = pending.results.get(call.id);
|
|
63
63
|
if (actual)
|
|
64
64
|
return actual;
|
|
65
65
|
recoveryCount.value += 1;
|
|
66
66
|
return pending.observations ? observation(call, missingResultText()) : missingResult(call);
|
|
67
|
-
})
|
|
67
|
+
});
|
|
68
|
+
if (pending.extraParts?.length) {
|
|
69
|
+
turnParts.push(...pending.extraParts);
|
|
70
|
+
}
|
|
71
|
+
appendTurn("user", turnParts);
|
|
68
72
|
pending = undefined;
|
|
69
73
|
};
|
|
70
74
|
for (const message of messages) {
|
|
@@ -83,14 +87,34 @@ export function replayToolHistory(messages, serializePart, onDiagnostics, policy
|
|
|
83
87
|
history("PI_TOOL_RESULT_NAME_MISMATCH");
|
|
84
88
|
if (value(current, "addedToolNames") !== undefined && dense(value(current, "addedToolNames")).length)
|
|
85
89
|
history("PI_TOOL_CALL_INVALID");
|
|
86
|
-
const
|
|
90
|
+
const textParts = [];
|
|
91
|
+
const imageParts = [];
|
|
92
|
+
for (const item of dense(value(current, "content"))) {
|
|
87
93
|
const part = record(item);
|
|
88
|
-
if (value(part, "type")
|
|
94
|
+
if (value(part, "type") === "text" && typeof value(part, "text") === "string") {
|
|
95
|
+
textParts.push(value(part, "text"));
|
|
96
|
+
}
|
|
97
|
+
else if (value(part, "type") === "image") {
|
|
98
|
+
const rawData = value(part, "data") ?? (isRecord(value(part, "source")) ? value(record(value(part, "source")), "data") : undefined);
|
|
99
|
+
if (typeof rawData === "string" && rawData) {
|
|
100
|
+
const rawMime = value(part, "mimeType") ?? (isRecord(value(part, "source")) ? value(record(value(part, "source")), "media_type") : undefined);
|
|
101
|
+
const mimeType = typeof rawMime === "string" && rawMime ? rawMime : "image/jpeg";
|
|
102
|
+
imageParts.push({ inlineData: { mimeType, data: rawData } });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
89
106
|
history("PI_TOOL_RESULT_MEDIA_UNSUPPORTED");
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
const
|
|
93
|
-
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const text = textParts.join("\n\n");
|
|
110
|
+
const outputText = text || (imageParts.length > 0 ? "[Image content]" : "");
|
|
111
|
+
const response = value(current, "isError") === true ? { error: outputText } : { output: outputText };
|
|
112
|
+
pending.results.set(id, pending.observations ? observation(call, outputText) : { functionResponse: { name: call.name, response } });
|
|
113
|
+
if (imageParts.length > 0) {
|
|
114
|
+
if (!pending.extraParts)
|
|
115
|
+
pending.extraParts = [];
|
|
116
|
+
pending.extraParts.push(...imageParts);
|
|
117
|
+
}
|
|
94
118
|
results.add(id);
|
|
95
119
|
continue;
|
|
96
120
|
}
|
package/dist/tool-schema.d.ts
CHANGED
package/dist/tool-schema.js
CHANGED
|
@@ -210,3 +210,34 @@ function isJsonObject(value) {
|
|
|
210
210
|
function define(target, key, value) {
|
|
211
211
|
Object.defineProperty(target, key, { value, enumerable: true, configurable: false, writable: false });
|
|
212
212
|
}
|
|
213
|
+
const CUSTOM_TOOL_SCHEMA_ALLOW = new Set([
|
|
214
|
+
"type",
|
|
215
|
+
"description",
|
|
216
|
+
"properties",
|
|
217
|
+
"required",
|
|
218
|
+
"items",
|
|
219
|
+
"enum",
|
|
220
|
+
]);
|
|
221
|
+
export function normalizeCustomToolSchema(schema) {
|
|
222
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema))
|
|
223
|
+
return {};
|
|
224
|
+
const out = {};
|
|
225
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
226
|
+
if (!CUSTOM_TOOL_SCHEMA_ALLOW.has(key))
|
|
227
|
+
continue;
|
|
228
|
+
if (key === "properties" && value && typeof value === "object" && !Array.isArray(value)) {
|
|
229
|
+
const props = {};
|
|
230
|
+
for (const [propName, propSchema] of Object.entries(value)) {
|
|
231
|
+
props[propName] = normalizeCustomToolSchema(propSchema);
|
|
232
|
+
}
|
|
233
|
+
out.properties = props;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (key === "items") {
|
|
237
|
+
out.items = normalizeCustomToolSchema(value);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
out[key] = value;
|
|
241
|
+
}
|
|
242
|
+
return out;
|
|
243
|
+
}
|