Preserve the active worktree snapshot on dev for follow-on integration

The root checkout already contained a large in-progress proxy, transformer,
and settings refactor. This commit captures that exact work on a dedicated
local dev branch without disturbing the original dirty worktree, so the
changes can be continued or split from dev instead of living only as
uncommitted state.

Constraint: The source checkout was already dirty on another branch, so the move had to preserve that worktree while excluding local .idea and .omx residue from the commit
Rejected: Switch the dirty root checkout directly to dev | risked disrupting the original branch and in-progress state
Confidence: medium
Scope-risk: broad
Reversibility: clean
Directive: Treat this as a transfer snapshot; fix the failing oauth/accountTokens/normalized/docs test regressions before merge or publication
Tested: git diff --check; npm run typecheck; npm run repo:drift-check
Not-tested: Clean test pass; npm test currently fails in oauth routes, accountTokens sync, shared normalized helpers, gemini route expectations, architecture-boundaries, and docs vitepress config
This commit is contained in:
cita-777
2026-04-17 19:41:14 +08:00
parent 6cca74b039
commit 88f40e91f7
133 changed files with 13780 additions and 5670 deletions
@@ -1,5 +1,10 @@
import type { PreparedProviderRequest, PrepareProviderRequestInput, ProviderProfile } from './types.js';
import { buildClaudeRuntimeHeaders } from './headerUtils.js';
import {
buildClaudeRuntimeHeaders,
CLAUDE_API_KEY_DEFAULT_BETA_HEADER,
CLAUDE_DEFAULT_BETA_HEADER,
CLAUDE_TOKEN_COUNTING_BETA,
} from './headerUtils.js';
export const claudeProviderProfile: ProviderProfile = {
id: 'claude',
@@ -22,6 +27,10 @@ export const claudeProviderProfile: ProviderProfile = {
stream: isCountTokens ? false : input.stream,
isClaudeOauthUpstream,
tokenValue: input.tokenValue,
defaultBetaHeader: isClaudeOauthUpstream
? CLAUDE_DEFAULT_BETA_HEADER
: CLAUDE_API_KEY_DEFAULT_BETA_HEADER,
...(isCountTokens ? { extraBetas: [CLAUDE_TOKEN_COUNTING_BETA] } : {}),
}),
body: input.body,
runtime: {
@@ -95,6 +95,7 @@ describe('provider header utils', () => {
expect(headers['anthropic-version']).toBe('2023-06-01');
expect(headers['anthropic-beta']).toContain('claude-code-20250219');
expect(headers['anthropic-beta']).toContain('fine-grained-tool-streaming-2025-05-14');
expect(headers['anthropic-beta']).toContain('custom-beta');
expect(headers.Authorization).toBe('Bearer oauth-token');
expect(headers.authorization).toBeUndefined();
@@ -1,9 +1,12 @@
import { pbkdf2Sync, randomUUID } from 'node:crypto';
import { inferCodexOfficialOriginator } from '../../shared/codexClientFamily.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';
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';
export const CLAUDE_TOKEN_COUNTING_BETA = 'token-counting-2024-11-01';
export const CLAUDE_DEFAULT_BETA_HEADER = 'claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05';
export const CLAUDE_API_KEY_DEFAULT_BETA_HEADER = 'claude-code-20250219,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05';
export function headerValueToString(value: unknown): string | null {
if (typeof value === 'string') {
@@ -132,7 +135,9 @@ export function buildCodexRuntimeHeaders(input: {
|| getInputHeader(input.baseHeaders, 'Authorization')
|| ''
);
const originator = getInputHeader(input.providerHeaders, 'originator')
const originator = inferCodexOfficialOriginator(input.providerHeaders)
|| inferCodexOfficialOriginator(input.baseHeaders)
|| getInputHeader(input.providerHeaders, 'originator')
|| input.originatorDefault
|| 'codex_cli_rs';
const accountId = getInputHeader(input.providerHeaders, 'chatgpt-account-id');
@@ -17,7 +17,7 @@ describe('resolveProviderProfile', () => {
Authorization: 'Bearer oauth-access-token',
},
providerHeaders: {
Originator: 'codex_cli_rs',
Originator: 'Codex Desktop',
'Chatgpt-Account-Id': 'chatgpt-account-123',
},
codexSessionCacheKey: 'gpt-5.2-codex:user-123',
@@ -30,7 +30,7 @@ describe('resolveProviderProfile', () => {
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.Originator).toBe('codex_chatgpt_desktop');
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);
@@ -74,6 +74,7 @@ describe('resolveProviderProfile', () => {
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.headers['anthropic-beta']).toContain('oauth-2025-04-20');
expect(result.headers['Accept-Encoding']).toBe('gzip, deflate, br, zstd');
expect(result.runtime).toMatchObject({
executor: 'claude',
@@ -83,6 +84,60 @@ describe('resolveProviderProfile', () => {
expect(result.body).toBe(protocolBody);
});
it('drops oauth-only claude betas for api-key upstreams', () => {
const profile = resolveProviderProfile('claude');
expect(profile?.id).toBe('claude');
const result = profile!.prepareRequest({
endpoint: 'messages',
modelName: 'claude-opus-4-6',
stream: false,
tokenValue: 'sk-claude-api-key',
sitePlatform: 'openai',
baseHeaders: {
'Content-Type': 'application/json',
},
claudeHeaders: {},
body: {
model: 'claude-opus-4-6',
max_tokens: 256,
messages: [{ role: 'user', content: 'hello' }],
},
});
expect(result.headers.Authorization).toBeUndefined();
expect(result.headers['x-api-key']).toBe('sk-claude-api-key');
expect(result.headers['anthropic-beta']).not.toContain('oauth-2025-04-20');
expect(result.headers['anthropic-beta']).toContain('fine-grained-tool-streaming-2025-05-14');
});
it('adds token-counting beta when building claude count_tokens requests', () => {
const profile = resolveProviderProfile('claude');
expect(profile?.id).toBe('claude');
const result = profile!.prepareRequest({
endpoint: 'messages',
modelName: 'claude-opus-4-6',
stream: false,
action: 'countTokens',
tokenValue: 'oauth-access-token',
oauthProvider: 'claude',
sitePlatform: 'claude',
baseHeaders: {
'Content-Type': 'application/json',
},
claudeHeaders: {},
body: {
model: 'claude-opus-4-6',
max_tokens: 256,
messages: [{ role: 'user', content: 'hello' }],
},
});
expect(result.path).toBe('/v1/messages/count_tokens?beta=true');
expect(result.headers['anthropic-beta']).toContain('token-counting-2024-11-01');
});
it('builds gemini-cli provider requests with wrapped runtime envelope and project validation', () => {
const profile = resolveProviderProfile('gemini-cli');
expect(profile?.id).toBe('gemini-cli');