forked from boos/BoosAPI
Address high-priority review gaps before merging the dev snapshot
The release branch still had unresolved review comments around payload-rule atomicity, brand blocking, compact fallback controls, and response compatibility edge-cases. This patch pulls those behaviors back in line with the intended contracts and adds focused regression coverage for the fragile bridges. Constraint: The fixes must stay narrow to the PR branch so review/merge can continue without reopening the larger dev snapshot conflict set Rejected: Leave outdated-looking threads unresolved until after merge | reviewers still see concrete unfixed regressions in the current release branch Rejected: Re-run another broad merge from dev/main | too risky while the PR branch is already green and mergeable Confidence: medium Scope-risk: moderate Directive: If these release-branch fixes need to persist for future release cuts, backport them onto dev instead of re-fighting the same review threads next time Tested: Focused vitest for settings events, brand matcher, compact responses, codex compatibility, anthropic stream bridge, openai chat response bridge; typecheck; repo drift check; git diff --check Not-tested: Full npm test; live PR thread resolution state after push
This commit is contained in:
@@ -905,6 +905,7 @@ export async function settingsRoutes(app: FastifyInstance) {
|
||||
const body = parsedBody.data as RuntimeSettingsBody;
|
||||
const changedLabels: string[] = [];
|
||||
const currentRequestIp = extractClientIp(request.ip, request.headers['x-forwarded-for']);
|
||||
let pendingPayloadRules: typeof config.payloadRules | undefined;
|
||||
|
||||
const webhookTouched = body.webhookUrl !== undefined || body.webhookEnabled !== undefined;
|
||||
const nextWebhookUrl = body.webhookUrl !== undefined
|
||||
@@ -1149,8 +1150,7 @@ export async function settingsRoutes(app: FastifyInstance) {
|
||||
if (previousRules !== nextRules) {
|
||||
changedLabels.push('Payload 规则');
|
||||
}
|
||||
config.payloadRules = parsedPayloadRules.normalized;
|
||||
await upsertSetting('payload_rules', config.payloadRules);
|
||||
pendingPayloadRules = parsedPayloadRules.normalized;
|
||||
}
|
||||
|
||||
if (body.modelAvailabilityProbeEnabled !== undefined) {
|
||||
@@ -1718,6 +1718,11 @@ export async function settingsRoutes(app: FastifyInstance) {
|
||||
upsertSetting('token_router_failure_cooldown_max_sec', normalized);
|
||||
}
|
||||
|
||||
if (pendingPayloadRules !== undefined) {
|
||||
config.payloadRules = pendingPayloadRules;
|
||||
await upsertSetting('payload_rules', pendingPayloadRules);
|
||||
}
|
||||
|
||||
if (changedLabels.length > 0) {
|
||||
let eventType: 'checkin' | 'balance' | 'proxy' | 'status' | 'token' = 'status';
|
||||
if (changedLabels.length === 1) {
|
||||
|
||||
@@ -179,7 +179,7 @@ describe('responses proxy compact upstream routing', () => {
|
||||
expect(targetUrl).toContain('/v1/responses/compact');
|
||||
});
|
||||
|
||||
it('automatically falls back from compact to ordinary responses for generic openai-compatible upstreams when compact is unsupported', async () => {
|
||||
it('does not fall back from compact to ordinary responses for generic openai-compatible upstreams when the fallback toggle is off', async () => {
|
||||
selectChannelMock.mockReturnValue({
|
||||
channel: { id: 11, routeId: 22 },
|
||||
site: { id: 44, name: 'generic-openai-site', url: 'https://upstream.example.com', platform: 'openai' },
|
||||
@@ -199,12 +199,12 @@ describe('responses proxy compact upstream routing', () => {
|
||||
headers: { 'content-type': 'application/json' },
|
||||
}))
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify({
|
||||
id: 'resp_123',
|
||||
object: 'response',
|
||||
output_text: 'hello from fallback',
|
||||
usage: { input_tokens: 10, output_tokens: 5, total_tokens: 15 },
|
||||
error: {
|
||||
message: 'Invalid URL (POST /v1/responses/compact)',
|
||||
type: 'invalid_request_error',
|
||||
},
|
||||
}), {
|
||||
status: 200,
|
||||
status: 404,
|
||||
headers: { 'content-type': 'application/json' },
|
||||
}));
|
||||
|
||||
@@ -217,19 +217,9 @@ describe('responses proxy compact upstream routing', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(2);
|
||||
expect(response.statusCode).toBe(404);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
expect(String(fetchMock.mock.calls[0]?.[0] || '')).toContain('/v1/responses/compact');
|
||||
expect(String(fetchMock.mock.calls[1]?.[0] || '')).toContain('/v1/responses');
|
||||
expect(String(fetchMock.mock.calls[1]?.[0] || '')).not.toContain('/compact');
|
||||
expect(response.json()).toMatchObject({
|
||||
object: 'response.compaction',
|
||||
usage: {
|
||||
input_tokens: 10,
|
||||
output_tokens: 5,
|
||||
total_tokens: 15,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('optionally falls back from compact to ordinary responses when compact is explicitly unsupported', async () => {
|
||||
@@ -282,6 +272,7 @@ describe('responses proxy compact upstream routing', () => {
|
||||
});
|
||||
|
||||
it('automatically falls back from compact when a generic upstream rejects the stream parameter on the compact endpoint', async () => {
|
||||
config.responsesCompactFallbackToResponsesEnabled = true;
|
||||
selectChannelMock.mockReturnValue({
|
||||
channel: { id: 11, routeId: 22 },
|
||||
site: { id: 44, name: 'generic-openai-site', url: 'https://upstream.example.com', platform: 'openai' },
|
||||
@@ -331,6 +322,7 @@ describe('responses proxy compact upstream routing', () => {
|
||||
});
|
||||
|
||||
it('rebuilds compact fallback as an SSE-capable non-compact /v1/responses request for sub2api', async () => {
|
||||
config.responsesCompactFallbackToResponsesEnabled = true;
|
||||
selectChannelMock.mockReturnValue({
|
||||
channel: { id: 11, routeId: 22 },
|
||||
site: { id: 44, name: 'sub2api-site', url: 'https://sub2api.example.com', platform: 'sub2api' },
|
||||
|
||||
Reference in New Issue
Block a user