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,47 @@
import type { PreparedProviderRequest, PrepareProviderRequestInput, ProviderAction, ProviderProfile } from './types.js';
const ANTIGRAVITY_RUNTIME_USER_AGENT = 'antigravity/1.19.6 darwin/arm64';
function asTrimmedString(value: unknown): string {
return typeof value === 'string' ? value.trim() : '';
}
function resolveAction(action: ProviderAction | undefined, stream: boolean): ProviderAction {
if (action) return action;
return stream ? 'streamGenerateContent' : 'generateContent';
}
function resolvePath(action: ProviderAction): string {
if (action === 'countTokens') return '/v1internal:countTokens';
if (action === 'streamGenerateContent') return '/v1internal:streamGenerateContent?alt=sse';
return '/v1internal:generateContent';
}
export const antigravityProviderProfile: ProviderProfile = {
id: 'antigravity',
prepareRequest(input: PrepareProviderRequestInput): PreparedProviderRequest {
const action = resolveAction(input.action, input.stream);
const projectId = asTrimmedString(input.oauthProjectId);
return {
path: resolvePath(action),
headers: {
Authorization: input.baseHeaders.Authorization,
'Content-Type': 'application/json',
Accept: action === 'streamGenerateContent' ? 'text/event-stream' : 'application/json',
'User-Agent': ANTIGRAVITY_RUNTIME_USER_AGENT,
},
body: {
project: projectId,
model: input.modelName,
request: input.body,
},
runtime: {
executor: 'antigravity',
modelName: input.modelName,
stream: action === 'streamGenerateContent',
oauthProjectId: projectId,
action,
},
};
},
};
@@ -0,0 +1,128 @@
import type { PreparedProviderRequest, PrepareProviderRequestInput, ProviderProfile } from './types.js';
const CLAUDE_DEFAULT_USER_AGENT = 'claude-cli/2.1.63 (external, cli)';
const CLAUDE_DEFAULT_BETA_HEADER = 'claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05';
function headerValueToString(value: unknown): string | null {
if (typeof value === 'string') {
const trimmed = value.trim();
return trimmed || null;
}
if (Array.isArray(value)) {
for (const item of value) {
if (typeof item !== 'string') continue;
const trimmed = item.trim();
if (trimmed) return trimmed;
}
}
return null;
}
function getInputHeader(
headers: Record<string, unknown> | Record<string, string> | undefined,
key: string,
): string | null {
if (!headers) return null;
for (const [candidateKey, candidateValue] of Object.entries(headers)) {
if (candidateKey.toLowerCase() !== key.toLowerCase()) continue;
return headerValueToString(candidateValue);
}
return null;
}
function mergeClaudeBetaHeader(
explicitValue: string | null,
extraBetas: string[] = [],
): string {
const source = explicitValue || CLAUDE_DEFAULT_BETA_HEADER;
const seen = new Set<string>();
const merged: string[] = [];
for (const entry of source.split(',')) {
const normalized = entry.trim();
if (!normalized || seen.has(normalized)) continue;
seen.add(normalized);
merged.push(normalized);
}
if (!explicitValue) {
for (const entry of extraBetas) {
const normalized = entry.trim();
if (!normalized || seen.has(normalized)) continue;
seen.add(normalized);
merged.push(normalized);
}
}
return merged.join(',');
}
function buildClaudeRuntimeHeaders(input: {
baseHeaders: Record<string, string>;
claudeHeaders: Record<string, string>;
anthropicVersion: string;
stream: boolean;
isClaudeOauthUpstream: boolean;
tokenValue: string;
}): Record<string, string> {
const anthropicBeta = mergeClaudeBetaHeader(
getInputHeader(input.claudeHeaders, 'anthropic-beta'),
);
const headers: Record<string, string> = {
...input.baseHeaders,
...input.claudeHeaders,
'anthropic-version': input.anthropicVersion,
...(anthropicBeta ? { 'anthropic-beta': anthropicBeta } : {}),
'Anthropic-Dangerous-Direct-Browser-Access': 'true',
'X-App': 'cli',
'X-Stainless-Retry-Count': getInputHeader(input.claudeHeaders, 'x-stainless-retry-count') || '0',
'X-Stainless-Runtime-Version': getInputHeader(input.claudeHeaders, 'x-stainless-runtime-version') || 'v24.3.0',
'X-Stainless-Package-Version': getInputHeader(input.claudeHeaders, 'x-stainless-package-version') || '0.74.0',
'X-Stainless-Runtime': getInputHeader(input.claudeHeaders, 'x-stainless-runtime') || 'node',
'X-Stainless-Lang': getInputHeader(input.claudeHeaders, 'x-stainless-lang') || 'js',
'X-Stainless-Arch': getInputHeader(input.claudeHeaders, 'x-stainless-arch') || 'x64',
'X-Stainless-Os': getInputHeader(input.claudeHeaders, 'x-stainless-os') || 'Windows',
'X-Stainless-Timeout': getInputHeader(input.claudeHeaders, 'x-stainless-timeout') || '600',
'User-Agent': getInputHeader(input.claudeHeaders, 'user-agent') || CLAUDE_DEFAULT_USER_AGENT,
Connection: 'keep-alive',
Accept: input.stream ? 'text/event-stream' : 'application/json',
'Accept-Encoding': input.stream ? 'identity' : 'gzip, deflate, br, zstd',
};
if (input.isClaudeOauthUpstream) {
headers.Authorization = `Bearer ${input.tokenValue}`;
} else {
headers['x-api-key'] = input.tokenValue;
}
return headers;
}
export const claudeProviderProfile: ProviderProfile = {
id: 'claude',
prepareRequest(input: PrepareProviderRequestInput): PreparedProviderRequest {
const anthropicVersion = (
input.claudeHeaders?.['anthropic-version']
|| input.baseHeaders['anthropic-version']
|| '2023-06-01'
);
const isClaudeOauthUpstream = input.sitePlatform?.trim().toLowerCase() === 'claude'
&& input.oauthProvider === 'claude';
const isCountTokens = input.action === 'countTokens';
return {
path: isCountTokens ? '/v1/messages/count_tokens?beta=true' : '/v1/messages',
headers: buildClaudeRuntimeHeaders({
baseHeaders: input.baseHeaders,
claudeHeaders: input.claudeHeaders ?? {},
anthropicVersion,
stream: isCountTokens ? false : input.stream,
isClaudeOauthUpstream,
tokenValue: input.tokenValue,
}),
body: input.body,
runtime: {
executor: 'claude',
modelName: input.modelName,
stream: isCountTokens ? false : input.stream,
oauthProjectId: null,
...(isCountTokens ? { action: 'countTokens' } : {}),
},
};
},
};
@@ -0,0 +1,131 @@
import { createHash, randomUUID } from 'node:crypto';
import type { PreparedProviderRequest, PrepareProviderRequestInput, ProviderProfile } from './types.js';
const CODEX_CLIENT_VERSION = '0.101.0';
const CODEX_DEFAULT_USER_AGENT = 'codex_cli_rs/0.101.0 (Mac OS 26.0.1; arm64) Apple_Terminal/464';
function asTrimmedString(value: unknown): string {
return typeof value === 'string' ? value.trim() : '';
}
function headerValueToString(value: unknown): string | null {
if (typeof value === 'string') {
const trimmed = value.trim();
return trimmed || null;
}
if (Array.isArray(value)) {
for (const item of value) {
if (typeof item !== 'string') continue;
const trimmed = item.trim();
if (trimmed) return trimmed;
}
}
return null;
}
function getInputHeader(
headers: Record<string, unknown> | Record<string, string> | undefined,
key: string,
): string | null {
if (!headers) return null;
for (const [candidateKey, candidateValue] of Object.entries(headers)) {
if (candidateKey.toLowerCase() !== key.toLowerCase()) continue;
return headerValueToString(candidateValue);
}
return null;
}
function uuidFromSeed(seed: string): string {
const hash = createHash('sha1').update(seed).digest();
const bytes = new Uint8Array(hash.subarray(0, 16));
bytes[6] = (bytes[6]! & 0x0f) | 0x50;
bytes[8] = (bytes[8]! & 0x3f) | 0x80;
const hex = Array.from(bytes, (value) => value.toString(16).padStart(2, '0')).join('');
return [
hex.slice(0, 8),
hex.slice(8, 12),
hex.slice(12, 16),
hex.slice(16, 20),
hex.slice(20, 32),
].join('-');
}
function buildCodexRuntimeHeaders(input: {
baseHeaders: Record<string, string>;
providerHeaders?: Record<string, string>;
explicitSessionId?: string | null;
continuityKey?: string | null;
}): Record<string, string> {
const authorization = (
getInputHeader(input.baseHeaders, 'authorization')
|| getInputHeader(input.baseHeaders, 'Authorization')
|| ''
);
const originator = getInputHeader(input.providerHeaders, 'originator') || 'codex_cli_rs';
const accountId = getInputHeader(input.providerHeaders, 'chatgpt-account-id');
const version = getInputHeader(input.baseHeaders, 'version') || CODEX_CLIENT_VERSION;
const userAgent = getInputHeader(input.baseHeaders, 'user-agent') || CODEX_DEFAULT_USER_AGENT;
const explicitSessionId = asTrimmedString(input.explicitSessionId);
const continuityKey = asTrimmedString(input.continuityKey);
const sessionId = (
getInputHeader(input.baseHeaders, 'session_id')
|| getInputHeader(input.baseHeaders, 'session-id')
|| explicitSessionId
|| (continuityKey ? uuidFromSeed(`metapi:codex:${continuityKey}`) : null)
|| randomUUID()
);
const conversationId = (
getInputHeader(input.baseHeaders, 'conversation_id')
|| getInputHeader(input.baseHeaders, 'conversation-id')
|| explicitSessionId
|| (continuityKey ? sessionId : null)
);
return {
Authorization: authorization,
'Content-Type': 'application/json',
...(accountId ? { 'Chatgpt-Account-Id': accountId } : {}),
Originator: originator,
Version: version,
Session_id: sessionId,
...(conversationId ? { Conversation_id: conversationId } : {}),
'User-Agent': userAgent,
Accept: 'text/event-stream',
Connection: 'Keep-Alive',
};
}
export const codexProviderProfile: ProviderProfile = {
id: 'codex',
prepareRequest(input: PrepareProviderRequestInput): PreparedProviderRequest {
const headers = buildCodexRuntimeHeaders({
baseHeaders: input.baseHeaders,
providerHeaders: input.providerHeaders,
explicitSessionId: asTrimmedString(input.codexExplicitSessionId) || null,
continuityKey: asTrimmedString(input.codexSessionCacheKey) || null,
});
const codexSessionId = getInputHeader(headers, 'session_id') || getInputHeader(headers, 'session-id');
const shouldInjectDerivedPromptCacheKey = !!codexSessionId
&& !asTrimmedString(input.body.prompt_cache_key)
&& !asTrimmedString(input.codexExplicitSessionId)
&& !!asTrimmedString(input.codexSessionCacheKey);
const body = shouldInjectDerivedPromptCacheKey
? {
...input.body,
prompt_cache_key: codexSessionId,
}
: input.body;
return {
path: '/responses',
headers,
body,
runtime: {
executor: 'codex',
modelName: input.modelName,
stream: input.stream,
oauthProjectId: asTrimmedString(input.oauthProjectId) || null,
},
};
},
};
@@ -0,0 +1,113 @@
import type { PreparedProviderRequest, PrepareProviderRequestInput, ProviderAction, ProviderProfile } from './types.js';
function asTrimmedString(value: unknown): string {
return typeof value === 'string' ? value.trim() : '';
}
function headerValueToString(value: unknown): string | null {
if (typeof value === 'string') {
const trimmed = value.trim();
return trimmed || null;
}
if (Array.isArray(value)) {
for (const item of value) {
if (typeof item !== 'string') continue;
const trimmed = item.trim();
if (trimmed) return trimmed;
}
}
return null;
}
function getInputHeader(
headers: Record<string, unknown> | Record<string, string> | undefined,
key: string,
): string | null {
if (!headers) return null;
for (const [candidateKey, candidateValue] of Object.entries(headers)) {
if (candidateKey.toLowerCase() !== key.toLowerCase()) continue;
return headerValueToString(candidateValue);
}
return null;
}
function parseGeminiCliUserAgentRuntime(userAgent: string | null): {
version: string;
platform: string;
arch: string;
} | null {
if (!userAgent) return null;
const match = /^GeminiCLI\/([^/]+)\/[^ ]+ \(([^;]+); ([^)]+)\)$/i.exec(userAgent.trim());
if (!match) return null;
return {
version: match[1] || '0.31.0',
platform: match[2] || 'win32',
arch: match[3] || 'x64',
};
}
function buildGeminiCLIUserAgent(modelName: string, existingUserAgent?: string | null): string {
const parsed = parseGeminiCliUserAgentRuntime(existingUserAgent ?? null);
const version = parsed?.version || '0.31.0';
const platform = parsed?.platform || 'win32';
const arch = parsed?.arch || 'x64';
const effectiveModel = asTrimmedString(modelName) || 'unknown';
return `GeminiCLI/${version}/${effectiveModel} (${platform}; ${arch})`;
}
function resolveAction(action: ProviderAction | undefined, stream: boolean): ProviderAction {
if (action) return action;
return stream ? 'streamGenerateContent' : 'generateContent';
}
function resolvePath(action: ProviderAction): string {
if (action === 'countTokens') return '/v1internal:countTokens';
if (action === 'streamGenerateContent') return '/v1internal:streamGenerateContent?alt=sse';
return '/v1internal:generateContent';
}
export const geminiCliProviderProfile: ProviderProfile = {
id: 'gemini-cli',
prepareRequest(input: PrepareProviderRequestInput): PreparedProviderRequest {
const projectId = asTrimmedString(input.oauthProjectId);
if (!projectId) {
throw new Error('gemini-cli oauth project id missing');
}
const action = resolveAction(input.action, input.stream);
const apiClient = (
getInputHeader(input.providerHeaders, 'x-goog-api-client')
|| getInputHeader(input.baseHeaders, 'x-goog-api-client')
);
const userAgent = buildGeminiCLIUserAgent(
input.modelName,
getInputHeader(input.providerHeaders, 'user-agent') || getInputHeader(input.baseHeaders, 'user-agent'),
);
const headers: Record<string, string> = {
Authorization: input.baseHeaders.Authorization,
'Content-Type': 'application/json',
'User-Agent': userAgent,
};
if (apiClient) {
headers['X-Goog-Api-Client'] = apiClient;
}
if (action === 'streamGenerateContent') {
headers.Accept = 'text/event-stream';
}
return {
path: resolvePath(action),
headers,
body: {
project: projectId,
model: input.modelName,
request: input.body,
},
runtime: {
executor: 'gemini-cli',
modelName: input.modelName,
stream: action === 'streamGenerateContent',
oauthProjectId: projectId,
action,
},
};
},
};
@@ -0,0 +1,181 @@
import { describe, expect, it } from 'vitest';
import { resolveProviderProfile } from './registry.js';
describe('resolveProviderProfile', () => {
it('builds codex provider requests with codex-specific path, headers, and runtime metadata', () => {
const profile = resolveProviderProfile('codex');
expect(profile?.id).toBe('codex');
const result = profile!.prepareRequest({
endpoint: 'responses',
modelName: 'gpt-5.2-codex',
stream: true,
tokenValue: 'oauth-access-token',
sitePlatform: 'codex',
baseHeaders: {
Authorization: 'Bearer oauth-access-token',
},
providerHeaders: {
Originator: 'codex_cli_rs',
'Chatgpt-Account-Id': 'chatgpt-account-123',
},
codexSessionCacheKey: 'gpt-5.2-codex:user-123',
body: {
model: 'gpt-5.2-codex',
stream: true,
store: false,
},
});
expect(result.path).toBe('/responses');
expect(result.headers.Authorization).toBe('Bearer oauth-access-token');
expect(result.headers.Originator).toBe('codex_cli_rs');
expect(result.headers['Chatgpt-Account-Id']).toBe('chatgpt-account-123');
expect(result.headers.Session_id).toMatch(/^[0-9a-f-]{36}$/i);
expect(result.headers.Conversation_id).toBe(result.headers.Session_id);
expect(result.runtime).toMatchObject({
executor: 'codex',
modelName: 'gpt-5.2-codex',
stream: true,
});
expect(result.body.prompt_cache_key).toBe(result.headers.Session_id);
});
it('builds claude provider requests without rebuilding protocol bodies', () => {
const profile = resolveProviderProfile('claude');
expect(profile?.id).toBe('claude');
const protocolBody = {
model: 'claude-opus-4-6',
max_tokens: 256,
messages: [{ role: 'user', content: 'hello' }],
};
const result = profile!.prepareRequest({
endpoint: 'messages',
modelName: 'claude-opus-4-6',
stream: false,
tokenValue: 'oauth-access-token',
oauthProvider: 'claude',
sitePlatform: 'claude',
baseHeaders: {
'Content-Type': 'application/json',
},
claudeHeaders: {},
body: protocolBody,
});
expect(result.path).toBe('/v1/messages');
expect(result.headers.Authorization).toBe('Bearer oauth-access-token');
expect(result.headers['x-api-key']).toBeUndefined();
expect(result.headers['anthropic-version']).toBe('2023-06-01');
expect(result.runtime).toMatchObject({
executor: 'claude',
modelName: 'claude-opus-4-6',
stream: false,
});
expect(result.body).toBe(protocolBody);
});
it('builds gemini-cli provider requests with wrapped runtime envelope and project validation', () => {
const profile = resolveProviderProfile('gemini-cli');
expect(profile?.id).toBe('gemini-cli');
const protocolBody = {
contents: [{ role: 'user', parts: [{ text: 'hello gemini cli' }] }],
};
const result = profile!.prepareRequest({
endpoint: 'chat',
modelName: 'gemini-2.5-pro',
stream: false,
tokenValue: 'oauth-access-token',
oauthProvider: 'gemini-cli',
oauthProjectId: 'project-demo',
sitePlatform: 'gemini-cli',
baseHeaders: {
Authorization: 'Bearer oauth-access-token',
},
providerHeaders: {
'User-Agent': 'GeminiCLI/0.31.0/unknown (win32; x64)',
'X-Goog-Api-Client': 'google-genai-sdk/1.41.0 gl-node/v22.19.0',
},
body: protocolBody,
});
expect(result.path).toBe('/v1internal:generateContent');
expect(result.headers.Authorization).toBe('Bearer oauth-access-token');
expect(result.headers['User-Agent']).toBe('GeminiCLI/0.31.0/gemini-2.5-pro (win32; x64)');
expect(result.headers['X-Goog-Api-Client']).toContain('google-genai-sdk/');
expect(result.runtime).toMatchObject({
executor: 'gemini-cli',
modelName: 'gemini-2.5-pro',
oauthProjectId: 'project-demo',
action: 'generateContent',
});
expect(result.body).toEqual({
project: 'project-demo',
model: 'gemini-2.5-pro',
request: protocolBody,
});
expect((result.body as Record<string, unknown>).request).toBe(protocolBody);
expect(() => profile!.prepareRequest({
endpoint: 'chat',
modelName: 'gemini-2.5-pro',
stream: false,
tokenValue: 'oauth-access-token',
oauthProvider: 'gemini-cli',
sitePlatform: 'gemini-cli',
baseHeaders: {
Authorization: 'Bearer oauth-access-token',
},
body: protocolBody,
})).toThrow(/project id missing/i);
});
it('builds antigravity provider requests without leaking gemini-cli client headers', () => {
const profile = resolveProviderProfile('antigravity');
expect(profile?.id).toBe('antigravity');
const protocolBody = {
contents: [{ role: 'user', parts: [{ text: 'hello antigravity' }] }],
};
const result = profile!.prepareRequest({
endpoint: 'chat',
modelName: 'gemini-3-pro-preview',
stream: true,
tokenValue: 'oauth-access-token',
oauthProjectId: 'project-demo',
sitePlatform: 'antigravity',
baseHeaders: {
Authorization: 'Bearer oauth-access-token',
},
providerHeaders: {
'User-Agent': 'GeminiCLI/0.31.0/unknown (win32; x64)',
'X-Goog-Api-Client': 'google-genai-sdk/1.41.0 gl-node/v22.19.0',
},
body: protocolBody,
});
expect(result.path).toBe('/v1internal:streamGenerateContent?alt=sse');
expect(result.headers.Authorization).toBe('Bearer oauth-access-token');
expect(result.headers['User-Agent']).toBe('antigravity/1.19.6 darwin/arm64');
expect(result.headers['X-Goog-Api-Client']).toBeUndefined();
expect(result.headers.Accept).toBe('text/event-stream');
expect(result.runtime).toMatchObject({
executor: 'antigravity',
modelName: 'gemini-3-pro-preview',
oauthProjectId: 'project-demo',
action: 'streamGenerateContent',
});
expect(result.body).toEqual({
project: 'project-demo',
model: 'gemini-3-pro-preview',
request: protocolBody,
});
expect((result.body as Record<string, unknown>).request).toBe(protocolBody);
});
});
@@ -0,0 +1,17 @@
import { antigravityProviderProfile } from './antigravityProviderProfile.js';
import { claudeProviderProfile } from './claudeProviderProfile.js';
import { codexProviderProfile } from './codexProviderProfile.js';
import { geminiCliProviderProfile } from './geminiCliProviderProfile.js';
import type { ProviderProfile } from './types.js';
const providerProfilesByPlatform: Record<string, ProviderProfile> = {
codex: codexProviderProfile,
claude: claudeProviderProfile,
'gemini-cli': geminiCliProviderProfile,
antigravity: antigravityProviderProfile,
};
export function resolveProviderProfile(sitePlatform?: string | null): ProviderProfile | null {
const normalized = typeof sitePlatform === 'string' ? sitePlatform.trim().toLowerCase() : '';
return providerProfilesByPlatform[normalized] ?? null;
}
+52
View File
@@ -0,0 +1,52 @@
export type ProviderProfileId =
| 'codex'
| 'claude'
| 'gemini-cli'
| 'antigravity';
export type ProviderEndpoint =
| 'chat'
| 'messages'
| 'responses';
export type ProviderAction =
| 'generateContent'
| 'streamGenerateContent'
| 'countTokens';
export type ProviderRuntimeDescriptor = {
executor: 'default' | 'codex' | 'gemini-cli' | 'antigravity' | 'claude';
modelName?: string;
stream?: boolean;
oauthProjectId?: string | null;
action?: ProviderAction;
};
export type PreparedProviderRequest = {
path: string;
headers: Record<string, string>;
body: Record<string, unknown>;
runtime: ProviderRuntimeDescriptor;
};
export type PrepareProviderRequestInput = {
endpoint: ProviderEndpoint;
modelName: string;
stream: boolean;
tokenValue: string;
oauthProvider?: string;
oauthProjectId?: string;
sitePlatform?: string;
baseHeaders: Record<string, string>;
providerHeaders?: Record<string, string>;
claudeHeaders?: Record<string, string>;
codexSessionCacheKey?: string | null;
codexExplicitSessionId?: string | null;
body: Record<string, unknown>;
action?: ProviderAction;
};
export type ProviderProfile = {
id: ProviderProfileId;
prepareRequest(input: PrepareProviderRequestInput): PreparedProviderRequest;
};