Files
metapi/src/server/routes/proxy/downstreamClientContext.test.ts
T

179 lines
5.2 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
detectDownstreamClientContext,
extractClaudeCodeSessionId,
isCodexResponsesSurface,
} from './downstreamClientContext.js';
describe('extractClaudeCodeSessionId', () => {
it('extracts session uuid from axonhub-compatible Claude Code user ids', () => {
expect(extractClaudeCodeSessionId(
'user_20836b5653ed68aa981604f502c0a491397f6053826a93c953423632578d38ad_account__session_f25958b8-e75c-455d-8b40-f006d87cc2a4',
)).toBe('f25958b8-e75c-455d-8b40-f006d87cc2a4');
});
it('returns null for non-Claude-Code user ids', () => {
expect(extractClaudeCodeSessionId('user_123')).toBe(null);
expect(extractClaudeCodeSessionId('session_f25958b8-e75c-455d-8b40-f006d87cc2a4')).toBe(null);
});
});
describe('isCodexResponsesSurface', () => {
it('detects Codex responses surface from originator, stainless, and turn-state headers', () => {
expect(isCodexResponsesSurface({
originator: 'codex_cli_rs',
})).toBe(true);
expect(isCodexResponsesSurface({
'x-stainless-lang': 'typescript',
})).toBe(true);
expect(isCodexResponsesSurface({
'x-codex-turn-state': 'turn-state-123',
})).toBe(true);
});
it('returns false for generic responses clients', () => {
expect(isCodexResponsesSurface({
'content-type': 'application/json',
})).toBe(false);
});
});
describe('detectDownstreamClientContext', () => {
it('recognizes Codex requests and attaches Session_id as session and trace hint', () => {
expect(detectDownstreamClientContext({
downstreamPath: '/v1/responses',
headers: {
originator: 'codex_cli_rs',
Session_id: 'codex-session-123',
},
})).toEqual({
clientKind: 'codex',
sessionId: 'codex-session-123',
traceHint: 'codex-session-123',
});
});
it('keeps Codex requests without Session_id as client-only context', () => {
expect(detectDownstreamClientContext({
downstreamPath: '/v1/responses/compact',
headers: {
'x-stainless-lang': 'typescript',
},
})).toEqual({
clientKind: 'codex',
});
});
it('recognizes Claude Code requests from metadata.user_id without mutating the body', () => {
const body = {
model: 'claude-opus-4-6',
metadata: {
user_id: 'user_20836b5653ed68aa981604f502c0a491397f6053826a93c953423632578d38ad_account__session_f25958b8-e75c-455d-8b40-f006d87cc2a4',
},
};
expect(detectDownstreamClientContext({
downstreamPath: '/v1/messages',
body,
})).toEqual({
clientKind: 'claude_code',
sessionId: 'f25958b8-e75c-455d-8b40-f006d87cc2a4',
traceHint: 'f25958b8-e75c-455d-8b40-f006d87cc2a4',
});
expect(body).toEqual({
model: 'claude-opus-4-6',
metadata: {
user_id: 'user_20836b5653ed68aa981604f502c0a491397f6053826a93c953423632578d38ad_account__session_f25958b8-e75c-455d-8b40-f006d87cc2a4',
},
});
});
it('falls back to generic when Claude metadata.user_id is missing or invalid', () => {
expect(detectDownstreamClientContext({
downstreamPath: '/v1/messages',
body: {
metadata: {
user_id: 'user_123',
},
},
})).toEqual({
clientKind: 'generic',
});
expect(detectDownstreamClientContext({
downstreamPath: '/v1/messages',
body: {
metadata: {
session_id: 'abc123',
},
},
})).toEqual({
clientKind: 'generic',
});
});
it('recognizes Gemini CLI internal routes as a first-class downstream client kind', () => {
expect(detectDownstreamClientContext({
downstreamPath: '/v1internal:generateContent',
body: {
model: 'gpt-4.1',
contents: [
{
role: 'user',
parts: [{ text: 'hello' }],
},
],
},
})).toEqual({
clientKind: 'gemini_cli',
});
});
it('recognizes app fingerprints alongside a generic protocol family', () => {
expect(detectDownstreamClientContext({
downstreamPath: '/v1/chat/completions',
headers: {
'x-title': 'Cherry Studio',
'http-referer': 'https://cherry-ai.com',
},
})).toEqual({
clientKind: 'generic',
clientAppId: 'cherry_studio',
clientAppName: 'Cherry Studio',
clientConfidence: 'exact',
});
});
it('keeps protocol family detection when an app fingerprint also matches', () => {
expect(detectDownstreamClientContext({
downstreamPath: '/v1/responses',
headers: {
originator: 'codex_cli_rs',
'x-title': 'Cherry Studio',
'http-referer': 'https://cherry-ai.com',
},
})).toEqual({
clientKind: 'codex',
clientAppId: 'cherry_studio',
clientAppName: 'Cherry Studio',
clientConfidence: 'exact',
});
});
it('marks weak app-only matches as heuristic instead of upgrading protocol behavior', () => {
expect(detectDownstreamClientContext({
downstreamPath: '/v1/chat/completions',
headers: {
'user-agent': 'CherryStudio/1.2.3',
},
})).toEqual({
clientKind: 'generic',
clientAppId: 'cherry_studio',
clientAppName: 'Cherry Studio',
clientConfidence: 'heuristic',
});
});
});