1
0
forked from boos/BoosAPI

Improve downstream client detection

This commit is contained in:
cita
2026-03-20 15:31:21 +08:00
parent 03a3db84c1
commit 0068200f2d
4 changed files with 224 additions and 2 deletions
@@ -1,5 +1,21 @@
import type { CliProfileDefinition, DetectCliProfileInput } from './types.js';
const CODEX_OFFICIAL_CLIENT_USER_AGENT_PREFIXES = [
'codex_cli_rs/',
'codex_vscode/',
'codex_app/',
'codex_chatgpt_desktop/',
'codex_atlas/',
'codex_exec/',
'codex_sdk_ts/',
'codex ',
];
const CODEX_OFFICIAL_CLIENT_ORIGINATOR_PREFIXES = [
'codex_',
'codex ',
];
function headerValueToString(value: unknown): string | null {
if (typeof value === 'string') {
const trimmed = value.trim();
@@ -38,6 +54,18 @@ function hasHeaderPrefix(headers: Record<string, unknown> | undefined, prefix: s
});
}
function matchesHeaderPrefixes(value: string | null, prefixes: string[]): boolean {
const normalizedValue = value?.trim().toLowerCase() || '';
if (!normalizedValue) return false;
return prefixes.some((prefix) => {
const normalizedPrefix = prefix.trim().toLowerCase();
if (!normalizedPrefix) return false;
return normalizedValue.startsWith(normalizedPrefix)
|| normalizedValue.includes(normalizedPrefix);
});
}
function isCodexPath(path: string): boolean {
const normalizedPath = path.trim().toLowerCase();
return normalizedPath.startsWith('/v1/responses')
@@ -62,7 +90,8 @@ export function isCodexRequest(input: DetectCliProfileInput): boolean {
if (!headers) return false;
const originator = getHeaderValue(headers, 'originator');
if (originator?.toLowerCase() === 'codex_cli_rs') return true;
if (matchesHeaderPrefixes(originator, CODEX_OFFICIAL_CLIENT_ORIGINATOR_PREFIXES)) return true;
if (matchesHeaderPrefixes(getHeaderValue(headers, 'user-agent'), CODEX_OFFICIAL_CLIENT_USER_AGENT_PREFIXES)) return true;
if (getHeaderValue(headers, 'openai-beta')) return true;
if (hasHeaderPrefix(headers, 'x-stainless-')) return true;
if (getCodexSessionId(headers)) return true;
@@ -39,6 +39,34 @@ describe('detectCliProfile', () => {
});
});
it('detects broader Codex official-client headers from user-agent and originator prefixes', () => {
expect(detectCliProfile({
downstreamPath: '/v1/responses',
headers: {
'user-agent': 'Mozilla/5.0 codex_chatgpt_desktop/1.2.3',
},
})).toMatchObject({
id: 'codex',
capabilities: {
supportsResponsesWebsocketIncremental: true,
echoesTurnState: true,
},
});
expect(detectCliProfile({
downstreamPath: '/v1/responses',
headers: {
originator: 'codex_exec',
},
})).toMatchObject({
id: 'codex',
capabilities: {
supportsResponsesWebsocketIncremental: true,
echoesTurnState: true,
},
});
});
it('detects Claude Code requests on the count_tokens surface and exposes token counting support', () => {
expect(detectCliProfile({
downstreamPath: '/v1/messages/count_tokens',