11import { TranslatorRegistry } from '../src/converters/registry.js' ;
22import { TranslatorPipeline } from '../src/converters/pipeline.js' ;
3+ import { registerAllTranslatorPairs } from '../src/converters/init.js' ;
4+ import { FormatOpenAI , FormatOpenAIResponse } from '../src/converters/formats.js' ;
5+ import { isErrorEnvelope } from '../src/converters/wire.js' ;
36import { makeId , normalizeArgs , num , asArray , str } from '../src/converters/json.js' ;
47import {
58 usageToChat ,
@@ -11,7 +14,8 @@ import {
1114 convertChatResponseToResponsesNonStream ,
1215 convertResponsesResponseToChatNonStream ,
1316} from '../src/converters/chat-responses/response.js' ;
14- import { convertChatRequestToMessages } from '../src/converters/chat-messages/request.js' ;
17+ import { convertChatRequestToMessages , convertMessagesRequestToChat } from '../src/converters/chat-messages/request.js' ;
18+ import { convertChatRequestToResponses } from '../src/converters/chat-responses/request.js' ;
1519import {
1620 convertMessagesRequestToResponses ,
1721 convertResponsesRequestToMessages ,
@@ -166,3 +170,49 @@ describe('Phase4 text-core downgrade pinned (P0)', () => {
166170 expect ( deltas . some ( ( e ) => e . type === 'response.output_text.delta' ) ) . toBe ( true ) ;
167171 } ) ;
168172} ) ;
173+
174+ describe ( 'PR review follow-ups' , ( ) => {
175+ test ( 'registerAll retry on a wired registry fails loud (no silent half-wire)' , ( ) => {
176+ const r = new TranslatorRegistry ( ) ;
177+ r . register ( FormatOpenAIResponse , FormatOpenAI , ( model , body ) => ( { ...body , model } ) , {
178+ nonStream : ( m , _o , _t , b ) => b ,
179+ } ) ;
180+ expect ( ( ) => registerAllTranslatorPairs ( r ) ) . toThrow ( / d u p l i c a t e / ) ;
181+ } ) ;
182+
183+ test ( 'registerAll on a fresh registry wires all 12 pairs' , ( ) => {
184+ const r = new TranslatorRegistry ( ) ;
185+ expect ( ( ) => registerAllTranslatorPairs ( r ) ) . not . toThrow ( ) ;
186+ expect ( r . size ( ) ) . toEqual ( { requests : 12 , responses : 12 } ) ;
187+ } ) ;
188+
189+ test ( 'isErrorEnvelope string path: error markers match, assistant text does not' , ( ) => {
190+ expect ( isErrorEnvelope ( 'event: error\ndata: {"type":"error"}' ) ) . toBe ( true ) ;
191+ expect ( isErrorEnvelope ( 'data: {"type":"response.failed"}' ) ) . toBe ( true ) ;
192+ expect ( isErrorEnvelope ( '{"type":"error","error":{"message":"x"}}' ) ) . toBe ( true ) ;
193+ expect ( isErrorEnvelope ( 'data: {"type":"response.output_text.delta"}' ) ) . toBe ( false ) ;
194+ // Valid delta whose text mentions error literals must still translate.
195+ expect ( isErrorEnvelope ( 'data: {"choices":[{"delta":{"content":"she explained \\"type\\":\\"error\\" handling"}}]}' ) ) . toBe ( false ) ;
196+ expect ( isErrorEnvelope ( 'data: [DONE]' ) ) . toBe ( false ) ;
197+ } ) ;
198+
199+ test ( 'chat->responses image detail original normalizes to high (symmetric)' , ( ) => {
200+ const out = convertChatRequestToResponses ( 'm' , {
201+ messages : [ { role : 'user' , content : [ { type : 'image_url' , image_url : { url : 'data:x' , detail : 'original' } } ] } ] ,
202+ } , false ) ;
203+ expect ( out . input [ 0 ] . content ) . toEqual ( [ { type : 'input_image' , image_url : 'data:x' , detail : 'high' } ] ) ;
204+ const missing = convertChatRequestToResponses ( 'm' , {
205+ messages : [ { role : 'user' , content : [ { type : 'image_url' , image_url : { url : 'data:x' } } ] } ] ,
206+ } , false ) ;
207+ expect ( missing . input [ 0 ] . content ) . toEqual ( [ { type : 'input_image' , image_url : 'data:x' } ] ) ;
208+ } ) ;
209+
210+ test ( 'thinking type matching is case-insensitive (Disabled -> none)' , ( ) => {
211+ const out = convertMessagesRequestToChat ( 'm' , {
212+ messages : [ { role : 'user' , content : [ { type : 'text' , text : 'hi' } ] } ] ,
213+ thinking : { type : 'Disabled' } ,
214+ } , false ) ;
215+ // 'none' adds no prompt line downstream; legacy exact-match gave null.
216+ expect ( out . reasoning_effort ) . toBe ( 'none' ) ;
217+ } ) ;
218+ } ) ;
0 commit comments