@@ -109,12 +109,17 @@ impl ConfigApi {
109109
110110 async fn apply_edits (
111111 & self ,
112- file_path : String ,
112+ file_path : Option < String > ,
113113 expected_version : Option < String > ,
114114 edits : Vec < ( String , JsonValue , MergeStrategy ) > ,
115115 ) -> Result < ConfigWriteResponse , JSONRPCErrorError > {
116116 let allowed_path = self . codex_home . join ( CONFIG_FILE_NAME ) ;
117- if !paths_match ( & allowed_path, & file_path) {
117+ let provided_path = file_path
118+ . as_ref ( )
119+ . map ( PathBuf :: from)
120+ . unwrap_or_else ( || allowed_path. clone ( ) ) ;
121+
122+ if !paths_match ( & allowed_path, & provided_path) {
118123 return Err ( config_write_error (
119124 ConfigWriteErrorCode :: ConfigLayerReadonly ,
120125 "Only writes to the user config are allowed" ,
@@ -190,9 +195,16 @@ impl ConfigApi {
190195 . map ( |_| WriteStatus :: OkOverridden )
191196 . unwrap_or ( WriteStatus :: Ok ) ;
192197
198+ let file_path = provided_path
199+ . canonicalize ( )
200+ . unwrap_or ( provided_path. clone ( ) )
201+ . display ( )
202+ . to_string ( ) ;
203+
193204 Ok ( ConfigWriteResponse {
194205 status,
195206 version : updated_layers. user . version . clone ( ) ,
207+ file_path,
196208 overridden_metadata : overridden,
197209 } )
198210 }
@@ -587,15 +599,14 @@ fn canonical_json(value: &JsonValue) -> JsonValue {
587599 }
588600}
589601
590- fn paths_match ( expected : & Path , provided : & str ) -> bool {
591- let provided_path = PathBuf :: from ( provided) ;
602+ fn paths_match ( expected : & Path , provided : & Path ) -> bool {
592603 if let ( Ok ( expanded_expected) , Ok ( expanded_provided) ) =
593- ( expected. canonicalize ( ) , provided_path . canonicalize ( ) )
604+ ( expected. canonicalize ( ) , provided . canonicalize ( ) )
594605 {
595606 return expanded_expected == expanded_provided;
596607 }
597608
598- expected == provided_path
609+ expected == provided
599610}
600611
601612fn value_at_path < ' a > ( root : & ' a TomlValue , segments : & [ String ] ) -> Option < & ' a TomlValue > {
@@ -795,7 +806,7 @@ mod tests {
795806
796807 let result = api
797808 . write_value ( ConfigValueWriteParams {
798- file_path : tmp. path ( ) . join ( CONFIG_FILE_NAME ) . display ( ) . to_string ( ) ,
809+ file_path : Some ( tmp. path ( ) . join ( CONFIG_FILE_NAME ) . display ( ) . to_string ( ) ) ,
799810 key_path : "approval_policy" . to_string ( ) ,
800811 value : json ! ( "never" ) ,
801812 merge_strategy : MergeStrategy :: Replace ,
@@ -832,7 +843,7 @@ mod tests {
832843 let api = ConfigApi :: new ( tmp. path ( ) . to_path_buf ( ) , vec ! [ ] ) ;
833844 let error = api
834845 . write_value ( ConfigValueWriteParams {
835- file_path : tmp. path ( ) . join ( CONFIG_FILE_NAME ) . display ( ) . to_string ( ) ,
846+ file_path : Some ( tmp. path ( ) . join ( CONFIG_FILE_NAME ) . display ( ) . to_string ( ) ) ,
836847 key_path : "model" . to_string ( ) ,
837848 value : json ! ( "gpt-5" ) ,
838849 merge_strategy : MergeStrategy :: Replace ,
@@ -852,6 +863,30 @@ mod tests {
852863 ) ;
853864 }
854865
866+ #[ tokio:: test]
867+ async fn write_value_defaults_to_user_config_path ( ) {
868+ let tmp = tempdir ( ) . expect ( "tempdir" ) ;
869+ std:: fs:: write ( tmp. path ( ) . join ( CONFIG_FILE_NAME ) , "" ) . unwrap ( ) ;
870+
871+ let api = ConfigApi :: new ( tmp. path ( ) . to_path_buf ( ) , vec ! [ ] ) ;
872+ api. write_value ( ConfigValueWriteParams {
873+ file_path : None ,
874+ key_path : "model" . to_string ( ) ,
875+ value : json ! ( "gpt-new" ) ,
876+ merge_strategy : MergeStrategy :: Replace ,
877+ expected_version : None ,
878+ } )
879+ . await
880+ . expect ( "write succeeds" ) ;
881+
882+ let contents =
883+ std:: fs:: read_to_string ( tmp. path ( ) . join ( CONFIG_FILE_NAME ) ) . expect ( "read config" ) ;
884+ assert ! (
885+ contents. contains( "model = \" gpt-new\" " ) ,
886+ "config.toml should be updated even when file_path is omitted"
887+ ) ;
888+ }
889+
855890 #[ tokio:: test]
856891 async fn invalid_user_value_rejected_even_if_overridden_by_managed ( ) {
857892 let tmp = tempdir ( ) . expect ( "tempdir" ) ;
@@ -872,7 +907,7 @@ mod tests {
872907
873908 let error = api
874909 . write_value ( ConfigValueWriteParams {
875- file_path : tmp. path ( ) . join ( CONFIG_FILE_NAME ) . display ( ) . to_string ( ) ,
910+ file_path : Some ( tmp. path ( ) . join ( CONFIG_FILE_NAME ) . display ( ) . to_string ( ) ) ,
876911 key_path : "approval_policy" . to_string ( ) ,
877912 value : json ! ( "bogus" ) ,
878913 merge_strategy : MergeStrategy :: Replace ,
@@ -957,7 +992,7 @@ mod tests {
957992
958993 let result = api
959994 . write_value ( ConfigValueWriteParams {
960- file_path : tmp. path ( ) . join ( CONFIG_FILE_NAME ) . display ( ) . to_string ( ) ,
995+ file_path : Some ( tmp. path ( ) . join ( CONFIG_FILE_NAME ) . display ( ) . to_string ( ) ) ,
961996 key_path : "approval_policy" . to_string ( ) ,
962997 value : json ! ( "on-request" ) ,
963998 merge_strategy : MergeStrategy :: Replace ,
0 commit comments