@benjamolina/pi-antigravity-guard 0.4.7 → 0.4.9
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/context.d.ts +3 -0
- package/dist/context.js +26 -6
- package/dist/envelope.d.ts +20 -0
- package/dist/envelope.js +112 -0
- package/dist/tool-context.d.ts +2 -0
- package/dist/tool-context.js +11 -4
- package/package.json +4 -2
package/dist/context.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export interface GenerationRequest {
|
|
|
26
26
|
request: {
|
|
27
27
|
contents: Content[];
|
|
28
28
|
systemInstruction?: {
|
|
29
|
+
role?: "user";
|
|
29
30
|
parts: Part[];
|
|
30
31
|
};
|
|
31
32
|
tools?: {
|
|
@@ -47,6 +48,8 @@ export interface GenerationRequest {
|
|
|
47
48
|
includeThoughts: boolean;
|
|
48
49
|
};
|
|
49
50
|
};
|
|
51
|
+
sessionId?: string;
|
|
52
|
+
labels?: Record<string, string>;
|
|
50
53
|
};
|
|
51
54
|
requestType: "agent";
|
|
52
55
|
userAgent: "antigravity";
|
package/dist/context.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CLAUDE_CUSTOM_PARAMETERS_PROFILE, getCatalogEntry, resolveGenerationSelection } from "./catalog.js";
|
|
2
2
|
import { normalizeCustomToolSchema } from "./tool-schema.js";
|
|
3
|
+
import { buildAntigravityEnvelope } from "./envelope.js";
|
|
3
4
|
import { hasToolContext, prepareToolContext, replayToolHistory } from "./tool-context.js";
|
|
4
5
|
const MAX_TEXT_BYTES = 8 * 1024 * 1024;
|
|
5
6
|
const PROVIDER = "antigravity-guard";
|
|
@@ -26,13 +27,23 @@ export function serializeContext(input, injectedSelection, onDiagnostics) {
|
|
|
26
27
|
const { toolChoice: _choice, ...textOptions } = isRecord(options) ? options : {};
|
|
27
28
|
const text = serializeTextContext({ ...input, context: { ...textContext, messages: [{ role: "user", content: "placeholder", timestamp: 0 }] }, options: textOptions });
|
|
28
29
|
const sameModel = (message) => field(message, "role") === "assistant" && entry.replay.kind === "same-public-model" && isSameProviderAndModel(message, entry.publicId);
|
|
29
|
-
const
|
|
30
|
-
|
|
30
|
+
const requireSigned = geminiRequiresSignedToolReplay(selection.route.wireModel);
|
|
31
|
+
const includeToolCallId = entry.response.family === "claude" || entry.response.family === "gpt-oss";
|
|
32
|
+
const toolReplayPolicy = (requireSigned || includeToolCallId) ? {
|
|
33
|
+
requireSignedToolCalls: requireSigned,
|
|
31
34
|
isSameModel: sameModel,
|
|
32
35
|
toolCallSignature: (part, message) => sameModel(message) ? validThoughtSignature(field(part, "thoughtSignature")) : undefined,
|
|
36
|
+
includeToolCallId,
|
|
33
37
|
} : undefined;
|
|
34
|
-
const contents = replayToolHistory(isDenseArray(messages), (part, message) => messagePart(part, field(message, "role") === "assistant", sameModel(message)), onDiagnostics,
|
|
38
|
+
const contents = replayToolHistory(isDenseArray(messages), (part, message) => messagePart(part, field(message, "role") === "assistant", sameModel(message)), onDiagnostics, toolReplayPolicy, prepared?.declarations.length ?? 0);
|
|
35
39
|
const { systemInstruction, generationConfig } = text.request;
|
|
40
|
+
const envelope = buildAntigravityEnvelope({
|
|
41
|
+
wireModelId: selection.route.wireModel,
|
|
42
|
+
family: entry.response.family,
|
|
43
|
+
contentsCount: contents.length,
|
|
44
|
+
messages: isDenseArray(messages),
|
|
45
|
+
injectedRequestId: input.requestId,
|
|
46
|
+
});
|
|
36
47
|
return { ...text, request: {
|
|
37
48
|
contents,
|
|
38
49
|
...(systemInstruction ? { systemInstruction } : {}),
|
|
@@ -47,7 +58,9 @@ export function serializeContext(input, injectedSelection, onDiagnostics) {
|
|
|
47
58
|
...(prepared.mode === "NONE" ? { toolConfig: { functionCallingConfig: { mode: "NONE" } } } : {}),
|
|
48
59
|
} : {}),
|
|
49
60
|
generationConfig,
|
|
50
|
-
|
|
61
|
+
sessionId: envelope.sessionId,
|
|
62
|
+
labels: envelope.labels,
|
|
63
|
+
}, requestId: envelope.requestId };
|
|
51
64
|
}
|
|
52
65
|
export function serializeTextContext(input) {
|
|
53
66
|
try {
|
|
@@ -91,9 +104,16 @@ export function serializeTextContext(input) {
|
|
|
91
104
|
}
|
|
92
105
|
if (!contents.length)
|
|
93
106
|
fail("A text conversation is required.");
|
|
94
|
-
const systemInstruction = systemPrompt === undefined ? undefined : { parts: [{ text: systemPrompt }] };
|
|
107
|
+
const systemInstruction = systemPrompt === undefined ? undefined : { role: "user", parts: [{ text: systemPrompt }] };
|
|
95
108
|
const temperature = option(options, "temperature");
|
|
96
109
|
const maxTokens = option(options, "maxTokens");
|
|
110
|
+
const envelope = buildAntigravityEnvelope({
|
|
111
|
+
wireModelId: route.wireModel,
|
|
112
|
+
family: entry.response.family,
|
|
113
|
+
contentsCount: contents.length,
|
|
114
|
+
messages: isDenseArray(field(context, "messages", true)),
|
|
115
|
+
injectedRequestId: requestId,
|
|
116
|
+
});
|
|
97
117
|
return { project, model: route.wireModel, request: { contents, ...(systemInstruction ? { systemInstruction } : {}), generationConfig: {
|
|
98
118
|
temperature: typeof temperature === "number" ? temperature : 1,
|
|
99
119
|
maxOutputTokens: resolveOutputTokens(maxTokens, entry.descriptor.maxTokens, route.thinking),
|
|
@@ -101,7 +121,7 @@ export function serializeTextContext(input) {
|
|
|
101
121
|
const thinkingConfig = serializeThinkingConfig(route.thinking);
|
|
102
122
|
return thinkingConfig ? { thinkingConfig } : {};
|
|
103
123
|
})(),
|
|
104
|
-
} }, requestType: "agent", userAgent: "antigravity", requestId };
|
|
124
|
+
}, sessionId: envelope.sessionId, labels: envelope.labels }, requestType: "agent", userAgent: "antigravity", requestId: envelope.requestId };
|
|
105
125
|
}
|
|
106
126
|
catch (error) {
|
|
107
127
|
if (error instanceof ContextSerializationError)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const ANTIGRAVITY_MODEL_ENUM: Readonly<Record<string, string>>;
|
|
2
|
+
export declare function stableUuid(seed: string): string;
|
|
3
|
+
export declare function resolveSessionTrajectory(messages?: readonly unknown[]): {
|
|
4
|
+
conversationId: string;
|
|
5
|
+
trajectoryId: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function clearSessionTrajectoryMap(): void;
|
|
8
|
+
export interface AntigravityEnvelope {
|
|
9
|
+
readonly requestId: string;
|
|
10
|
+
readonly sessionId: string;
|
|
11
|
+
readonly labels: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
export declare function buildAntigravityEnvelope(options: {
|
|
14
|
+
wireModelId: string;
|
|
15
|
+
family: "gemini" | "claude" | "gpt-oss";
|
|
16
|
+
contentsCount: number;
|
|
17
|
+
messages?: readonly unknown[];
|
|
18
|
+
explicitSessionId?: string;
|
|
19
|
+
injectedRequestId?: string;
|
|
20
|
+
}): AntigravityEnvelope;
|
package/dist/envelope.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
export const ANTIGRAVITY_MODEL_ENUM = Object.freeze({
|
|
3
|
+
// Gemini 3.8 Flash
|
|
4
|
+
"gemini-3.8-flash": "MODEL_PLACEHOLDER_M318",
|
|
5
|
+
"gemini-3.8-flash-high": "MODEL_PLACEHOLDER_M318",
|
|
6
|
+
"gemini-3.8-flash-medium": "MODEL_PLACEHOLDER_M319",
|
|
7
|
+
"gemini-3.8-flash-low": "MODEL_PLACEHOLDER_M320",
|
|
8
|
+
"gemini-3.8-flash-tiered": "MODEL_PLACEHOLDER_M322",
|
|
9
|
+
// Gemini 3.7 Flash
|
|
10
|
+
"gemini-3.7-flash": "MODEL_PLACEHOLDER_M298",
|
|
11
|
+
"gemini-3.7-flash-high": "MODEL_PLACEHOLDER_M298",
|
|
12
|
+
"gemini-3.7-flash-medium": "MODEL_PLACEHOLDER_M299",
|
|
13
|
+
"gemini-3.7-flash-low": "MODEL_PLACEHOLDER_M300",
|
|
14
|
+
"gemini-3.7-flash-tiered": "MODEL_PLACEHOLDER_M301",
|
|
15
|
+
// Gemini 3.6 Flash
|
|
16
|
+
"gemini-3.6-flash": "MODEL_PLACEHOLDER_M71",
|
|
17
|
+
"gemini-3.6-flash-high": "MODEL_PLACEHOLDER_M71",
|
|
18
|
+
"gemini-3.6-flash-medium": "MODEL_PLACEHOLDER_M72",
|
|
19
|
+
"gemini-3.6-flash-low": "MODEL_PLACEHOLDER_M73",
|
|
20
|
+
"gemini-3.6-flash-tiered": "MODEL_PLACEHOLDER_M196",
|
|
21
|
+
// Gemini 3.5 Flash
|
|
22
|
+
"gemini-3.5-flash": "MODEL_PLACEHOLDER_M20",
|
|
23
|
+
"gemini-3.5-flash-extra-low": "MODEL_PLACEHOLDER_M187",
|
|
24
|
+
"gemini-3.5-flash-low": "MODEL_PLACEHOLDER_M20",
|
|
25
|
+
"gemini-3-flash-agent": "MODEL_PLACEHOLDER_M84",
|
|
26
|
+
// Gemini 3.1 Pro
|
|
27
|
+
"gemini-3.1-pro": "MODEL_PLACEHOLDER_M36",
|
|
28
|
+
"gemini-3.1-pro-low": "MODEL_PLACEHOLDER_M36",
|
|
29
|
+
"gemini-3.1-pro-high": "MODEL_PLACEHOLDER_M37",
|
|
30
|
+
"gemini-pro-agent": "MODEL_PLACEHOLDER_M16",
|
|
31
|
+
// Claude
|
|
32
|
+
"claude-sonnet-4-6": "MODEL_PLACEHOLDER_M35",
|
|
33
|
+
"claude-opus-4-6": "MODEL_PLACEHOLDER_M26",
|
|
34
|
+
"claude-opus-4-6-thinking": "MODEL_PLACEHOLDER_M26",
|
|
35
|
+
// GPT-OSS
|
|
36
|
+
"gpt-oss-120b": "MODEL_OPENAI_GPT_OSS_120B_MEDIUM",
|
|
37
|
+
"gpt-oss-120b-medium": "MODEL_OPENAI_GPT_OSS_120B_MEDIUM",
|
|
38
|
+
});
|
|
39
|
+
export function stableUuid(seed) {
|
|
40
|
+
const bytes = createHash("sha1").update(seed).digest().subarray(0, 16);
|
|
41
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x50;
|
|
42
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
43
|
+
const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
44
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
45
|
+
}
|
|
46
|
+
const sessionTrajectoryMap = new Map();
|
|
47
|
+
export function resolveSessionTrajectory(messages) {
|
|
48
|
+
const firstMsg = Array.isArray(messages) ? messages[0] : undefined;
|
|
49
|
+
if (!isRecord(firstMsg)) {
|
|
50
|
+
return { conversationId: crypto.randomUUID(), trajectoryId: crypto.randomUUID() };
|
|
51
|
+
}
|
|
52
|
+
const role = typeof firstMsg.role === "string" ? firstMsg.role : "user";
|
|
53
|
+
const timestamp = typeof firstMsg.timestamp === "number" ? String(firstMsg.timestamp) : "";
|
|
54
|
+
const rawContent = firstMsg.content;
|
|
55
|
+
const contentSeed = typeof rawContent === "string"
|
|
56
|
+
? rawContent.slice(0, 64)
|
|
57
|
+
: Array.isArray(rawContent)
|
|
58
|
+
? JSON.stringify(rawContent[0] ?? "").slice(0, 64)
|
|
59
|
+
: "";
|
|
60
|
+
const seed = `${role}:${timestamp}:${contentSeed}`;
|
|
61
|
+
let entry = sessionTrajectoryMap.get(seed);
|
|
62
|
+
if (!entry) {
|
|
63
|
+
entry = {
|
|
64
|
+
conversationId: stableUuid(`antigravity:conv:${seed}`),
|
|
65
|
+
trajectoryId: stableUuid(`antigravity:traj:${seed}`),
|
|
66
|
+
};
|
|
67
|
+
sessionTrajectoryMap.set(seed, entry);
|
|
68
|
+
if (sessionTrajectoryMap.size > 64) {
|
|
69
|
+
const oldestKey = sessionTrajectoryMap.keys().next().value;
|
|
70
|
+
if (oldestKey !== undefined)
|
|
71
|
+
sessionTrajectoryMap.delete(oldestKey);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return entry;
|
|
75
|
+
}
|
|
76
|
+
export function clearSessionTrajectoryMap() {
|
|
77
|
+
sessionTrajectoryMap.clear();
|
|
78
|
+
}
|
|
79
|
+
const UUID_AGENT_REGEX = /^agent-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
80
|
+
export function buildAntigravityEnvelope(options) {
|
|
81
|
+
const isClaude = options.family === "claude";
|
|
82
|
+
const isNonGemini = options.family === "claude" || options.family === "gpt-oss";
|
|
83
|
+
const step = Math.max(1, options.contentsCount);
|
|
84
|
+
const lastStepIndex = String(Math.max(0, step - 1));
|
|
85
|
+
const assistantMsgCount = Array.isArray(options.messages)
|
|
86
|
+
? options.messages.filter((m) => isRecord(m) && m.role === "assistant" && m.stopReason !== "error" && m.stopReason !== "aborted").length
|
|
87
|
+
: 0;
|
|
88
|
+
const requestIndex = Math.max(0, assistantMsgCount);
|
|
89
|
+
const { conversationId, trajectoryId } = resolveSessionTrajectory(options.messages);
|
|
90
|
+
const sessionHash = createHash("sha1").update(`session:${trajectoryId}`).digest().subarray(0, 8);
|
|
91
|
+
const generatedSessionId = String(new DataView(sessionHash.buffer, sessionHash.byteOffset, 8).getBigInt64(0, true));
|
|
92
|
+
const sessionId = options.explicitSessionId || generatedSessionId;
|
|
93
|
+
const labels = {
|
|
94
|
+
last_step_index: lastStepIndex,
|
|
95
|
+
request_id: `${trajectoryId}-${requestIndex}`,
|
|
96
|
+
trajectory_id: trajectoryId,
|
|
97
|
+
used_claude: isClaude ? "true" : "false",
|
|
98
|
+
used_claude_conservative: isClaude ? "true" : "false",
|
|
99
|
+
used_non_gemini_model: isNonGemini ? "true" : "false",
|
|
100
|
+
};
|
|
101
|
+
const modelEnum = ANTIGRAVITY_MODEL_ENUM[options.wireModelId];
|
|
102
|
+
if (modelEnum) {
|
|
103
|
+
labels.model_enum = modelEnum;
|
|
104
|
+
}
|
|
105
|
+
const requestId = options.injectedRequestId && !UUID_AGENT_REGEX.test(options.injectedRequestId)
|
|
106
|
+
? options.injectedRequestId
|
|
107
|
+
: `agent/${conversationId}/${trajectoryId}/${step}`;
|
|
108
|
+
return { requestId, sessionId, labels };
|
|
109
|
+
}
|
|
110
|
+
function isRecord(value) {
|
|
111
|
+
return typeof value === "object" && value !== null;
|
|
112
|
+
}
|
package/dist/tool-context.d.ts
CHANGED
|
@@ -20,10 +20,12 @@ export interface ToolReplayDiagnostics {
|
|
|
20
20
|
readonly assistantToolCallBlockCount: number;
|
|
21
21
|
readonly declaredToolCount: number;
|
|
22
22
|
}
|
|
23
|
+
export declare function sanitizeToolCallId(id: string, fallbackName?: string): string;
|
|
23
24
|
export interface ToolReplayPolicy {
|
|
24
25
|
readonly requireSignedToolCalls: boolean;
|
|
25
26
|
readonly isSameModel: (message: Record<string, unknown>) => boolean;
|
|
26
27
|
readonly toolCallSignature: (part: Record<string, unknown>, message: Record<string, unknown>) => string | undefined;
|
|
28
|
+
readonly includeToolCallId?: boolean;
|
|
27
29
|
}
|
|
28
30
|
export declare function replayToolHistory(messages: unknown[], serializePart: (part: Record<string, unknown>, message: Record<string, unknown>) => WirePart, onDiagnostics?: (diagnostics: ToolReplayDiagnostics) => void, policy?: ToolReplayPolicy, declaredToolCount?: number): WireContent[];
|
|
29
31
|
export {};
|
package/dist/tool-context.js
CHANGED
|
@@ -32,6 +32,12 @@ export function prepareToolContext(tools, choice, schemaProfile) {
|
|
|
32
32
|
unsupportedChoice();
|
|
33
33
|
return { declarations, mode: choice === "none" ? "NONE" : "AUTO" };
|
|
34
34
|
}
|
|
35
|
+
let toolCallCounter = 0;
|
|
36
|
+
export function sanitizeToolCallId(id, fallbackName) {
|
|
37
|
+
const cleaned = id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
38
|
+
const capped = cleaned.slice(0, 64);
|
|
39
|
+
return capped || `${fallbackName || "tool"}_${++toolCallCounter}`;
|
|
40
|
+
}
|
|
35
41
|
export function replayToolHistory(messages, serializePart, onDiagnostics, policy, declaredToolCount = 0) {
|
|
36
42
|
const output = [];
|
|
37
43
|
const calls = new Set();
|
|
@@ -63,7 +69,7 @@ export function replayToolHistory(messages, serializePart, onDiagnostics, policy
|
|
|
63
69
|
if (actual)
|
|
64
70
|
return actual;
|
|
65
71
|
recoveryCount.value += 1;
|
|
66
|
-
return pending.observations ? observation(call, missingResultText()) : missingResult(call);
|
|
72
|
+
return pending.observations ? observation(call, missingResultText()) : missingResult(call, policy?.includeToolCallId);
|
|
67
73
|
});
|
|
68
74
|
if (pending.extraParts?.length) {
|
|
69
75
|
turnParts.push(...pending.extraParts);
|
|
@@ -109,7 +115,7 @@ export function replayToolHistory(messages, serializePart, onDiagnostics, policy
|
|
|
109
115
|
const text = textParts.join("\n\n");
|
|
110
116
|
const outputText = text || (imageParts.length > 0 ? "[Image content]" : "");
|
|
111
117
|
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 } });
|
|
118
|
+
pending.results.set(id, pending.observations ? observation(call, outputText) : { functionResponse: { ...(policy?.includeToolCallId ? { id: sanitizeToolCallId(call.id, call.name) } : {}), name: call.name, response } });
|
|
113
119
|
if (imageParts.length > 0) {
|
|
114
120
|
if (!pending.extraParts)
|
|
115
121
|
pending.extraParts = [];
|
|
@@ -174,7 +180,7 @@ export function replayToolHistory(messages, serializePart, onDiagnostics, policy
|
|
|
174
180
|
return [part];
|
|
175
181
|
if (observations)
|
|
176
182
|
return [];
|
|
177
|
-
return [{ functionCall: { name: part.call.name, args: part.call.args }, ...(part.signature ? { thoughtSignature: part.signature } : {}) }];
|
|
183
|
+
return [{ functionCall: { ...(policy?.includeToolCallId ? { id: sanitizeToolCallId(part.call.id, part.call.name) } : {}), name: part.call.name, args: part.call.args }, ...(part.signature ? { thoughtSignature: part.signature } : {}) }];
|
|
178
184
|
}));
|
|
179
185
|
pending = { calls: group, results: new Map(), observations };
|
|
180
186
|
}
|
|
@@ -190,9 +196,10 @@ function observation(call, text) {
|
|
|
190
196
|
function missingResultText() {
|
|
191
197
|
return "Tool execution did not complete or its result was not recorded. Treat the call as failed; do not assume it had no side effects and do not retry it automatically.";
|
|
192
198
|
}
|
|
193
|
-
function missingResult(call) {
|
|
199
|
+
function missingResult(call, includeToolCallId) {
|
|
194
200
|
return {
|
|
195
201
|
functionResponse: {
|
|
202
|
+
...(includeToolCallId ? { id: sanitizeToolCallId(call.id, call.name) } : {}),
|
|
196
203
|
name: call.name,
|
|
197
204
|
response: {
|
|
198
205
|
error: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@benjamolina/pi-antigravity-guard",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.9",
|
|
4
4
|
"description": "Pi adapter for Antigravity Guard",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"README.md"
|
|
25
25
|
],
|
|
26
26
|
"pi": {
|
|
27
|
-
"extensions": [
|
|
27
|
+
"extensions": [
|
|
28
|
+
"./dist/extension.js"
|
|
29
|
+
]
|
|
28
30
|
},
|
|
29
31
|
"dependencies": {
|
|
30
32
|
"@benjamolina/antigravity-guard-core": "0.1.0"
|