@@ -76,6 +76,78 @@ describe("OpenAiCodexHandler.getModel", () => {
7676} )
7777
7878describe ( "OpenAiCodexHandler.createMessage" , ( ) => {
79+ afterEach ( ( ) => {
80+ vitest . restoreAllMocks ( )
81+ vitest . unstubAllGlobals ( )
82+ } )
83+
84+ it ( "sends the priority service tier in streaming SDK requests when Fast is selected" , async ( ) => {
85+ const handler = new OpenAiCodexHandler ( {
86+ apiModelId : "gpt-5.6-sol" ,
87+ openAiCodexServiceTier : "priority" ,
88+ } )
89+ vitest . spyOn ( openAiCodexOAuthManager , "getAccessToken" ) . mockResolvedValue ( "test-token" )
90+ vitest . spyOn ( openAiCodexOAuthManager , "getAccountId" ) . mockResolvedValue ( "acct_test" )
91+ const mockCreate = vitest . fn ( ) . mockResolvedValue ( createCompletedStream ( ) )
92+ Reflect . set ( handler , "client" , { responses : { create : mockCreate } } )
93+
94+ await drainStream ( handler . createMessage ( "System prompt" , [ ] ) )
95+
96+ const [ body ] = mockCreate . mock . calls [ 0 ]
97+ expect ( body ) . toMatchObject ( { stream : true , service_tier : "priority" } )
98+ } )
99+
100+ it . each ( [
101+ [ "an absent preference" , { } ] ,
102+ [ "an explicit Standard preference from an older profile" , { openAiCodexServiceTier : "default" } ] ,
103+ ] ) ( "omits the service tier in streaming SDK requests for %s" , async ( _description , serviceTierOptions ) => {
104+ const handler = new OpenAiCodexHandler ( {
105+ apiModelId : "gpt-5.6-sol" ,
106+ ...serviceTierOptions ,
107+ } as ConstructorParameters < typeof OpenAiCodexHandler > [ 0 ] )
108+ vitest . spyOn ( openAiCodexOAuthManager , "getAccessToken" ) . mockResolvedValue ( "test-token" )
109+ vitest . spyOn ( openAiCodexOAuthManager , "getAccountId" ) . mockResolvedValue ( "acct_test" )
110+ const mockCreate = vitest . fn ( ) . mockResolvedValue ( createCompletedStream ( ) )
111+ Reflect . set ( handler , "client" , { responses : { create : mockCreate } } )
112+
113+ await drainStream ( handler . createMessage ( "System prompt" , [ ] ) )
114+
115+ expect ( mockCreate . mock . calls [ 0 ] [ 0 ] ) . not . toHaveProperty ( "service_tier" )
116+ } )
117+
118+ it ( "preserves the priority service tier in the manual streaming fallback" , async ( ) => {
119+ const handler = new OpenAiCodexHandler ( {
120+ apiModelId : "gpt-5.6-sol" ,
121+ openAiCodexServiceTier : "priority" ,
122+ } )
123+ vitest . spyOn ( openAiCodexOAuthManager , "getAccessToken" ) . mockResolvedValue ( "test-token" )
124+ vitest . spyOn ( openAiCodexOAuthManager , "getAccountId" ) . mockResolvedValue ( "acct_test" )
125+ Reflect . set ( handler , "client" , {
126+ responses : { create : vitest . fn ( ) . mockRejectedValue ( new Error ( "SDK unavailable" ) ) } ,
127+ } )
128+ const mockFetch = vitest . fn ( ) . mockResolvedValue ( {
129+ ok : true ,
130+ body : new ReadableStream ( {
131+ start ( controller ) {
132+ controller . enqueue (
133+ new TextEncoder ( ) . encode (
134+ 'data: {"type":"response.completed","response":{"output":[],"usage":{"input_tokens":1,"output_tokens":1}}}\n\n' ,
135+ ) ,
136+ )
137+ controller . close ( )
138+ } ,
139+ } ) ,
140+ } )
141+ vitest . stubGlobal ( "fetch" , mockFetch )
142+
143+ await drainStream ( handler . createMessage ( "System prompt" , [ ] ) )
144+
145+ expect ( JSON . parse ( mockFetch . mock . calls [ 0 ] [ 1 ] . body ) ) . toMatchObject ( {
146+ stream : true ,
147+ service_tier : "priority" ,
148+ } )
149+ } )
150+
79151 it ( "should skip URL-sourced images in formatFullConversation (only base64 emits input_image)" , async ( ) => {
80152 const handler = new OpenAiCodexHandler ( { apiModelId : "gpt-5.1-codex" } )
81153
@@ -176,6 +248,40 @@ describe("OpenAiCodexHandler.createMessage", () => {
176248 } )
177249} )
178250
251+ describe ( "OpenAiCodexHandler.completePrompt service tier" , ( ) => {
252+ afterEach ( ( ) => {
253+ vitest . restoreAllMocks ( )
254+ vitest . unstubAllGlobals ( )
255+ } )
256+
257+ it . each ( [
258+ [ "Fast" , "priority" , "priority" ] ,
259+ [ "Standard" , undefined , undefined ] ,
260+ ] ) ( "uses the %s preference in non-streaming requests" , async ( _mode , configuredTier , expectedTier ) => {
261+ const handler = new OpenAiCodexHandler ( {
262+ apiModelId : "gpt-5.6-sol" ,
263+ ...( configuredTier ? { openAiCodexServiceTier : configuredTier as "priority" } : { } ) ,
264+ } )
265+ vitest . spyOn ( openAiCodexOAuthManager , "getAccessToken" ) . mockResolvedValue ( "test-token" )
266+ vitest . spyOn ( openAiCodexOAuthManager , "getAccountId" ) . mockResolvedValue ( "acct_test" )
267+ const mockFetch = vitest . fn ( ) . mockResolvedValue ( {
268+ ok : true ,
269+ json : vitest . fn ( ) . mockResolvedValue ( { text : "Complete" } ) ,
270+ } )
271+ vitest . stubGlobal ( "fetch" , mockFetch )
272+
273+ await expect ( handler . completePrompt ( "Hello" ) ) . resolves . toBe ( "Complete" )
274+
275+ const body = JSON . parse ( mockFetch . mock . calls [ 0 ] [ 1 ] . body )
276+ expect ( body . stream ) . toBe ( false )
277+ if ( expectedTier ) {
278+ expect ( body . service_tier ) . toBe ( expectedTier )
279+ } else {
280+ expect ( body ) . not . toHaveProperty ( "service_tier" )
281+ }
282+ } )
283+ } )
284+
179285describe ( "transformLunaResponsesLiteBody" , ( ) => {
180286 it ( "creates the exact Responses Lite body while preserving unrelated fields and reasoning" , ( ) => {
181287 const tools = [ { type : "function" , name : "read_file" , parameters : { type : "object" } } ]
0 commit comments