Follow-ups surfaced by cross-model review during #1856 (all pre-existing in the #1616 gateway code, none introduced there — filed separately so the test PR stays scoped):
- Malformed input shapes surface as 500s instead of OpenAI-shape 400s. Unguarded paths throw plain
TypeError/SyntaxError (no statusCode), which serialize as 500s; OpenAI SDK clients retry 5xx, so these should be invalid_request_error 400s:
- non-array
tools (req.tools?.length is truthy for a string; translateTools's .map throws) — chatCompletions.ts / translation.ts
tools[] element without function, and messages[] element that is null — translation.ts
- malformed JSON body:
body = await body rejects outside the try/catch — embeddings.ts, chatCompletions.ts
response_format: json_schema nesting: toGenerateOpts forwards the OpenAI wrapper { name, schema, strict } as the schema; the actual schema is nested at json_schema.schema. Verify what the backend contract expects and unwrap accordingly — translation.ts.
role: 'developer' unmapped: newer OpenAI models send role: 'developer'; translateMessages casts it through without mapping. Decide mapping (likely → system).
Context: #631 (Phase 4 of #510), gateway code lands via #1616.
🤖 Filed with Claude Code on behalf of @heskew from cross-model review findings
Follow-ups surfaced by cross-model review during #1856 (all pre-existing in the #1616 gateway code, none introduced there — filed separately so the test PR stays scoped):
TypeError/SyntaxError(nostatusCode), which serialize as 500s; OpenAI SDK clients retry 5xx, so these should beinvalid_request_error400s:tools(req.tools?.lengthis truthy for a string;translateTools's.mapthrows) —chatCompletions.ts/translation.tstools[]element withoutfunction, andmessages[]element that is null —translation.tsbody = await bodyrejects outside the try/catch —embeddings.ts,chatCompletions.tsresponse_format: json_schemanesting:toGenerateOptsforwards the OpenAI wrapper{ name, schema, strict }as the schema; the actual schema is nested atjson_schema.schema. Verify what the backend contract expects and unwrap accordingly —translation.ts.role: 'developer'unmapped: newer OpenAI models sendrole: 'developer';translateMessagescasts it through without mapping. Decide mapping (likely →system).Context: #631 (Phase 4 of #510), gateway code lands via #1616.
🤖 Filed with Claude Code on behalf of @heskew from cross-model review findings