Settle the last concrete review regressions on the release branch
A few review threads still pointed at real behavior mismatches: Anthropic tool JSON deltas were still trimming whitespace, Responses conversion still raised low token caps to the floor, and the bare /responses GET alias returned upgrade messaging that did not match the actual websocket entrypoint. This commit makes those behaviors explicit and locks them with focused tests. Constraint: Keep the release branch green while fixing only the review findings that have a clear, testable contract Rejected: Leave these for a follow-up cleanup PR | they were low-diff and directly blocked comment resolution on the current release PR Confidence: high Scope-risk: narrow Directive: Preserve raw stream delta text unless a downstream protocol explicitly requires normalization; whitespace can be semantic in incremental payloads Tested: Focused vitest for anthropic stream bridge, responses conversion, route aliases; typecheck; git diff --check Not-tested: Full npm test; the remaining review threads that still need broader product decisions
This commit is contained in:
@@ -34,7 +34,7 @@ export async function responsesProxyRoute(app: FastifyInstance) {
|
||||
app.get('/responses', async (_request: FastifyRequest, reply: FastifyReply) =>
|
||||
reply.code(426).send({
|
||||
error: {
|
||||
message: 'WebSocket upgrade required for GET /responses',
|
||||
message: 'WebSocket upgrade required for GET /v1/responses',
|
||||
type: 'invalid_request_error',
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -89,7 +89,7 @@ describe('proxy route aliases', () => {
|
||||
expect(handleOpenAiResponsesSurfaceRequestMock).not.toHaveBeenCalled();
|
||||
expect(response.json()).toEqual({
|
||||
error: {
|
||||
message: 'WebSocket upgrade required for GET /responses',
|
||||
message: 'WebSocket upgrade required for GET /v1/responses',
|
||||
type: 'invalid_request_error',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -109,6 +109,30 @@ describe('anthropic messages stream bridge', () => {
|
||||
expect(thinkingResult.lines.join('')).toContain(' padded thinking ');
|
||||
});
|
||||
|
||||
it('preserves partial_json spacing for streaming tool-call deltas', () => {
|
||||
const streamContext = anthropicMessagesStream.createContext('claude-test');
|
||||
const downstreamContext = anthropicMessagesStream.createDownstreamContext();
|
||||
|
||||
const result = consumeAnthropicSseEvent(
|
||||
{
|
||||
event: 'content_block_delta',
|
||||
data: JSON.stringify({
|
||||
type: 'content_block_delta',
|
||||
index: 0,
|
||||
delta: {
|
||||
type: 'input_json_delta',
|
||||
partial_json: '{ "city": "Paris" }',
|
||||
},
|
||||
}),
|
||||
},
|
||||
streamContext,
|
||||
downstreamContext,
|
||||
'claude-test',
|
||||
);
|
||||
|
||||
expect(result.lines.join('')).toContain('partial_json":"{ \\"city\\": \\"Paris\\" }"');
|
||||
});
|
||||
|
||||
it('preserves responses output-item ordering when streaming anthropic fallback blocks', () => {
|
||||
const streamContext = anthropicMessagesStream.createContext('claude-test');
|
||||
const downstreamContext = anthropicMessagesStream.createDownstreamContext();
|
||||
|
||||
@@ -867,7 +867,7 @@ function normalizeAnthropicRawEvent(
|
||||
return {
|
||||
toolCallDeltas: [{
|
||||
index,
|
||||
argumentsDelta: asTrimmedString(delta.partial_json),
|
||||
argumentsDelta: asUntouchedString(delta.partial_json),
|
||||
}],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -719,7 +719,7 @@ describe('convertOpenAiBodyToResponsesBody', () => {
|
||||
expect(result.max_output_tokens).toBeUndefined();
|
||||
});
|
||||
|
||||
it('clamps explicit chat token limits to the sub2api floor when converting to Responses bodies', () => {
|
||||
it('preserves explicit chat token limits when converting to Responses bodies', () => {
|
||||
const result = convertOpenAiBodyToResponsesBody(
|
||||
{
|
||||
model: 'gpt-5',
|
||||
@@ -730,7 +730,7 @@ describe('convertOpenAiBodyToResponsesBody', () => {
|
||||
false,
|
||||
);
|
||||
|
||||
expect(result.max_output_tokens).toBe(128);
|
||||
expect(result.max_output_tokens).toBe(64);
|
||||
});
|
||||
|
||||
it('uses sub2api-compatible placeholders for empty tool arguments and empty tool outputs', () => {
|
||||
|
||||
@@ -618,10 +618,7 @@ export function convertOpenAiBodyToResponsesBody(
|
||||
};
|
||||
|
||||
if (requestedMaxOutputTokens !== null && requestedMaxOutputTokens > 0) {
|
||||
body.max_output_tokens = Math.max(
|
||||
MIN_RESPONSES_MAX_OUTPUT_TOKENS,
|
||||
Math.trunc(requestedMaxOutputTokens),
|
||||
);
|
||||
body.max_output_tokens = Math.trunc(requestedMaxOutputTokens);
|
||||
}
|
||||
|
||||
if (systemContents.length > 0) {
|
||||
|
||||
Reference in New Issue
Block a user