@bitkyc08/opencodex 2.6.15-preview.20260701 → 2.6.15
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/gui/dist/assets/index-4jSPBLbx.js +9 -0
- package/gui/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/adapters/anthropic.ts +11 -3
- package/src/adapters/google.ts +7 -5
- package/src/providers/antigravity-models.ts +31 -7
- package/src/responses/parser.ts +1 -0
- package/src/server.ts +1 -0
- package/src/types.ts +1 -0
- package/src/usage-summary.ts +24 -3
- package/gui/dist/assets/index-lhwpequc.js +0 -9
package/gui/dist/index.html
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
} catch (e) {}
|
|
17
17
|
})();
|
|
18
18
|
</script>
|
|
19
|
-
<script type="module" crossorigin src="/assets/index-
|
|
19
|
+
<script type="module" crossorigin src="/assets/index-4jSPBLbx.js"></script>
|
|
20
20
|
<link rel="stylesheet" crossorigin href="/assets/index-DIBiVVC0.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
package/package.json
CHANGED
|
@@ -41,6 +41,11 @@ const OUTPUT_HEADROOM = 8192;
|
|
|
41
41
|
/** Minimum visible-output room kept below `max_tokens` (so `max_tokens > budget_tokens` always holds). */
|
|
42
42
|
const OUTPUT_FLOOR = 4096;
|
|
43
43
|
const COMPAT_TOOL_PREFIX = "cx_";
|
|
44
|
+
const EPHEMERAL_CACHE_CONTROL = { type: "ephemeral" } as const;
|
|
45
|
+
|
|
46
|
+
function withPromptCache<T extends Record<string, unknown>>(block: T): T & { cache_control: typeof EPHEMERAL_CACHE_CONTROL } {
|
|
47
|
+
return { ...block, cache_control: EPHEMERAL_CACHE_CONTROL };
|
|
48
|
+
}
|
|
44
49
|
|
|
45
50
|
/** Map a Responses reasoning effort to an Anthropic extended-thinking budget (tokens, >= 1024). */
|
|
46
51
|
function reasoningBudget(effort: string): number {
|
|
@@ -203,11 +208,14 @@ function toolsToAnthropicFormat(parsed: OcxParsedRequest, toolNames: { toWire: (
|
|
|
203
208
|
? parsed.context.tools.filter(t => toolAllowedByChoice(t, allowed))
|
|
204
209
|
: parsed.context.tools;
|
|
205
210
|
if (tools.length === 0) return undefined;
|
|
206
|
-
|
|
211
|
+
const converted = tools.map(t => ({
|
|
207
212
|
name: toolNames.toWire(namespacedToolName(t.namespace, t.name)),
|
|
208
213
|
description: t.description,
|
|
209
214
|
input_schema: t.parameters,
|
|
210
215
|
}));
|
|
216
|
+
const last = converted.length - 1;
|
|
217
|
+
converted[last] = withPromptCache(converted[last]);
|
|
218
|
+
return converted;
|
|
211
219
|
}
|
|
212
220
|
|
|
213
221
|
export function createAnthropicAdapter(provider: OcxProviderConfig): ProviderAdapter {
|
|
@@ -230,10 +238,10 @@ export function createAnthropicAdapter(provider: OcxProviderConfig): ProviderAda
|
|
|
230
238
|
// Claude OAuth (Pro/Max) requires the first system block to be the Claude Code identity.
|
|
231
239
|
body.system = [
|
|
232
240
|
{ type: "text", text: CLAUDE_CODE_SYSTEM_INSTRUCTION },
|
|
233
|
-
...(system ? [{ type: "text", text: system }] : []),
|
|
241
|
+
...(system ? [withPromptCache({ type: "text", text: system })] : []),
|
|
234
242
|
];
|
|
235
243
|
} else if (system) {
|
|
236
|
-
body.system = system;
|
|
244
|
+
body.system = [withPromptCache({ type: "text", text: system })];
|
|
237
245
|
}
|
|
238
246
|
if (tools) body.tools = tools;
|
|
239
247
|
if (parsed.options.temperature !== undefined) body.temperature = parsed.options.temperature;
|
package/src/adapters/google.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { ANTIGRAVITY_REQUEST_UA, antigravitySessionId, isLikelyRealThoughtSignat
|
|
|
20
20
|
import { sanitizeGeminiToolParameters } from "./google-tool-schema";
|
|
21
21
|
import { neutralizeIdentity } from "./identity";
|
|
22
22
|
import { antigravityUsesReplayCache, applyAntigravityReplay, clearAntigravityReplay, observeAntigravityReplay } from "./google-antigravity-replay";
|
|
23
|
+
import { resolveAntigravityWireModelId } from "../providers/antigravity-models";
|
|
23
24
|
|
|
24
25
|
// Google-family models (Gemini/Vertex/Antigravity) tend to emit long running commentary between
|
|
25
26
|
// tool calls. This steers them to keep the BETWEEN-STEP text to one line and reason internally
|
|
@@ -229,14 +230,15 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
229
230
|
const project = provider.project;
|
|
230
231
|
if (!project) throw new Error("Antigravity requires a discovered Cloud Code Assist project id (re-run `ocx login google-antigravity`).");
|
|
231
232
|
const sessionId = antigravitySessionId(parsed);
|
|
232
|
-
|
|
233
|
+
const wireModelId = resolveAntigravityWireModelId(parsed.modelId);
|
|
234
|
+
antigravityModel = wireModelId;
|
|
233
235
|
antigravitySession = sessionId;
|
|
234
236
|
// Reasoning continuity: Gemini models re-inject cached thoughtSignatures; Claude-on-Antigravity
|
|
235
237
|
// sanitizes signatures inline (no cache). Both guard against the upstream 400 on bad signatures.
|
|
236
238
|
if (Array.isArray((body as { contents?: unknown[] }).contents)) {
|
|
237
239
|
const contents = (body as { contents: unknown[] }).contents;
|
|
238
|
-
if (antigravityUsesReplayCache(
|
|
239
|
-
applyAntigravityReplay(
|
|
240
|
+
if (antigravityUsesReplayCache(wireModelId)) {
|
|
241
|
+
applyAntigravityReplay(wireModelId, sessionId, contents);
|
|
240
242
|
} else {
|
|
241
243
|
sanitizeAntigravityClaudeSignatures(contents);
|
|
242
244
|
}
|
|
@@ -246,13 +248,13 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
246
248
|
// spelling is a non-first-party key, so we send the single canonical location.
|
|
247
249
|
const request: Record<string, unknown> = { ...body, sessionId };
|
|
248
250
|
// Claude-on-Antigravity forces VALIDATED function calling (the real client always sets it).
|
|
249
|
-
if (/claude/i.test(
|
|
251
|
+
if (/claude/i.test(wireModelId)) {
|
|
250
252
|
const existing = (request.toolConfig ?? {}) as Record<string, unknown>;
|
|
251
253
|
const fcc = (existing.functionCallingConfig ?? {}) as Record<string, unknown>;
|
|
252
254
|
request.toolConfig = { ...existing, functionCallingConfig: { ...fcc, mode: "VALIDATED" } };
|
|
253
255
|
}
|
|
254
256
|
const envelope = {
|
|
255
|
-
model:
|
|
257
|
+
model: wireModelId,
|
|
256
258
|
// The envelope's `userAgent` field is a protocol constant ("antigravity"), distinct from
|
|
257
259
|
// the HTTP `User-Agent` header (the real CLI UA). CLIProxyAPI `geminiToAntigravity` hardcodes
|
|
258
260
|
// the body field; only the header carries the versioned client string.
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
// Google Antigravity (Cloud Code Assist) bundled model list.
|
|
2
2
|
//
|
|
3
3
|
// Single source of truth: the Antigravity `:fetchAvailableModels` backend, the same one the `agy`
|
|
4
|
-
// CLI resolves labels against. The
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
// backend has no OpenAI-style `GET /models`, so this static list is what surfaces in the picker.
|
|
9
|
-
export const ANTIGRAVITY_MODELS = [
|
|
4
|
+
// CLI resolves labels against. The ids below are the CCA WIRE ids followed by CLIProxyAPI-style
|
|
5
|
+
// client aliases. The CCA envelope's `model` field must receive the wire id (for example
|
|
6
|
+
// "Gemini 3.1 Pro (High)" => gemini-pro-agent), while the picker can expose label-shaped aliases.
|
|
7
|
+
const ANTIGRAVITY_WIRE_MODELS = [
|
|
10
8
|
"gemini-3.5-flash-low",
|
|
11
9
|
"gemini-3-flash-agent",
|
|
12
10
|
"gemini-3.5-flash-extra-low",
|
|
@@ -17,8 +15,20 @@ export const ANTIGRAVITY_MODELS = [
|
|
|
17
15
|
"gpt-oss-120b-medium",
|
|
18
16
|
];
|
|
19
17
|
|
|
18
|
+
export const ANTIGRAVITY_MODEL_ALIASES: Record<string, string> = {
|
|
19
|
+
"gemini-3.5-flash-mid": "gemini-3.5-flash-low",
|
|
20
|
+
"gemini-3.5-flash-high": "gemini-3-flash-agent",
|
|
21
|
+
"gemini-3.1-pro-high": "gemini-pro-agent",
|
|
22
|
+
"gemini-3.1-pro-preview": "gemini-pro-agent",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const ANTIGRAVITY_MODELS = [
|
|
26
|
+
...ANTIGRAVITY_WIRE_MODELS,
|
|
27
|
+
...Object.keys(ANTIGRAVITY_MODEL_ALIASES),
|
|
28
|
+
];
|
|
29
|
+
|
|
20
30
|
// Context windows from the upstream `:fetchAvailableModels` maxTokens per model.
|
|
21
|
-
|
|
31
|
+
const ANTIGRAVITY_WIRE_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
22
32
|
"gemini-3.5-flash-low": 1_048_576,
|
|
23
33
|
"gemini-3-flash-agent": 1_048_576,
|
|
24
34
|
"gemini-3.5-flash-extra-low": 1_048_576,
|
|
@@ -28,3 +38,17 @@ export const ANTIGRAVITY_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
|
28
38
|
"claude-opus-4-6-thinking": 1_000_000,
|
|
29
39
|
"gpt-oss-120b-medium": 131_072,
|
|
30
40
|
};
|
|
41
|
+
|
|
42
|
+
export const ANTIGRAVITY_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
43
|
+
...ANTIGRAVITY_WIRE_MODEL_CONTEXT_WINDOWS,
|
|
44
|
+
...Object.fromEntries(
|
|
45
|
+
Object.entries(ANTIGRAVITY_MODEL_ALIASES).map(([alias, wire]) => [
|
|
46
|
+
alias,
|
|
47
|
+
ANTIGRAVITY_WIRE_MODEL_CONTEXT_WINDOWS[wire],
|
|
48
|
+
]),
|
|
49
|
+
),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export function resolveAntigravityWireModelId(modelId: string): string {
|
|
53
|
+
return ANTIGRAVITY_MODEL_ALIASES[modelId] ?? modelId;
|
|
54
|
+
}
|
package/src/responses/parser.ts
CHANGED
|
@@ -396,6 +396,7 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
396
396
|
if (data.presence_penalty !== undefined) options.presencePenalty = data.presence_penalty;
|
|
397
397
|
if (data.frequency_penalty !== undefined) options.frequencyPenalty = data.frequency_penalty;
|
|
398
398
|
if (data.service_tier !== undefined) options.serviceTier = data.service_tier;
|
|
399
|
+
if (data.prompt_cache_key !== undefined) options.promptCacheKey = data.prompt_cache_key;
|
|
399
400
|
|
|
400
401
|
// Stash the hosted web_search config (if Codex enabled it) so the proxy can run searches via the
|
|
401
402
|
// gpt-mini sidecar for routed providers. buildTools still drops the hosted tool; the sidecar path
|
package/src/server.ts
CHANGED
|
@@ -1589,6 +1589,7 @@ async function handleManagementAPI(req: Request, url: URL, config: OcxConfig): P
|
|
|
1589
1589
|
generatedAt: now,
|
|
1590
1590
|
summary: {
|
|
1591
1591
|
requests: 0,
|
|
1592
|
+
measuredRequests: 0,
|
|
1592
1593
|
reportedRequests: 0,
|
|
1593
1594
|
unreportedRequests: 0,
|
|
1594
1595
|
unsupportedRequests: 0,
|
package/src/types.ts
CHANGED
|
@@ -171,6 +171,7 @@ export interface OcxRequestOptions {
|
|
|
171
171
|
serviceTier?: string;
|
|
172
172
|
presencePenalty?: number;
|
|
173
173
|
frequencyPenalty?: number;
|
|
174
|
+
/** Responses prompt-cache affinity key. Passthrough preserves it via _rawBody; routed adapters do not consume it unless their upstream wire supports it. */
|
|
174
175
|
promptCacheKey?: string;
|
|
175
176
|
}
|
|
176
177
|
|
package/src/usage-summary.ts
CHANGED
|
@@ -5,6 +5,7 @@ export type UsageRange = "7d" | "30d" | "all";
|
|
|
5
5
|
|
|
6
6
|
export interface UsageSummaryTotals {
|
|
7
7
|
requests: number;
|
|
8
|
+
measuredRequests: number;
|
|
8
9
|
reportedRequests: number;
|
|
9
10
|
unreportedRequests: number;
|
|
10
11
|
unsupportedRequests: number;
|
|
@@ -20,6 +21,7 @@ export interface UsageSummaryTotals {
|
|
|
20
21
|
export interface UsageDay {
|
|
21
22
|
date: string;
|
|
22
23
|
requests: number;
|
|
24
|
+
measuredRequests: number;
|
|
23
25
|
reportedRequests: number;
|
|
24
26
|
totalTokens: number;
|
|
25
27
|
models: UsageDayModel[];
|
|
@@ -37,7 +39,9 @@ export interface UsageModel {
|
|
|
37
39
|
model: string;
|
|
38
40
|
resolvedModel?: string;
|
|
39
41
|
requests: number;
|
|
42
|
+
measuredRequests: number;
|
|
40
43
|
reportedRequests: number;
|
|
44
|
+
estimatedRequests: number;
|
|
41
45
|
totalTokens: number;
|
|
42
46
|
inputTokens: number;
|
|
43
47
|
outputTokens: number;
|
|
@@ -47,7 +51,9 @@ export interface UsageModel {
|
|
|
47
51
|
export interface UsageProvider {
|
|
48
52
|
provider: string;
|
|
49
53
|
requests: number;
|
|
54
|
+
measuredRequests: number;
|
|
50
55
|
reportedRequests: number;
|
|
56
|
+
estimatedRequests: number;
|
|
51
57
|
totalTokens: number;
|
|
52
58
|
shareRatio: number;
|
|
53
59
|
}
|
|
@@ -93,6 +99,7 @@ function dayCountForAllRange(entries: PersistedUsageEntry[], now: number): numbe
|
|
|
93
99
|
function blankTotals(): UsageSummaryTotals {
|
|
94
100
|
return {
|
|
95
101
|
requests: 0,
|
|
102
|
+
measuredRequests: 0,
|
|
96
103
|
reportedRequests: 0,
|
|
97
104
|
unreportedRequests: 0,
|
|
98
105
|
unsupportedRequests: 0,
|
|
@@ -106,8 +113,13 @@ function blankTotals(): UsageSummaryTotals {
|
|
|
106
113
|
};
|
|
107
114
|
}
|
|
108
115
|
|
|
116
|
+
function isMeasuredStatus(status: UsageStatus): boolean {
|
|
117
|
+
return status === "reported" || status === "estimated";
|
|
118
|
+
}
|
|
119
|
+
|
|
109
120
|
function bumpStatus(totals: UsageSummaryTotals, status: UsageStatus): void {
|
|
110
121
|
totals.requests += 1;
|
|
122
|
+
if (isMeasuredStatus(status)) totals.measuredRequests += 1;
|
|
111
123
|
if (status === "reported") totals.reportedRequests += 1;
|
|
112
124
|
else if (status === "unreported") totals.unreportedRequests += 1;
|
|
113
125
|
else if (status === "unsupported") totals.unsupportedRequests += 1;
|
|
@@ -125,7 +137,7 @@ function addTokens(totals: UsageSummaryTotals, entry: PersistedUsageEntry): void
|
|
|
125
137
|
}
|
|
126
138
|
|
|
127
139
|
function finalizeCoverage(totals: UsageSummaryTotals): void {
|
|
128
|
-
totals.coverageRatio = totals.requests === 0 ? 0 : totals.
|
|
140
|
+
totals.coverageRatio = totals.requests === 0 ? 0 : totals.measuredRequests / totals.requests;
|
|
129
141
|
}
|
|
130
142
|
|
|
131
143
|
function buildDayGrid(range: UsageRange, since: number | null, now: number, entries: PersistedUsageEntry[]): UsageDay[] {
|
|
@@ -147,16 +159,17 @@ function buildDayGrid(range: UsageRange, since: number | null, now: number, entr
|
|
|
147
159
|
};
|
|
148
160
|
for (let i = days - 1; i >= 0; i--) {
|
|
149
161
|
const key = localDateKey(now - i * DAY_MS);
|
|
150
|
-
grid.set(key, { date: key, requests: 0, reportedRequests: 0, totalTokens: 0, models: [] });
|
|
162
|
+
grid.set(key, { date: key, requests: 0, measuredRequests: 0, reportedRequests: 0, totalTokens: 0, models: [] });
|
|
151
163
|
}
|
|
152
164
|
for (const entry of entries) {
|
|
153
165
|
const key = localDateKey(entry.timestamp);
|
|
154
166
|
let day = grid.get(key);
|
|
155
167
|
if (!day) {
|
|
156
|
-
day = { date: key, requests: 0, reportedRequests: 0, totalTokens: 0, models: [] };
|
|
168
|
+
day = { date: key, requests: 0, measuredRequests: 0, reportedRequests: 0, totalTokens: 0, models: [] };
|
|
157
169
|
grid.set(key, day);
|
|
158
170
|
}
|
|
159
171
|
day.requests += 1;
|
|
172
|
+
if (isMeasuredStatus(entry.usageStatus)) day.measuredRequests += 1;
|
|
160
173
|
if (entry.usageStatus === "reported") day.reportedRequests += 1;
|
|
161
174
|
if (typeof entry.totalTokens === "number") day.totalTokens += entry.totalTokens;
|
|
162
175
|
else if (entry.usage) day.totalTokens += entry.usage.inputTokens + entry.usage.outputTokens;
|
|
@@ -186,7 +199,9 @@ function buildModels(entries: PersistedUsageEntry[], totalRequests: number): Usa
|
|
|
186
199
|
model: entry.model,
|
|
187
200
|
...(entry.resolvedModel ? { resolvedModel: entry.resolvedModel } : {}),
|
|
188
201
|
requests: 0,
|
|
202
|
+
measuredRequests: 0,
|
|
189
203
|
reportedRequests: 0,
|
|
204
|
+
estimatedRequests: 0,
|
|
190
205
|
totalTokens: 0,
|
|
191
206
|
inputTokens: 0,
|
|
192
207
|
outputTokens: 0,
|
|
@@ -195,7 +210,9 @@ function buildModels(entries: PersistedUsageEntry[], totalRequests: number): Usa
|
|
|
195
210
|
byKey.set(key, model);
|
|
196
211
|
}
|
|
197
212
|
model.requests += 1;
|
|
213
|
+
if (isMeasuredStatus(entry.usageStatus)) model.measuredRequests += 1;
|
|
198
214
|
if (entry.usageStatus === "reported") model.reportedRequests += 1;
|
|
215
|
+
else if (entry.usageStatus === "estimated") model.estimatedRequests += 1;
|
|
199
216
|
if (entry.usage) {
|
|
200
217
|
model.inputTokens += entry.usage.inputTokens;
|
|
201
218
|
model.outputTokens += entry.usage.outputTokens;
|
|
@@ -217,14 +234,18 @@ function buildProviders(entries: PersistedUsageEntry[], totalRequests: number):
|
|
|
217
234
|
provider = {
|
|
218
235
|
provider: providerKey,
|
|
219
236
|
requests: 0,
|
|
237
|
+
measuredRequests: 0,
|
|
220
238
|
reportedRequests: 0,
|
|
239
|
+
estimatedRequests: 0,
|
|
221
240
|
totalTokens: 0,
|
|
222
241
|
shareRatio: 0,
|
|
223
242
|
};
|
|
224
243
|
byKey.set(providerKey, provider);
|
|
225
244
|
}
|
|
226
245
|
provider.requests += 1;
|
|
246
|
+
if (isMeasuredStatus(entry.usageStatus)) provider.measuredRequests += 1;
|
|
227
247
|
if (entry.usageStatus === "reported") provider.reportedRequests += 1;
|
|
248
|
+
else if (entry.usageStatus === "estimated") provider.estimatedRequests += 1;
|
|
228
249
|
if (entry.usage) {
|
|
229
250
|
if (typeof entry.totalTokens === "number") provider.totalTokens += entry.totalTokens;
|
|
230
251
|
else provider.totalTokens += entry.usage.inputTokens + entry.usage.outputTokens;
|