@@ -1582,6 +1582,38 @@ impl ProviderModelConfig {
15821582 }
15831583}
15841584
1585+ /// Runtime settings applied when creating or resuming a session.
1586+ #[ derive( Debug , Clone , Default , PartialEq , Eq , Serialize , Deserialize ) ]
1587+ #[ serde( rename_all = "camelCase" ) ]
1588+ #[ non_exhaustive]
1589+ pub struct RuntimeSettings {
1590+ /// Restricts model selection to this model identifier.
1591+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
1592+ pub model_lock : Option < String > ,
1593+ /// Restricts context tier selection to this tier.
1594+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
1595+ pub context_tier_lock : Option < String > ,
1596+ }
1597+
1598+ impl RuntimeSettings {
1599+ /// Construct runtime settings with all fields unset.
1600+ pub fn new ( ) -> Self {
1601+ Self :: default ( )
1602+ }
1603+
1604+ /// Restrict model selection to the given model identifier.
1605+ pub fn with_model_lock ( mut self , model_lock : impl Into < String > ) -> Self {
1606+ self . model_lock = Some ( model_lock. into ( ) ) ;
1607+ self
1608+ }
1609+
1610+ /// Restrict context tier selection to the given tier.
1611+ pub fn with_context_tier_lock ( mut self , context_tier_lock : impl Into < String > ) -> Self {
1612+ self . context_tier_lock = Some ( context_tier_lock. into ( ) ) ;
1613+ self
1614+ }
1615+ }
1616+
15851617/// Configuration for creating a new session via the `session.create` RPC.
15861618///
15871619/// All fields are optional — the CLI applies sensible defaults.
@@ -1640,6 +1672,8 @@ pub struct SessionConfig {
16401672 pub session_id : Option < SessionId > ,
16411673 /// Model to use (e.g. `"gpt-4"`, `"claude-sonnet-4"`).
16421674 pub model : Option < String > ,
1675+ /// Runtime settings applied to this session.
1676+ pub runtime_settings : Option < RuntimeSettings > ,
16431677 /// Application name sent as `User-Agent` context.
16441678 pub client_name : Option < String > ,
16451679 /// Reasoning effort level (e.g. `"low"`, `"medium"`, `"high"`).
@@ -1921,6 +1955,7 @@ impl std::fmt::Debug for SessionConfig {
19211955 f. debug_struct ( "SessionConfig" )
19221956 . field ( "session_id" , & self . session_id )
19231957 . field ( "model" , & self . model )
1958+ . field ( "runtime_settings" , & self . runtime_settings )
19241959 . field ( "client_name" , & self . client_name )
19251960 . field ( "reasoning_effort" , & self . reasoning_effort )
19261961 . field ( "reasoning_summary" , & self . reasoning_summary )
@@ -2048,6 +2083,7 @@ impl Default for SessionConfig {
20482083 Self {
20492084 session_id : None ,
20502085 model : None ,
2086+ runtime_settings : None ,
20512087 client_name : None ,
20522088 reasoning_effort : None ,
20532089 reasoning_summary : None ,
@@ -2200,6 +2236,7 @@ impl SessionConfig {
22002236 let wire = crate :: wire:: SessionCreateWire {
22012237 session_id,
22022238 model : self . model ,
2239+ runtime_settings : self . runtime_settings ,
22032240 client_name : self . client_name ,
22042241 reasoning_effort : self . reasoning_effort ,
22052242 reasoning_summary : self . reasoning_summary ,
@@ -2406,6 +2443,12 @@ impl SessionConfig {
24062443 self
24072444 }
24082445
2446+ /// Set runtime settings for this session.
2447+ pub fn with_runtime_settings ( mut self , runtime_settings : RuntimeSettings ) -> Self {
2448+ self . runtime_settings = Some ( runtime_settings) ;
2449+ self
2450+ }
2451+
24092452 /// Set the application name sent as `User-Agent` context.
24102453 pub fn with_client_name ( mut self , name : impl Into < String > ) -> Self {
24112454 self . client_name = Some ( name. into ( ) ) ;
@@ -2870,6 +2913,8 @@ pub struct ResumeSessionConfig {
28702913 /// Model to use for this session (e.g. `"gpt-4"`, `"claude-sonnet-4"`).
28712914 /// Can change the model when resuming.
28722915 pub model : Option < String > ,
2916+ /// Runtime settings applied to the resumed session.
2917+ pub runtime_settings : Option < RuntimeSettings > ,
28732918 /// Application name sent as User-Agent context.
28742919 pub client_name : Option < String > ,
28752920 /// Desired reasoning effort to apply after resuming the session.
@@ -3089,6 +3134,7 @@ impl std::fmt::Debug for ResumeSessionConfig {
30893134 f. debug_struct ( "ResumeSessionConfig" )
30903135 . field ( "session_id" , & self . session_id )
30913136 . field ( "model" , & self . model )
3137+ . field ( "runtime_settings" , & self . runtime_settings )
30923138 . field ( "client_name" , & self . client_name )
30933139 . field ( "reasoning_effort" , & self . reasoning_effort )
30943140 . field ( "reasoning_summary" , & self . reasoning_summary )
@@ -3253,6 +3299,7 @@ impl ResumeSessionConfig {
32533299 let wire = crate :: wire:: SessionResumeWire {
32543300 session_id : self . session_id ,
32553301 model : self . model ,
3302+ runtime_settings : self . runtime_settings ,
32563303 client_name : self . client_name ,
32573304 reasoning_effort : self . reasoning_effort ,
32583305 reasoning_summary : self . reasoning_summary ,
@@ -3350,6 +3397,7 @@ impl ResumeSessionConfig {
33503397 Self {
33513398 session_id,
33523399 model : None ,
3400+ runtime_settings : None ,
33533401 client_name : None ,
33543402 reasoning_effort : None ,
33553403 reasoning_summary : None ,
@@ -3527,6 +3575,12 @@ impl ResumeSessionConfig {
35273575 self
35283576 }
35293577
3578+ /// Set runtime settings for the resumed session.
3579+ pub fn with_runtime_settings ( mut self , runtime_settings : RuntimeSettings ) -> Self {
3580+ self . runtime_settings = Some ( runtime_settings) ;
3581+ self
3582+ }
3583+
35303584 /// Set the application name sent as `User-Agent` context.
35313585 pub fn with_client_name ( mut self , name : impl Into < String > ) -> Self {
35323586 self . client_name = Some ( name. into ( ) ) ;
@@ -5404,9 +5458,9 @@ mod tests {
54045458 CustomAgentConfig , DeliveryMode , ExtensionInfo , GitHubReferenceType , InfiniteSessionConfig ,
54055459 LargeToolOutputConfig , McpServerConfig , McpStdioServerConfig , MemoryConfiguration ,
54065460 NamedProviderConfig , ProviderConfig , ProviderModelConfig , ReasoningSummary ,
5407- ResumeSessionConfig , SessionConfig , SessionEvent , SessionId , SystemMessageConfig , Tool ,
5408- ToolBinaryResult , ToolResult , ToolResultExpanded , ToolResultResponse ,
5409- ensure_attachment_display_names,
5461+ ResumeSessionConfig , RuntimeSettings , SessionConfig , SessionEvent , SessionId ,
5462+ SystemMessageConfig , Tool , ToolBinaryResult , ToolResult , ToolResultExpanded ,
5463+ ToolResultResponse , ensure_attachment_display_names,
54105464 } ;
54115465 use crate :: generated:: session_events:: TypedSessionEvent ;
54125466
@@ -5791,6 +5845,83 @@ mod tests {
57915845 assert_eq ! ( json[ "expAssignments" ] , assignments) ;
57925846 }
57935847
5848+ #[ test]
5849+ fn runtime_settings_serializes_locks ( ) {
5850+ let settings = RuntimeSettings :: new ( )
5851+ . with_model_lock ( "gpt-5.6-sol" )
5852+ . with_context_tier_lock ( "long_context" ) ;
5853+ assert_eq ! (
5854+ serde_json:: to_value( settings) . unwrap( ) ,
5855+ json!( {
5856+ "modelLock" : "gpt-5.6-sol" ,
5857+ "contextTierLock" : "long_context"
5858+ } )
5859+ ) ;
5860+ assert_eq ! (
5861+ serde_json:: to_value( RuntimeSettings :: default ( ) ) . unwrap( ) ,
5862+ json!( { } )
5863+ ) ;
5864+ }
5865+
5866+ #[ test]
5867+ fn session_config_into_wire_serializes_runtime_settings ( ) {
5868+ let config = SessionConfig :: default ( ) . with_runtime_settings (
5869+ RuntimeSettings :: new ( )
5870+ . with_model_lock ( "gpt-5.6-sol" )
5871+ . with_context_tier_lock ( "long_context" ) ,
5872+ ) ;
5873+ let ( wire, _) = config
5874+ . into_wire ( Some ( SessionId :: from ( "runtime-settings" ) ) )
5875+ . expect ( "no duplicate handlers" ) ;
5876+ let json = serde_json:: to_value ( wire) . unwrap ( ) ;
5877+ assert_eq ! (
5878+ json[ "runtimeSettings" ] ,
5879+ json!( {
5880+ "modelLock" : "gpt-5.6-sol" ,
5881+ "contextTierLock" : "long_context"
5882+ } )
5883+ ) ;
5884+
5885+ let ( wire, _) = SessionConfig :: default ( )
5886+ . into_wire ( Some ( SessionId :: from ( "no-runtime-settings" ) ) )
5887+ . expect ( "no duplicate handlers" ) ;
5888+ assert ! (
5889+ serde_json:: to_value( wire)
5890+ . unwrap( )
5891+ . get( "runtimeSettings" )
5892+ . is_none( )
5893+ ) ;
5894+ }
5895+
5896+ #[ test]
5897+ fn resume_session_config_into_wire_serializes_runtime_settings ( ) {
5898+ let config = ResumeSessionConfig :: new ( SessionId :: from ( "runtime-settings" ) )
5899+ . with_runtime_settings (
5900+ RuntimeSettings :: new ( )
5901+ . with_model_lock ( "gpt-5.6-sol" )
5902+ . with_context_tier_lock ( "long_context" ) ,
5903+ ) ;
5904+ let ( wire, _) = config. into_wire ( ) . expect ( "no duplicate handlers" ) ;
5905+ let json = serde_json:: to_value ( wire) . unwrap ( ) ;
5906+ assert_eq ! (
5907+ json[ "runtimeSettings" ] ,
5908+ json!( {
5909+ "modelLock" : "gpt-5.6-sol" ,
5910+ "contextTierLock" : "long_context"
5911+ } )
5912+ ) ;
5913+
5914+ let ( wire, _) = ResumeSessionConfig :: new ( SessionId :: from ( "no-runtime-settings" ) )
5915+ . into_wire ( )
5916+ . expect ( "no duplicate handlers" ) ;
5917+ assert ! (
5918+ serde_json:: to_value( wire)
5919+ . unwrap( )
5920+ . get( "runtimeSettings" )
5921+ . is_none( )
5922+ ) ;
5923+ }
5924+
57945925 #[ test]
57955926 #[ allow( clippy:: field_reassign_with_default) ]
57965927 fn session_config_into_wire_serializes_bucket_b_fields ( ) {
0 commit comments