Refactor proxy-core surfaces and transformer boundaries (#163)

* refactor: add canonical request contracts

* test: harden transformer boundary contracts

* refactor: adapt protocol transformers to canonical contract

* refactor: add cli profile registry

* refactor: extract provider profiles

* refactor: add conductor and provider executors

* refactor: add models surface

* refactor: migrate responses surface

* refactor: migrate chat surface

* refactor: migrate gemini surface

* refactor: migrate file surfaces

* test: align runtime executor undici mock

* fix: preserve compact SSE closeout payloads

* feat: support all-api-hub v2 backup imports

* fix: aggregate codex oauth SSE final payloads

* fix: harden responses SSE failure handling
This commit is contained in:
Cita
2026-03-19 16:07:56 +08:00
committed by GitHub
parent c0c993f448
commit 24483c28eb
75 changed files with 8333 additions and 3574 deletions
@@ -0,0 +1,212 @@
import { createHash, randomUUID } from 'node:crypto';
import { Response } from 'undici';
import type { RuntimeDispatchInput, RuntimeExecutor, RuntimeResponse } from './types.js';
import {
asTrimmedString,
materializeErrorResponse,
performFetch,
withRequestBody,
} from './types.js';
const ANTIGRAVITY_RUNTIME_BASE_URLS = [
'https://daily-cloudcode-pa.googleapis.com',
'https://daily-cloudcode-pa.sandbox.googleapis.com',
] as const;
function antigravityRequestType(modelName: string): 'image_gen' | 'agent' {
return modelName.includes('image') ? 'image_gen' : 'agent';
}
function generateAntigravityProjectId(): string {
const adjectives = ['useful', 'bright', 'swift', 'calm', 'bold'];
const nouns = ['signal', 'river', 'rocket', 'forest', 'bridge'];
const adjective = adjectives[Math.floor(Math.random() * adjectives.length)] || 'useful';
const noun = nouns[Math.floor(Math.random() * nouns.length)] || 'signal';
const suffix = Math.floor(100000 + Math.random() * 900000);
return `${adjective}-${noun}-${suffix}`;
}
function extractFirstUserText(value: unknown): string {
if (!Array.isArray(value)) return '';
for (const content of value) {
if (!content || typeof content !== 'object' || Array.isArray(content)) continue;
const record = content as Record<string, unknown>;
if (asTrimmedString(record.role) !== 'user') continue;
const parts = Array.isArray(record.parts) ? record.parts : [];
for (const part of parts) {
if (!part || typeof part !== 'object' || Array.isArray(part)) continue;
const text = asTrimmedString((part as Record<string, unknown>).text);
if (text) return text;
}
}
return '';
}
function generateStableAntigravitySessionId(payload: Record<string, unknown>): string {
const firstUserText = extractFirstUserText(
payload.request && typeof payload.request === 'object' && !Array.isArray(payload.request)
? (payload.request as Record<string, unknown>).contents
: undefined,
);
if (!firstUserText) {
return `-${BigInt(`0x${randomUUID().replace(/-/g, '').slice(0, 16)}`).toString()}`;
}
const digest = createHash('sha256').update(firstUserText).digest('hex').slice(0, 16);
const bigint = BigInt(`0x${digest}`) & BigInt('0x7fffffffffffffff');
return `-${bigint.toString()}`;
}
function renameParametersJsonSchema(value: unknown): unknown {
if (Array.isArray(value)) {
return value.map((item) => renameParametersJsonSchema(item));
}
if (!value || typeof value !== 'object') return value;
const input = value as Record<string, unknown>;
const output: Record<string, unknown> = {};
for (const [key, entry] of Object.entries(input)) {
const nextKey = key === 'parametersJsonSchema' ? 'parameters' : key;
output[nextKey] = renameParametersJsonSchema(entry);
}
return output;
}
function deleteNestedMaxOutputTokens(payload: Record<string, unknown>): void {
const request = payload.request;
if (!request || typeof request !== 'object' || Array.isArray(request)) return;
const generationConfig = (request as Record<string, unknown>).generationConfig;
if (!generationConfig || typeof generationConfig !== 'object' || Array.isArray(generationConfig)) return;
delete (generationConfig as Record<string, unknown>).maxOutputTokens;
}
function buildAntigravityRuntimeBody(
originalBody: Record<string, unknown>,
modelName: string,
action?: NonNullable<RuntimeDispatchInput['request']['runtime']>['action'],
): Record<string, unknown> {
const payload = renameParametersJsonSchema(structuredClone(originalBody)) as Record<string, unknown>;
if (action === 'countTokens') {
return payload;
}
const requestType = antigravityRequestType(modelName);
const projectId = asTrimmedString(payload.project) || generateAntigravityProjectId();
payload.model = modelName;
payload.project = projectId;
payload.userAgent = 'antigravity';
payload.requestType = requestType;
payload.requestId = requestType === 'image_gen'
? `image_gen/${Date.now()}/${randomUUID()}/12`
: `agent-${randomUUID()}`;
const request = payload.request;
if (request && typeof request === 'object' && !Array.isArray(request)) {
delete (request as Record<string, unknown>).safetySettings;
if (requestType !== 'image_gen') {
(request as Record<string, unknown>).sessionId = generateStableAntigravitySessionId(payload);
}
if (modelName.includes('claude')) {
const toolConfig = (
(request as Record<string, unknown>).toolConfig
&& typeof (request as Record<string, unknown>).toolConfig === 'object'
&& !Array.isArray((request as Record<string, unknown>).toolConfig)
)
? (request as Record<string, unknown>).toolConfig as Record<string, unknown>
: (((request as Record<string, unknown>).toolConfig = {}) as Record<string, unknown>);
toolConfig.functionCallingConfig = { mode: 'VALIDATED' };
} else {
deleteNestedMaxOutputTokens(payload);
}
}
return payload;
}
function antigravityShouldRetryNoCapacity(
status: number,
responseText: string,
): boolean {
return status === 503 && responseText.toLowerCase().includes('no capacity available');
}
function antigravityNoCapacityRetryDelay(attempt: number): number {
return Math.min((attempt + 1) * 250, 2000);
}
async function waitMs(ms: number): Promise<void> {
if (ms <= 0) return;
await new Promise((resolve) => setTimeout(resolve, ms));
}
export const antigravityExecutor: RuntimeExecutor = {
async dispatch(input: RuntimeDispatchInput) {
const modelName = asTrimmedString(input.request.runtime?.modelName) || asTrimmedString(input.request.body.model);
const runtimeBody = buildAntigravityRuntimeBody(
input.request.body,
modelName,
input.request.runtime?.action,
);
const baseAttempts = 3;
let lastResponse: RuntimeResponse | null = null;
attemptLoop:
for (let attempt = 0; attempt < baseAttempts; attempt += 1) {
for (const baseUrl of ANTIGRAVITY_RUNTIME_BASE_URLS) {
const requestUrl = `${baseUrl}${input.request.path}`;
const minimalHeaders: Record<string, string> = {
Authorization: input.request.headers.Authorization || input.request.headers.authorization || '',
'Content-Type': 'application/json',
Accept: input.request.runtime?.stream ? 'text/event-stream' : 'application/json',
'User-Agent': 'antigravity/1.19.6 darwin/arm64',
};
let response: RuntimeResponse;
try {
response = await performFetch(
input,
withRequestBody(input.request, runtimeBody, minimalHeaders),
requestUrl,
);
} catch (error) {
if (baseUrl !== ANTIGRAVITY_RUNTIME_BASE_URLS[ANTIGRAVITY_RUNTIME_BASE_URLS.length - 1]) {
continue;
}
if (attempt + 1 < baseAttempts) {
continue attemptLoop;
}
throw error;
}
if (response.ok) return response;
const errorResponse = await materializeErrorResponse(response);
const errorText = await errorResponse.text().catch(() => '');
lastResponse = new Response(errorText, {
status: errorResponse.status,
headers: errorResponse.headers,
});
if (errorResponse.status === 429) {
continue;
}
if (antigravityShouldRetryNoCapacity(errorResponse.status, errorText)) {
if (baseUrl !== ANTIGRAVITY_RUNTIME_BASE_URLS[ANTIGRAVITY_RUNTIME_BASE_URLS.length - 1]) {
continue;
}
if (attempt + 1 < baseAttempts) {
await waitMs(antigravityNoCapacityRetryDelay(attempt));
continue attemptLoop;
}
}
return lastResponse;
}
}
return lastResponse || performFetch(input, withRequestBody(input.request, runtimeBody, {
Authorization: input.request.headers.Authorization || input.request.headers.authorization || '',
'Content-Type': 'application/json',
Accept: input.request.runtime?.stream ? 'text/event-stream' : 'application/json',
'User-Agent': 'antigravity/1.19.6 darwin/arm64',
}));
},
};
@@ -0,0 +1,8 @@
import type { RuntimeDispatchInput, RuntimeExecutor } from './types.js';
import { performFetch } from './types.js';
export const claudeExecutor: RuntimeExecutor = {
async dispatch(input: RuntimeDispatchInput) {
return performFetch(input, input.request);
},
};
@@ -0,0 +1,8 @@
import type { RuntimeDispatchInput, RuntimeExecutor } from './types.js';
import { performFetch } from './types.js';
export const codexExecutor: RuntimeExecutor = {
async dispatch(input: RuntimeDispatchInput) {
return performFetch(input, input.request);
},
};
@@ -0,0 +1,60 @@
import type { RuntimeDispatchInput, RuntimeExecutor, RuntimeResponse } from './types.js';
import {
asTrimmedString,
materializeErrorResponse,
performFetch,
withRequestBody,
} from './types.js';
function replaceGeminiCliModelInUserAgent(userAgent: string | undefined, modelName: string): string | undefined {
const raw = asTrimmedString(userAgent);
if (!raw) return undefined;
return raw.replace(/^GeminiCLI\/([^/]+)\/[^ ]+ /i, `GeminiCLI/$1/${modelName} `);
}
function buildGeminiCliAttemptRequest(
request: RuntimeDispatchInput['request'],
modelName: string,
) {
const body = structuredClone(request.body);
const action = request.runtime?.action;
if (action === 'countTokens') {
delete body.model;
delete body.project;
} else {
body.model = modelName;
}
const headers = { ...request.headers };
const nextUserAgent = replaceGeminiCliModelInUserAgent(
headers['User-Agent'] || headers['user-agent'],
modelName,
);
if (nextUserAgent) {
headers['User-Agent'] = nextUserAgent;
delete headers['user-agent'];
}
return withRequestBody(request, body, headers);
}
export const geminiCliExecutor: RuntimeExecutor = {
async dispatch(input: RuntimeDispatchInput) {
const baseModel = asTrimmedString(input.request.runtime?.modelName) || asTrimmedString(input.request.body.model);
const models = [baseModel].filter(Boolean);
let lastResponse: RuntimeResponse | null = null;
for (const modelName of models.length > 0 ? models : [baseModel || 'unknown']) {
const attemptRequest = buildGeminiCliAttemptRequest(input.request, modelName);
const response = await performFetch(input, attemptRequest);
if (response.ok) return response;
if (response.status === 429) {
lastResponse = await materializeErrorResponse(response);
continue;
}
return materializeErrorResponse(response);
}
return lastResponse || performFetch(input, input.request);
},
};
+75
View File
@@ -0,0 +1,75 @@
import {
Response,
fetch,
type RequestInit as UndiciRequestInit,
type Response as UndiciResponse,
} from 'undici';
export type ProxyRuntimeRequest = {
endpoint: 'chat' | 'messages' | 'responses';
path: string;
headers: Record<string, string>;
body: Record<string, unknown>;
runtime?: {
executor: 'default' | 'codex' | 'gemini-cli' | 'antigravity' | 'claude';
modelName?: string;
stream?: boolean;
oauthProjectId?: string | null;
action?: 'generateContent' | 'streamGenerateContent' | 'countTokens';
};
};
export type RuntimeDispatchInput = {
siteUrl: string;
request: ProxyRuntimeRequest;
targetUrl?: string;
buildInit: (requestUrl: string, request: ProxyRuntimeRequest) => Promise<UndiciRequestInit> | UndiciRequestInit;
};
export type RuntimeResponse = UndiciResponse;
export type RuntimeExecutor = {
dispatch(input: RuntimeDispatchInput): Promise<RuntimeResponse>;
};
export function asTrimmedString(value: unknown): string {
return typeof value === 'string' ? value.trim() : '';
}
export function withRequestBody(
request: ProxyRuntimeRequest,
body: Record<string, unknown>,
headers?: Record<string, string>,
): ProxyRuntimeRequest {
return {
...request,
headers: headers ? { ...headers } : { ...request.headers },
body,
};
}
function buildUpstreamUrl(siteUrl: string, path: string): string {
const normalizedBase = siteUrl.replace(/\/+$/, '');
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
return `${normalizedBase}${normalizedPath}`;
}
export async function performFetch(
input: RuntimeDispatchInput,
request: ProxyRuntimeRequest,
requestUrl = input.targetUrl || buildUpstreamUrl(input.siteUrl, request.path),
): Promise<RuntimeResponse> {
const init = await input.buildInit(requestUrl, request);
return fetch(requestUrl, init);
}
export async function materializeErrorResponse(
response: RuntimeResponse,
): Promise<RuntimeResponse> {
if (response.ok) return response;
const text = await response.text().catch(() => '');
return new Response(text, {
status: response.status,
headers: response.headers,
});
}