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:
@@ -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');
|
||||
|
||||
Reference in New Issue
Block a user