1
0
forked from boos/BoosAPI

feat: Add support for OpenAI Responses endpoint and enhance proxy retry logic

- Updated proxyRetryPolicy to retry on all 4xx and 5xx status codes.
- Introduced 'responses' target format in TestChatRequestPayload.
- Implemented extractResponsesContent function to handle responses format in ModelTester.
- Enhanced ModelTester to support responses target format and display appropriate labels.
- Updated ProxyLogs to extract and display upstream paths from error messages.
- Added tests to ensure responses target format is preserved during payload sync.
- Created responses proxy route to handle requests to the new OpenAI Responses endpoint.
- Updated upstreamEndpoint logic to include responses endpoint handling.
- Added modelService tests to validate token route rebuilding logic.
This commit is contained in:
cita
2026-03-01 15:21:16 +08:00
parent 44af9a91cf
commit 4e22b379a8
21 changed files with 1794 additions and 56 deletions
@@ -199,6 +199,17 @@ describe('modelTesterSession', () => {
expect(syncedJson.messages).toEqual([{ role: 'user', content: 'new' }]);
});
it('keeps responses target format in custom payload sync', () => {
const synced = syncMessagesToCustomRequestBody(
'{"model":"gpt-5.2","targetFormat":"responses"}',
[{ id: '1', role: 'user', content: 'hello', createAt: 1 }],
{ ...DEFAULT_INPUTS, model: 'gpt-5.2', targetFormat: 'openai' },
);
const syncedJson = JSON.parse(synced);
expect(syncedJson.targetFormat).toBe('responses');
});
it('merges marketplace models with exact enabled route models for tester options', () => {
const modelNames = collectModelTesterModelNames(
{
+17 -5
View File
@@ -14,7 +14,7 @@ export const DEBUG_TABS = {
type MessageStatus = typeof MESSAGE_STATUS[keyof typeof MESSAGE_STATUS];
export type DebugTab = typeof DEBUG_TABS[keyof typeof DEBUG_TABS];
type ChatRole = 'user' | 'assistant' | 'system';
export type TestTargetFormat = 'openai' | 'claude';
export type TestTargetFormat = 'openai' | 'claude' | 'responses';
export type ChatMessage = {
id: string;
@@ -256,7 +256,11 @@ const parseInputs = (value: unknown, fallbackModel = ''): ModelTesterInputs => {
return {
model,
targetFormat: value.targetFormat === 'claude' ? 'claude' : DEFAULT_INPUTS.targetFormat,
targetFormat: value.targetFormat === 'claude'
? 'claude'
: value.targetFormat === 'responses'
? 'responses'
: DEFAULT_INPUTS.targetFormat,
temperature: toFiniteNumber(value.temperature, DEFAULT_INPUTS.temperature),
top_p: toFiniteNumber(value.top_p, DEFAULT_INPUTS.top_p),
max_tokens: toFiniteNumber(value.max_tokens, DEFAULT_INPUTS.max_tokens),
@@ -298,7 +302,7 @@ const parsePendingPayload = (value: unknown): TestChatPayload | null => {
messages: payloadMessages,
};
if (value.targetFormat === 'claude' || value.targetFormat === 'openai') {
if (value.targetFormat === 'claude' || value.targetFormat === 'openai' || value.targetFormat === 'responses') {
payload.targetFormat = value.targetFormat;
}
if (typeof value.stream === 'boolean') payload.stream = value.stream;
@@ -385,7 +389,11 @@ const buildFallbackInputsFromLegacy = (value: Record<string, unknown>): ModelTes
const inputs = parseInputs(value.inputs, legacyModel);
if (!value.inputs) {
inputs.targetFormat = value.targetFormat === 'claude' ? 'claude' : inputs.targetFormat;
inputs.targetFormat = value.targetFormat === 'claude'
? 'claude'
: value.targetFormat === 'responses'
? 'responses'
: inputs.targetFormat;
inputs.temperature = toFiniteNumber(value.temperature, inputs.temperature);
}
@@ -511,7 +519,11 @@ export const syncMessagesToCustomRequestBody = (
payload.model = typeof payload.model === 'string' && payload.model.trim().length > 0
? payload.model
: inputs.model;
payload.targetFormat = payload.targetFormat === 'claude' ? 'claude' : inputs.targetFormat;
payload.targetFormat = payload.targetFormat === 'claude'
? 'claude'
: payload.targetFormat === 'responses'
? 'responses'
: inputs.targetFormat;
payload.stream = payload.stream !== undefined ? payload.stream : inputs.stream;
payload.messages = toApiMessages(messages);