@@ -365,23 +365,34 @@ fn build_turn_input_items(
365365 input. push ( json ! ( { "type" : "mention" , "name" : name, "path" : path } ) ) ;
366366 }
367367 }
368- if input. is_empty ( ) {
369- return Err ( "empty user message" . to_string ( ) ) ;
370- }
371- Ok ( input)
372- }
373-
374- pub ( crate ) async fn send_user_message_core (
375- sessions : & Mutex < HashMap < String , Arc < WorkspaceSession > > > ,
376- workspaces : & Mutex < HashMap < String , WorkspaceEntry > > ,
377- workspace_id : String ,
378- thread_id : String ,
379- text : String ,
380- model : Option < String > ,
381- effort : Option < String > ,
382- access_mode : Option < String > ,
383- images : Option < Vec < String > > ,
384- app_mentions : Option < Vec < Value > > ,
368+ if input. is_empty ( ) {
369+ return Err ( "empty user message" . to_string ( ) ) ;
370+ }
371+ Ok ( input)
372+ }
373+
374+ pub ( crate ) fn insert_optional_nullable_string (
375+ params : & mut Map < String , Value > ,
376+ key : & str ,
377+ value : Option < Option < String > > ,
378+ ) {
379+ if let Some ( value) = value {
380+ params. insert ( key. to_string ( ) , json ! ( value) ) ;
381+ }
382+ }
383+
384+ pub ( crate ) async fn send_user_message_core (
385+ sessions : & Mutex < HashMap < String , Arc < WorkspaceSession > > > ,
386+ workspaces : & Mutex < HashMap < String , WorkspaceEntry > > ,
387+ workspace_id : String ,
388+ thread_id : String ,
389+ text : String ,
390+ model : Option < String > ,
391+ effort : Option < String > ,
392+ service_tier : Option < Option < String > > ,
393+ access_mode : Option < String > ,
394+ images : Option < Vec < String > > ,
395+ app_mentions : Option < Vec < Value > > ,
385396 collaboration_mode : Option < Value > ,
386397) -> Result < Value , String > {
387398 let session = get_session_clone ( sessions, & workspace_id) . await ?;
@@ -408,14 +419,15 @@ pub(crate) async fn send_user_message_core(
408419 let mut params = Map :: new ( ) ;
409420 params. insert ( "threadId" . to_string ( ) , json ! ( thread_id) ) ;
410421 params. insert ( "input" . to_string ( ) , json ! ( input) ) ;
411- params. insert ( "cwd" . to_string ( ) , json ! ( workspace_path) ) ;
412- params. insert ( "approvalPolicy" . to_string ( ) , json ! ( approval_policy) ) ;
413- params. insert ( "sandboxPolicy" . to_string ( ) , json ! ( sandbox_policy) ) ;
414- params. insert ( "model" . to_string ( ) , json ! ( model) ) ;
415- params. insert ( "effort" . to_string ( ) , json ! ( effort) ) ;
416- if let Some ( mode) = collaboration_mode {
417- if !mode. is_null ( ) {
418- params. insert ( "collaborationMode" . to_string ( ) , mode) ;
422+ params. insert ( "cwd" . to_string ( ) , json ! ( workspace_path) ) ;
423+ params. insert ( "approvalPolicy" . to_string ( ) , json ! ( approval_policy) ) ;
424+ params. insert ( "sandboxPolicy" . to_string ( ) , json ! ( sandbox_policy) ) ;
425+ params. insert ( "model" . to_string ( ) , json ! ( model) ) ;
426+ params. insert ( "effort" . to_string ( ) , json ! ( effort) ) ;
427+ insert_optional_nullable_string ( & mut params, "serviceTier" , service_tier) ;
428+ if let Some ( mode) = collaboration_mode {
429+ if !mode. is_null ( ) {
430+ params. insert ( "collaborationMode" . to_string ( ) , mode) ;
419431 }
420432 }
421433 session
@@ -470,24 +482,24 @@ pub(crate) async fn turn_interrupt_core(
470482 . await
471483}
472484
473- pub ( crate ) async fn start_review_core (
474- sessions : & Mutex < HashMap < String , Arc < WorkspaceSession > > > ,
475- workspace_id : String ,
476- thread_id : String ,
477- target : Value ,
478- delivery : Option < String > ,
479- ) -> Result < Value , String > {
480- let session = get_session_clone ( sessions, & workspace_id) . await ?;
481- let mut params = Map :: new ( ) ;
482- params. insert ( "threadId" . to_string ( ) , json ! ( thread_id) ) ;
483- params. insert ( "target" . to_string ( ) , target) ;
484- if let Some ( delivery) = delivery {
485- params. insert ( "delivery" . to_string ( ) , json ! ( delivery) ) ;
486- }
487- session
488- . send_request_for_workspace ( & workspace_id, "review/start" , Value :: Object ( params) )
489- . await
490- }
485+ pub ( crate ) async fn start_review_core (
486+ sessions : & Mutex < HashMap < String , Arc < WorkspaceSession > > > ,
487+ workspace_id : String ,
488+ thread_id : String ,
489+ target : Value ,
490+ delivery : Option < String > ,
491+ ) -> Result < Value , String > {
492+ let session = get_session_clone ( sessions, & workspace_id) . await ?;
493+ let mut params = Map :: new ( ) ;
494+ params. insert ( "threadId" . to_string ( ) , json ! ( thread_id) ) ;
495+ params. insert ( "target" . to_string ( ) , target) ;
496+ if let Some ( delivery) = delivery {
497+ params. insert ( "delivery" . to_string ( ) , json ! ( delivery) ) ;
498+ }
499+ session
500+ . send_request_for_workspace ( & workspace_id, "review/start" , Value :: Object ( params) )
501+ . await
502+ }
491503
492504pub ( crate ) async fn model_list_core (
493505 sessions : & Mutex < HashMap < String , Arc < WorkspaceSession > > > ,
@@ -786,9 +798,10 @@ pub(crate) async fn get_config_model_core(
786798 Ok ( json ! ( { "model" : model } ) )
787799}
788800
789- #[ cfg( test) ]
790- mod tests {
791- use super :: * ;
801+ #[ cfg( test) ]
802+ mod tests {
803+ use super :: * ;
804+ use serde_json:: Value ;
792805
793806 #[ test]
794807 fn normalize_strips_file_uri_prefix ( ) {
@@ -851,7 +864,7 @@ mod tests {
851864 }
852865
853866 #[ test]
854- fn read_image_data_url_core_succeeds_with_file_uri_for_real_file ( ) {
867+ fn read_image_data_url_core_succeeds_with_file_uri_for_real_file ( ) {
855868 let dir = std:: env:: temp_dir ( ) . join ( "codex_monitor_test" ) ;
856869 std:: fs:: create_dir_all ( & dir) . unwrap ( ) ;
857870 let img_path = dir. join ( "test_photo.png" ) ;
@@ -902,7 +915,25 @@ mod tests {
902915 "plain filesystem paths with percent sequences should not be decoded, got: {:?}" ,
903916 result3. err( )
904917 ) ;
905-
906- let _ = std:: fs:: remove_dir_all ( & dir) ;
907- }
908- }
918+
919+ let _ = std:: fs:: remove_dir_all ( & dir) ;
920+ }
921+
922+ #[ test]
923+ fn insert_optional_nullable_string_omits_missing_and_preserves_null ( ) {
924+ let mut params = Map :: new ( ) ;
925+
926+ insert_optional_nullable_string ( & mut params, "serviceTier" , None ) ;
927+ assert ! ( !params. contains_key( "serviceTier" ) ) ;
928+
929+ insert_optional_nullable_string ( & mut params, "serviceTier" , Some ( None ) ) ;
930+ assert_eq ! ( params. get( "serviceTier" ) , Some ( & Value :: Null ) ) ;
931+
932+ insert_optional_nullable_string (
933+ & mut params,
934+ "serviceTier" ,
935+ Some ( Some ( "fast" . to_string ( ) ) ) ,
936+ ) ;
937+ assert_eq ! ( params. get( "serviceTier" ) , Some ( & json!( "fast" ) ) ) ;
938+ }
939+ }
0 commit comments