@@ -6,6 +6,7 @@ import { OpenAiCodexHandler } from "../openai-codex"
66import type { ApiHandlerOptions } from "../../../shared/api"
77import { NativeToolCallParser } from "../../../core/assistant-message/NativeToolCallParser"
88import { openAiCodexOAuthManager } from "../../../integrations/openai-codex/oauth"
9+ import { Package } from "../../../shared/package"
910
1011describe ( "OpenAiCodexHandler native tool calls" , ( ) => {
1112 let handler : OpenAiCodexHandler
@@ -405,4 +406,125 @@ describe("OpenAiCodexHandler native tool calls", () => {
405406 const textChunks = chunks . filter ( ( c ) => c . type === "text" )
406407 expect ( textChunks . map ( ( c ) => c . text ) . join ( "" ) ) . toBe ( "hello world" )
407408 } )
409+
410+ it ( "identifies SDK requests as Zoo Code" , async ( ) => {
411+ vi . spyOn ( openAiCodexOAuthManager , "getAccessToken" ) . mockResolvedValue ( "test-token" )
412+ vi . spyOn ( openAiCodexOAuthManager , "getAccountId" ) . mockResolvedValue ( "acct_test" )
413+
414+ const mockCreate = vi . fn ( ) . mockResolvedValue ( {
415+ async * [ Symbol . asyncIterator ] ( ) {
416+ yield { type : "response.output_text.delta" , delta : "ok" }
417+ yield {
418+ type : "response.completed" ,
419+ response : {
420+ id : "resp_sdk_headers" ,
421+ status : "completed" ,
422+ output : [ ] ,
423+ usage : { input_tokens : 1 , output_tokens : 1 } ,
424+ } ,
425+ }
426+ } ,
427+ } )
428+ ; ( handler as any ) . client = { responses : { create : mockCreate } }
429+
430+ const stream = handler . createMessage ( "system" , [ { role : "user" , content : "headers" } as any ] , {
431+ taskId : "task-123" ,
432+ tools : [ ] ,
433+ } )
434+ for await ( const _chunk of stream ) {
435+ // drain stream
436+ }
437+
438+ expect ( mockCreate ) . toHaveBeenCalledWith (
439+ expect . anything ( ) ,
440+ expect . objectContaining ( {
441+ headers : expect . objectContaining ( {
442+ originator : "zoo-code" ,
443+ session_id : "task-123" ,
444+ "ChatGPT-Account-Id" : "acct_test" ,
445+ "User-Agent" : expect . stringContaining ( `zoo-code/${ Package . version } ` ) ,
446+ } ) ,
447+ } ) ,
448+ )
449+ } )
450+
451+ it ( "identifies fetch fallback requests as Zoo Code" , async ( ) => {
452+ vi . spyOn ( openAiCodexOAuthManager , "getAccessToken" ) . mockResolvedValue ( "test-token" )
453+ vi . spyOn ( openAiCodexOAuthManager , "getAccountId" ) . mockResolvedValue ( "acct_test" )
454+
455+ const mockFetch = vi . fn ( ) . mockResolvedValue ( {
456+ ok : true ,
457+ body : new ReadableStream ( {
458+ start ( controller ) {
459+ controller . enqueue (
460+ new TextEncoder ( ) . encode ( 'data: {"type":"response.output_text.delta","delta":"fallback"}\n\n' ) ,
461+ )
462+ controller . enqueue (
463+ new TextEncoder ( ) . encode (
464+ 'data: {"type":"response.completed","response":{"id":"resp_fetch_headers","status":"completed","output":[],"usage":{"input_tokens":1,"output_tokens":1}}}\n\n' ,
465+ ) ,
466+ )
467+ controller . close ( )
468+ } ,
469+ } ) ,
470+ } )
471+ global . fetch = mockFetch as any
472+ ; ( handler as any ) . client = {
473+ responses : {
474+ create : vi . fn ( ) . mockRejectedValue ( new Error ( "SDK unavailable" ) ) ,
475+ } ,
476+ }
477+
478+ const stream = handler . createMessage ( "system" , [ { role : "user" , content : "fallback" } as any ] , {
479+ taskId : "task-456" ,
480+ tools : [ ] ,
481+ } )
482+ for await ( const _chunk of stream ) {
483+ // drain stream
484+ }
485+
486+ expect ( mockFetch ) . toHaveBeenCalledWith (
487+ expect . stringContaining ( "/responses" ) ,
488+ expect . objectContaining ( {
489+ headers : expect . objectContaining ( {
490+ originator : "zoo-code" ,
491+ session_id : "task-456" ,
492+ "ChatGPT-Account-Id" : "acct_test" ,
493+ "User-Agent" : expect . stringContaining ( `zoo-code/${ Package . version } ` ) ,
494+ } ) ,
495+ } ) ,
496+ )
497+ } )
498+
499+ it ( "identifies completePrompt requests as Zoo Code" , async ( ) => {
500+ vi . spyOn ( openAiCodexOAuthManager , "getAccessToken" ) . mockResolvedValue ( "test-token" )
501+ vi . spyOn ( openAiCodexOAuthManager , "getAccountId" ) . mockResolvedValue ( "acct_test" )
502+
503+ const mockFetch = vi . fn ( ) . mockResolvedValue ( {
504+ ok : true ,
505+ json : vi . fn ( ) . mockResolvedValue ( {
506+ output : [
507+ {
508+ type : "message" ,
509+ content : [ { type : "output_text" , text : "done" } ] ,
510+ } ,
511+ ] ,
512+ } ) ,
513+ } )
514+ global . fetch = mockFetch as any
515+
516+ await expect ( handler . completePrompt ( "Test prompt" ) ) . resolves . toBe ( "done" )
517+
518+ expect ( mockFetch ) . toHaveBeenCalledWith (
519+ expect . stringContaining ( "/responses" ) ,
520+ expect . objectContaining ( {
521+ headers : expect . objectContaining ( {
522+ originator : "zoo-code" ,
523+ "ChatGPT-Account-Id" : "acct_test" ,
524+ "User-Agent" : expect . stringContaining ( `zoo-code/${ Package . version } ` ) ,
525+ session_id : expect . any ( String ) ,
526+ } ) ,
527+ } ) ,
528+ )
529+ } )
408530} )
0 commit comments