@yansigit/opencodex 2.31.3 → 2.33.0
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 +2 -2
- package/bin/ocx.mjs +99 -70
- package/gui/dist/assets/index-DKLr4LTE.js +102 -0
- package/gui/dist/assets/index-DrSQdTRd.css +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +6 -5
- package/src/adapters/anthropic.ts +25 -13
- package/src/adapters/azure.ts +20 -4
- package/src/adapters/base.ts +5 -1
- package/src/adapters/command-code.ts +42 -10
- package/src/adapters/cursor/live-models.ts +8 -0
- package/src/adapters/cursor/live-transport.ts +1 -1
- package/src/adapters/cursor/native-exec-desktop.ts +16 -0
- package/src/adapters/cursor/protobuf-events.ts +158 -7
- package/src/adapters/cursor/protobuf-request.ts +33 -15
- package/src/adapters/cursor/request-builder.ts +4 -3
- package/src/adapters/cursor/tool-definitions.ts +27 -1
- package/src/adapters/cursor/types.ts +4 -3
- package/src/adapters/cursor.ts +9 -0
- package/src/adapters/google-antigravity-replay.ts +2 -2
- package/src/adapters/google-antigravity-wire.ts +7 -0
- package/src/adapters/google-errors.ts +6 -2
- package/src/adapters/google-http.ts +30 -7
- package/src/adapters/google-truncation.ts +5 -0
- package/src/adapters/google-wire-compiler.ts +38 -6
- package/src/adapters/google.ts +154 -33
- package/src/adapters/kiro-tools.ts +20 -9
- package/src/adapters/kiro.ts +0 -3
- package/src/adapters/openai-chat.ts +9 -0
- package/src/adapters/openai-responses.ts +4 -1
- package/src/adapters/tool-catalog-nudge.ts +1 -1
- package/src/adapters/xai-web-search.ts +7 -2
- package/src/bridge.ts +133 -24
- package/src/claude/context-windows.ts +16 -9
- package/src/cli/dispatch.ts +50 -2
- package/src/cli/doctor.ts +26 -13
- package/src/cli/help.ts +4 -3
- package/src/cli/index.ts +20 -6
- package/src/cli/models.ts +13 -3
- package/src/cli/observe.ts +20 -5
- package/src/cli/provider.ts +8 -1
- package/src/cli/registry.ts +7 -5
- package/src/cli/status.ts +25 -1
- package/src/cli/system-restart-client.ts +1 -1
- package/src/cli/usage-report.ts +134 -0
- package/src/codex/app-server-processes.ts +3 -1
- package/src/codex/auth-api.ts +4 -2
- package/src/codex/autostart-health.ts +16 -0
- package/src/codex/catalog/aggregation.ts +12 -0
- package/src/codex/catalog/effort.ts +42 -12
- package/src/codex/catalog/metadata.ts +27 -1
- package/src/codex/catalog/model-metadata.ts +593 -0
- package/src/codex/catalog/parsing.ts +71 -27
- package/src/codex/catalog/provider-fetch.ts +189 -33
- package/src/codex/catalog/sync.ts +6 -5
- package/src/codex/convergence.ts +5 -0
- package/src/codex/desktop-app-restart.ts +342 -0
- package/src/codex/history-job.ts +32 -3
- package/src/codex/history-manifest.ts +112 -0
- package/src/codex/history-migration-guardian.ts +5 -5
- package/src/codex/history-provider.ts +825 -247
- package/src/codex/history-worker.ts +8 -5
- package/src/codex/inject.ts +49 -21
- package/src/codex/injected-marker.ts +1 -1
- package/src/codex/internal/history-writer.ts +4 -3
- package/src/codex/native-profile-startup.ts +157 -27
- package/src/codex/native-residue.ts +26 -33
- package/src/codex/shim.ts +56 -3
- package/src/combos/failover.ts +27 -0
- package/src/compatibility/index.ts +26 -0
- package/src/compatibility/manifest.ts +253 -0
- package/src/compatibility/openai-responses.ts +81 -0
- package/src/config/atomic-write.ts +219 -0
- package/src/config/paths.ts +40 -0
- package/src/config/process-state.ts +308 -0
- package/src/config/provider-validation.ts +214 -0
- package/src/config.ts +153 -814
- package/src/generated/compatibility-version.json +232 -148
- package/src/images/loop.ts +37 -6
- package/src/images/plan.ts +5 -4
- package/src/integrations/ownership-policy.ts +141 -0
- package/src/integrations/ownership.ts +10 -0
- package/src/integrations/state.ts +44 -5
- package/src/integrations/writer.ts +6 -0
- package/src/lib/azure-identity.ts +154 -0
- package/src/lib/bounded-body.ts +14 -2
- package/src/lib/debug.ts +42 -0
- package/src/lib/errors.ts +14 -0
- package/src/lib/process-control.ts +2 -1
- package/src/lib/provider-outbound.ts +45 -33
- package/src/lib/provider-tls-profile.ts +309 -0
- package/src/lib/proxy-env.ts +49 -0
- package/src/lib/redact.ts +10 -1
- package/src/lib/state-store-registrations.ts +2 -0
- package/src/lib/tool-argument-integers.ts +56 -5
- package/src/oauth/antigravity-routing.ts +282 -236
- package/src/oauth/callback-server.ts +22 -2
- package/src/oauth/command-code.ts +5 -16
- package/src/oauth/google-antigravity.ts +42 -5
- package/src/oauth/health.ts +1 -1
- package/src/oauth/index.ts +15 -3
- package/src/oauth/kimi.ts +9 -1
- package/src/oauth/open-browser-choice.ts +26 -0
- package/src/oauth/store.ts +6 -0
- package/src/providers/antigravity-quota.ts +3 -1
- package/src/providers/api-keys.ts +2 -1
- package/src/providers/auto-compact-budget.ts +65 -0
- package/src/providers/derive.ts +4 -0
- package/src/providers/key-failover.ts +5 -1
- package/src/providers/openai-tiers.ts +5 -0
- package/src/providers/provider-id-rewrite.ts +1 -0
- package/src/providers/quota.ts +59 -13
- package/src/providers/registry.ts +4 -2
- package/src/providers/request-pacing.ts +33 -6
- package/src/providers/xai-transport.ts +21 -0
- package/src/reasoning-effort.ts +19 -2
- package/src/responses/apply-patch-envelope.ts +63 -0
- package/src/responses/custom-tool-compat.ts +132 -38
- package/src/responses/google-provider-options.ts +36 -0
- package/src/responses/namespace-tool-compat.ts +84 -4
- package/src/responses/parser.ts +14 -2
- package/src/responses/provider-opaque-metadata.ts +3 -3
- package/src/responses/reasoning-replay-cache.ts +81 -3
- package/src/responses/schema.ts +37 -0
- package/src/responses/state.ts +94 -4
- package/src/router.ts +8 -2
- package/src/server/auth-cors.ts +37 -7
- package/src/server/images.ts +19 -35
- package/src/server/index.ts +102 -21
- package/src/server/local-management-read-client.ts +1 -1
- package/src/server/local-provider-reload-client.ts +1 -1
- package/src/server/management/agent-settings-routes.ts +206 -16
- package/src/server/management/combo-routes.ts +6 -0
- package/src/server/management/config-routes.ts +35 -6
- package/src/server/management/context.ts +1 -1
- package/src/server/management/logs-usage-routes.ts +27 -6
- package/src/server/management/model-routes.ts +8 -4
- package/src/server/management/model-rows.ts +4 -0
- package/src/server/management/native-integration-routes.ts +2 -1
- package/src/server/management/oauth-account-routes.ts +25 -4
- package/src/server/management/provider-capability-config.ts +1 -1
- package/src/server/management/provider-routes.ts +113 -15
- package/src/server/management/routing-profile-routes.ts +3 -0
- package/src/server/management/system-restart.ts +1 -1
- package/src/server/port-reclaim.ts +1 -1
- package/src/server/proxy-liveness.ts +2 -1
- package/src/server/request-log-conversation.ts +30 -0
- package/src/server/request-log.ts +21 -0
- package/src/server/responses/agent-task-recovery.ts +1 -1
- package/src/server/responses/codex-auth-error.ts +55 -0
- package/src/server/responses/combo-stream-preflight.ts +171 -0
- package/src/server/responses/compact.ts +36 -22
- package/src/server/responses/core.ts +584 -247
- package/src/server/responses/empty-completion-guard.ts +35 -6
- package/src/server/responses/fetch-helpers.ts +20 -102
- package/src/server/responses/v2-native-parent-override.ts +59 -0
- package/src/server/responses/ws-upstream.ts +75 -2
- package/src/server/responses-custom-tool-repair.ts +41 -5
- package/src/server/responses-undeclared-tool-guard.ts +241 -18
- package/src/service.ts +9 -5
- package/src/types/config.ts +16 -1
- package/src/types/provider.ts +16 -0
- package/src/types/request.ts +34 -1
- package/src/types/tools.ts +114 -11
- package/src/types.ts +7 -1
- package/src/update/index.ts +5 -4
- package/src/update/job.ts +3 -1
- package/src/update/transactional-install.mjs +8 -1
- package/src/usage/log.ts +16 -8
- package/src/usage/summary.ts +201 -8
- package/src/vision/describe.ts +18 -13
- package/src/web-search/executor.ts +10 -3
- package/src/web-search/gemini-executor.ts +6 -4
- package/src/web-search/loop.ts +42 -6
- package/gui/dist/assets/index-CGoDO3uO.css +0 -1
- package/gui/dist/assets/index-Cxt5fZMP.js +0 -102
package/src/adapters/cursor.ts
CHANGED
|
@@ -208,6 +208,14 @@ export function createCursorAdapter(provider: OcxProviderConfig, deps: CursorAda
|
|
|
208
208
|
};
|
|
209
209
|
|
|
210
210
|
const runOnce = async (activeRequest: ReturnType<typeof createCursorRequest>) => {
|
|
211
|
+
const effort = _parsed.options.reasoning;
|
|
212
|
+
const isHeavyReasoning = effort === "high"
|
|
213
|
+
|| effort === "max"
|
|
214
|
+
|| effort === "xhigh"
|
|
215
|
+
|| activeRequest.modelId.includes("grok-4.6")
|
|
216
|
+
|| activeRequest.modelId.includes("kimi-k3")
|
|
217
|
+
|| activeRequest.modelId.includes("opus-4-8");
|
|
218
|
+
const heartbeatOnlyMs = isHeavyReasoning ? 300_000 : 180_000;
|
|
211
219
|
await runCursorTurnWithRetry(
|
|
212
220
|
makeTransport,
|
|
213
221
|
{
|
|
@@ -216,6 +224,7 @@ export function createCursorAdapter(provider: OcxProviderConfig, deps: CursorAda
|
|
|
216
224
|
translatorBudget: incoming.translatorBudget,
|
|
217
225
|
requestDeclaresFullAccess: cursorRequestDeclaresFullAccess(activeRequest),
|
|
218
226
|
sessionId: activeRequest.conversationId,
|
|
227
|
+
streamHeartbeatOnlyFailMs: heartbeatOnlyMs,
|
|
219
228
|
...(incoming.providerFetch ? { fetch: incoming.providerFetch } : {}),
|
|
220
229
|
},
|
|
221
230
|
activeRequest,
|
|
@@ -38,9 +38,9 @@ const REPLAY_TTL_MS = 60 * 60 * 1000; // 1h
|
|
|
38
38
|
export const ANTIGRAVITY_REPLAY_MAX_ENTRIES = 10_240;
|
|
39
39
|
const REPLAY_EVICT_BATCH = 128;
|
|
40
40
|
const REPLAY_MAX_CALLS_PER_SESSION = 256;
|
|
41
|
-
export const ANTIGRAVITY_REPLAY_MAX_BYTES_PER_SESSION =
|
|
41
|
+
export const ANTIGRAVITY_REPLAY_MAX_BYTES_PER_SESSION = 8 * 1024 * 1024;
|
|
42
42
|
export const ANTIGRAVITY_REPLAY_MAX_TOTAL_BYTES = 64 * 1024 * 1024;
|
|
43
|
-
const REPLAY_MAX_SIGNATURE_BYTES =
|
|
43
|
+
const REPLAY_MAX_SIGNATURE_BYTES = 1024 * 1024;
|
|
44
44
|
/** Fixed 64-hex outer key length, counted once per session entry. */
|
|
45
45
|
const REPLAY_SESSION_KEY_BYTES = 64;
|
|
46
46
|
const REPLAY_SNAPSHOT_FILE = "antigravity-replay.json";
|
|
@@ -11,6 +11,13 @@ import { antigravityUserAgent } from "./client-fingerprint";
|
|
|
11
11
|
*/
|
|
12
12
|
export const ANTIGRAVITY_REQUEST_UA = antigravityUserAgent();
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Bypass sentinel for Google Cloud Code Assist (Antigravity).
|
|
16
|
+
* When a historical functionCall part lacks a thought_signature, Antigravity rejects
|
|
17
|
+
* the request with HTTP 400 unless this sentinel is provided.
|
|
18
|
+
*/
|
|
19
|
+
export const ANTIGRAVITY_SIGNATURE_BYPASS_SENTINEL = "skip_thought_signature_validator";
|
|
20
|
+
|
|
14
21
|
/**
|
|
15
22
|
* Whether a stored `OcxToolCall.thoughtSignature` is a REAL upstream Gemini signature versus a
|
|
16
23
|
* foreign id that must not be forwarded to Gemini/Antigravity.
|
|
@@ -2,7 +2,10 @@ import { parseUpstreamJsonPayload, safeUpstreamErrorString, sanitizeUpstreamErro
|
|
|
2
2
|
|
|
3
3
|
/** Pull the human detail out of the Google API error envelope `{error:{message,status,code}}`. */
|
|
4
4
|
function googleErrorDetail(payloadText: string): { message?: string; status?: string } {
|
|
5
|
-
|
|
5
|
+
let trimmed = payloadText.trim();
|
|
6
|
+
if (trimmed.startsWith("data:")) {
|
|
7
|
+
trimmed = trimmed.replace(/^data:\s*/, "").trim();
|
|
8
|
+
}
|
|
6
9
|
if (!trimmed || (!trimmed.startsWith("{") && !trimmed.startsWith("["))) {
|
|
7
10
|
return { message: trimmed || undefined };
|
|
8
11
|
}
|
|
@@ -18,7 +21,8 @@ function googleErrorDetail(payloadText: string): { message?: string; status?: st
|
|
|
18
21
|
const ANTIGRAVITY_GEO_BLOCKED_MARKER = "user location is not supported for the api use";
|
|
19
22
|
|
|
20
23
|
export function isAntigravityGeoBlockedBody(payloadText: string): boolean {
|
|
21
|
-
|
|
24
|
+
const lower = payloadText.toLowerCase();
|
|
25
|
+
return lower.includes(ANTIGRAVITY_GEO_BLOCKED_MARKER) || lower.includes("location is not supported");
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
function classifyGoogle(label: string, status: number | undefined, enumStatus: string | undefined, text: string): string {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./google-errors";
|
|
8
8
|
import { isGoogleMixedBuiltinToolError, repairGoogleInvalidRequestBody, stripGoogleBuiltinToolsFromWireBody } from "./google-wire-compiler";
|
|
9
9
|
import { normalizeUpstreamHttpErrorResponse, readDisplaySafeErrorPayloadText } from "./upstream-http-error";
|
|
10
|
-
import { recordAntigravityCooldown } from "../oauth/antigravity-routing";
|
|
10
|
+
import { recordAntigravityCooldown, recordAntigravitySyntheticFailure } from "../oauth/antigravity-routing";
|
|
11
11
|
import {
|
|
12
12
|
antigravityHostCandidates,
|
|
13
13
|
canonicalAntigravityHttpsHost,
|
|
@@ -178,6 +178,7 @@ function responseWithBufferedBody(
|
|
|
178
178
|
async function prepareCcaSseResponse(
|
|
179
179
|
response: Response,
|
|
180
180
|
fetchPeer: (() => Promise<Response>) | undefined,
|
|
181
|
+
accountId?: string,
|
|
181
182
|
): Promise<Response> {
|
|
182
183
|
if (!response.body) return fetchPeer ? fetchPeer() : response;
|
|
183
184
|
const reader = response.body.getReader();
|
|
@@ -209,6 +210,13 @@ async function prepareCcaSseResponse(
|
|
|
209
210
|
return failoverOrPassthrough();
|
|
210
211
|
}
|
|
211
212
|
if (probe === "quota_exhausted" || probe === "geo_blocked") {
|
|
213
|
+
if (accountId) {
|
|
214
|
+
recordAntigravitySyntheticFailure(accountId, {
|
|
215
|
+
code: probe === "quota_exhausted" ? 429 : 403,
|
|
216
|
+
status: probe === "quota_exhausted" ? "RESOURCE_EXHAUSTED" : "PERMISSION_DENIED",
|
|
217
|
+
message: probe === "quota_exhausted" ? "quota exceeded" : "user location is not supported",
|
|
218
|
+
});
|
|
219
|
+
}
|
|
212
220
|
const status = probe === "quota_exhausted" ? 429 : 403;
|
|
213
221
|
return passthrough(undefined, status);
|
|
214
222
|
}
|
|
@@ -237,6 +245,13 @@ async function prepareCcaSseResponse(
|
|
|
237
245
|
return failoverOrPassthrough();
|
|
238
246
|
}
|
|
239
247
|
if (probe === "quota_exhausted" || probe === "geo_blocked") {
|
|
248
|
+
if (accountId) {
|
|
249
|
+
recordAntigravitySyntheticFailure(accountId, {
|
|
250
|
+
code: probe === "quota_exhausted" ? 429 : 403,
|
|
251
|
+
status: probe === "quota_exhausted" ? "RESOURCE_EXHAUSTED" : "PERMISSION_DENIED",
|
|
252
|
+
message: probe === "quota_exhausted" ? "quota exceeded" : "user location is not supported",
|
|
253
|
+
});
|
|
254
|
+
}
|
|
240
255
|
const status = probe === "quota_exhausted" ? 429 : 403;
|
|
241
256
|
return passthrough(overflow, status);
|
|
242
257
|
}
|
|
@@ -262,6 +277,8 @@ function isUnavailableResponse(response: Response): boolean {
|
|
|
262
277
|
export interface GoogleRetryOptions {
|
|
263
278
|
/** Repair-and-replay structurally invalid 400 bodies (Vertex/Antigravity behavior). */
|
|
264
279
|
repairInvalid400?: boolean;
|
|
280
|
+
/** Let the Responses layer own Antigravity's single same-account 429 replay. */
|
|
281
|
+
retry429?: boolean;
|
|
265
282
|
}
|
|
266
283
|
|
|
267
284
|
async function normalizeFinalGoogleError(label: string, res: Response, signal?: AbortSignal): Promise<Response> {
|
|
@@ -291,13 +308,15 @@ async function recordAntigravityHttpCooldown(
|
|
|
291
308
|
if (response.status === 429) {
|
|
292
309
|
recordAntigravityCooldown(
|
|
293
310
|
accountId,
|
|
294
|
-
|
|
295
|
-
|
|
311
|
+
response.headers.get("retry-after"),
|
|
312
|
+
Date.now(),
|
|
313
|
+
isQuotaExhaustedBody(payloadText) ? "quota" : "rate-limit",
|
|
314
|
+
"synthetic",
|
|
296
315
|
);
|
|
297
316
|
return true;
|
|
298
317
|
}
|
|
299
|
-
if (isAntigravityGeoBlockedBody(payloadText)) {
|
|
300
|
-
recordAntigravityCooldown(accountId, "
|
|
318
|
+
if (response.status === 403 || isAntigravityGeoBlockedBody(payloadText)) {
|
|
319
|
+
recordAntigravityCooldown(accountId, response.headers.get("retry-after"), Date.now(), "geoblock", "synthetic");
|
|
301
320
|
return true;
|
|
302
321
|
}
|
|
303
322
|
return false;
|
|
@@ -318,6 +337,7 @@ async function fetchGoogleWithRetryInternal(
|
|
|
318
337
|
opts: GoogleRetryOptions = {},
|
|
319
338
|
): Promise<Response> {
|
|
320
339
|
const repairInvalid400 = opts.repairInvalid400 ?? true;
|
|
340
|
+
const retry429 = opts.retry429 ?? true;
|
|
321
341
|
const timeoutMs = ctx.timeoutMs ?? 200_000;
|
|
322
342
|
const executor = ctx.executor ?? globalThis.fetch;
|
|
323
343
|
let activeRequest = request;
|
|
@@ -369,7 +389,7 @@ async function fetchGoogleWithRetryInternal(
|
|
|
369
389
|
opts,
|
|
370
390
|
)
|
|
371
391
|
: undefined;
|
|
372
|
-
return prepareCcaSseResponse(res, fetchPeer);
|
|
392
|
+
return prepareCcaSseResponse(res, fetchPeer, ctx.accountId);
|
|
373
393
|
}
|
|
374
394
|
if (res.status === 400 && repairInvalid400 && !compatibilityReplayUsed) {
|
|
375
395
|
let payloadText = "";
|
|
@@ -397,6 +417,9 @@ async function fetchGoogleWithRetryInternal(
|
|
|
397
417
|
continue;
|
|
398
418
|
}
|
|
399
419
|
}
|
|
420
|
+
if (res.status === 429 && !retry429) {
|
|
421
|
+
return ctx.returnRawErrors ? res : normalizeFinalGoogleError(label, res, ctx.abortSignal);
|
|
422
|
+
}
|
|
400
423
|
if (!retryableGoogleStatus(res.status) || attempt === GOOGLE_RETRY_ATTEMPTS - 1) {
|
|
401
424
|
return ctx.returnRawErrors ? res : normalizeFinalGoogleError(label, res, ctx.abortSignal);
|
|
402
425
|
}
|
|
@@ -466,5 +489,5 @@ export function fetchVertexWithRetry(request: AdapterRequest, ctx: AdapterFetchC
|
|
|
466
489
|
|
|
467
490
|
/** Antigravity (Cloud Code Assist) retry wrapper. */
|
|
468
491
|
export function fetchAntigravityWithRetry(request: AdapterRequest, ctx: AdapterFetchContext = {}): Promise<Response> {
|
|
469
|
-
return fetchGoogleWithRetry("Antigravity", request, ctx);
|
|
492
|
+
return fetchGoogleWithRetry("Antigravity", request, ctx, { retry429: false });
|
|
470
493
|
}
|
|
@@ -12,6 +12,11 @@ export function vertexTruncationErrorMessage(reason?: string): string {
|
|
|
12
12
|
return `Vertex AI response truncated upstream before the turn completed${suffix}`;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
export function googleTruncationErrorMessage(reason?: string): string {
|
|
16
|
+
const suffix = reason ? ` (${redactSecretString(reason).slice(0, 160)})` : "";
|
|
17
|
+
return `Google AI Studio response truncated upstream before the turn completed${suffix}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
/**
|
|
16
21
|
* Whether a finished turn must fail closed. A truncation reason arriving mid tool call always
|
|
17
22
|
* does. MALFORMED_FUNCTION_CALL fails closed even with zero started calls: the malformed call
|
|
@@ -5,6 +5,15 @@ type JsonObject = Record<string, unknown>;
|
|
|
5
5
|
|
|
6
6
|
const GOOGLE_TOOL_NAME = /^[A-Za-z_][A-Za-z0-9_-]{0,63}$/;
|
|
7
7
|
const GOOGLE_THINKING_LEVELS = new Set(["minimal", "low", "medium", "high"]);
|
|
8
|
+
const GOOGLE_SAFETY_CATEGORIES = new Set([
|
|
9
|
+
"HARM_CATEGORY_HATE_SPEECH", "HARM_CATEGORY_SEXUALLY_EXPLICIT", "HARM_CATEGORY_DANGEROUS_CONTENT",
|
|
10
|
+
"HARM_CATEGORY_HARASSMENT", "HARM_CATEGORY_CIVIC_INTEGRITY", "HARM_CATEGORY_JAILBREAK",
|
|
11
|
+
]);
|
|
12
|
+
const GOOGLE_SAFETY_THRESHOLDS = new Set([
|
|
13
|
+
"HARM_BLOCK_THRESHOLD_UNSPECIFIED", "BLOCK_LOW_AND_ABOVE", "BLOCK_MEDIUM_AND_ABOVE",
|
|
14
|
+
"BLOCK_ONLY_HIGH", "BLOCK_NONE", "OFF",
|
|
15
|
+
]);
|
|
16
|
+
const GOOGLE_CACHED_CONTENT = /^(?:cachedContents\/[^/?#\s]+|projects\/[^/?#\s]+\/locations\/[^/?#\s]+\/cachedContents\/[^/?#\s]+)$/;
|
|
8
17
|
|
|
9
18
|
function isObject(value: unknown): value is JsonObject {
|
|
10
19
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -158,12 +167,18 @@ function compileGenerationConfig(value: unknown): JsonObject | undefined {
|
|
|
158
167
|
))].slice(0, 5);
|
|
159
168
|
if (stopSequences.length > 0) out.stopSequences = stopSequences;
|
|
160
169
|
}
|
|
161
|
-
if (isObject(value.thinkingConfig)
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (
|
|
170
|
+
if (isObject(value.thinkingConfig)) {
|
|
171
|
+
const config: JsonObject = {};
|
|
172
|
+
if (typeof value.thinkingConfig.thinkingBudget === "number"
|
|
173
|
+
&& Number.isSafeInteger(value.thinkingConfig.thinkingBudget)
|
|
174
|
+
&& value.thinkingConfig.thinkingBudget >= -1) config.thinkingBudget = value.thinkingConfig.thinkingBudget;
|
|
175
|
+
if (typeof value.thinkingConfig.includeThoughts === "boolean") config.includeThoughts = value.thinkingConfig.includeThoughts;
|
|
176
|
+
if (typeof value.thinkingConfig.thinkingLevel === "string") {
|
|
177
|
+
const raw = value.thinkingConfig.thinkingLevel.toLowerCase();
|
|
178
|
+
const thinkingLevel = GOOGLE_THINKING_LEVELS.has(raw) ? raw : (["xhigh", "max", "ultra"].includes(raw) ? "high" : undefined);
|
|
179
|
+
if (thinkingLevel && config.thinkingBudget === undefined) config.thinkingLevel = thinkingLevel;
|
|
180
|
+
}
|
|
181
|
+
if (Object.keys(config).length > 0) out.thinkingConfig = config;
|
|
167
182
|
}
|
|
168
183
|
if (Array.isArray(value.responseModalities)) {
|
|
169
184
|
const valid = value.responseModalities.filter((m): m is string => typeof m === "string" && ["TEXT", "IMAGE", "AUDIO"].includes(m));
|
|
@@ -180,6 +195,20 @@ function compileGenerationConfig(value: unknown): JsonObject | undefined {
|
|
|
180
195
|
return Object.keys(out).length > 0 ? out : undefined;
|
|
181
196
|
}
|
|
182
197
|
|
|
198
|
+
function compileSafetySettings(value: unknown): unknown[] | undefined {
|
|
199
|
+
if (!Array.isArray(value) || value.length > 16) return undefined;
|
|
200
|
+
const seen = new Set<string>();
|
|
201
|
+
const out: JsonObject[] = [];
|
|
202
|
+
for (const setting of value) {
|
|
203
|
+
if (!isObject(setting) || typeof setting.category !== "string" || !GOOGLE_SAFETY_CATEGORIES.has(setting.category)
|
|
204
|
+
|| typeof setting.threshold !== "string" || !GOOGLE_SAFETY_THRESHOLDS.has(setting.threshold)
|
|
205
|
+
|| seen.has(setting.category)) return undefined;
|
|
206
|
+
seen.add(setting.category);
|
|
207
|
+
out.push({ category: setting.category, threshold: setting.threshold });
|
|
208
|
+
}
|
|
209
|
+
return out.length > 0 ? out : undefined;
|
|
210
|
+
}
|
|
211
|
+
|
|
183
212
|
function compileToolConfig(value: unknown, toWireName: (name: string) => string): JsonObject | undefined {
|
|
184
213
|
if (!isObject(value) || !isObject(value.functionCallingConfig)) return undefined;
|
|
185
214
|
const raw = value.functionCallingConfig;
|
|
@@ -216,6 +245,9 @@ export function compileGoogleWireBody(input: unknown): {
|
|
|
216
245
|
if (generationConfig) body.generationConfig = generationConfig;
|
|
217
246
|
const toolConfig = compileToolConfig(source.toolConfig, names.toWire);
|
|
218
247
|
if (toolConfig) body.toolConfig = toolConfig;
|
|
248
|
+
const safetySettings = compileSafetySettings(source.safetySettings);
|
|
249
|
+
if (safetySettings) body.safetySettings = safetySettings;
|
|
250
|
+
if (typeof source.cachedContent === "string" && GOOGLE_CACHED_CONTENT.test(source.cachedContent)) body.cachedContent = source.cachedContent;
|
|
219
251
|
if (typeof source.sessionId === "string" && source.sessionId.length > 0) body.sessionId = source.sessionId;
|
|
220
252
|
return { body, restoreToolName: names.fromWire };
|
|
221
253
|
}
|