@@ -226,6 +226,7 @@ impl AcpHarnesses {
226226 . ok_or_else ( || format ! ( "unknown ACP harness {reference:?}" ) ) ?;
227227 let mut command = Command :: new ( & profile. command ) ;
228228 command. args ( & profile. args ) ;
229+ command. env_remove ( "OPENROUTER_API_KEY" ) ;
229230 command
230231 } ;
231232 // Every trusted profile is spawned directly (never through a shell)
@@ -282,6 +283,9 @@ impl AcpHarnesses {
282283 command. arg ( "--credential-dir" ) . arg ( path) ;
283284 }
284285 config. telemetry . append_cli_args ( & mut command) ;
286+ if let Some ( api_key) = & config. openrouter_api_key {
287+ command. env ( "OPENROUTER_API_KEY" , api_key. as_str ( ) ) ;
288+ }
285289 Ok ( command)
286290 }
287291}
@@ -307,6 +311,7 @@ pub(crate) fn serve_command(
307311 model : & str ,
308312 provider : crate :: ProviderKind ,
309313 reasoning_effort : Option < crate :: ReasoningEffort > ,
314+ openrouter_api_key : Option < & crate :: provider:: OpenRouterApiKey > ,
310315 session_id : & str ,
311316 resume : bool ,
312317) -> std:: io:: Result < Command > {
@@ -326,6 +331,9 @@ pub(crate) fn serve_command(
326331 if resume {
327332 command. arg ( "--resume" ) ;
328333 }
334+ if let Some ( api_key) = openrouter_api_key {
335+ command. env ( "OPENROUTER_API_KEY" , api_key. as_str ( ) ) ;
336+ }
329337 Ok ( command)
330338}
331339
@@ -335,6 +343,7 @@ pub(crate) struct ChildConfig {
335343 pub model : String ,
336344 pub provider : crate :: ProviderKind ,
337345 pub reasoning_effort : Option < crate :: ReasoningEffort > ,
346+ pub openrouter_api_key : Option < crate :: provider:: OpenRouterApiKey > ,
338347 pub mcp_config : Option < PathBuf > ,
339348 pub credential_storage : CredentialStorage ,
340349 pub telemetry : crate :: telemetry:: Settings ,
@@ -1047,6 +1056,7 @@ mod tests {
10471056 "test-model" ,
10481057 crate :: ProviderKind :: OpenRouter ,
10491058 Some ( crate :: ReasoningEffort :: Medium ) ,
1059+ Some ( & crate :: provider:: OpenRouterApiKey :: new ( "tui-secret" ) ) ,
10501060 "session" ,
10511061 true ,
10521062 )
@@ -1060,6 +1070,48 @@ mod tests {
10601070 args. windows( 2 )
10611071 . any( |pair| pair == [ "--reasoning-effort" , "medium" ] )
10621072 ) ;
1073+ assert ! ( args. iter( ) . all( |arg| arg != "tui-secret" ) ) ;
1074+ assert ! ( command. as_std( ) . get_envs( ) . any( |( name, value) | {
1075+ name == "OPENROUTER_API_KEY" && value == Some ( std:: ffi:: OsStr :: new( "tui-secret" ) )
1076+ } ) ) ;
1077+ }
1078+
1079+ #[ test]
1080+ fn openrouter_key_is_removed_from_external_acp_profiles ( ) {
1081+ let root = tempfile:: tempdir ( ) . unwrap ( ) ;
1082+ let harnesses = AcpHarnesses :: new ( BTreeMap :: from ( [ (
1083+ "external" . into ( ) ,
1084+ AcpHarnessProfile {
1085+ command : "external-agent" . into ( ) ,
1086+ args : Vec :: new ( ) ,
1087+ permissions : AcpPermissionPolicy :: Deny ,
1088+ } ,
1089+ ) ] ) )
1090+ . unwrap ( ) ;
1091+ for openrouter_api_key in [
1092+ Some ( crate :: provider:: OpenRouterApiKey :: new ( "external-secret" ) ) ,
1093+ None ,
1094+ ] {
1095+ let config = ChildConfig {
1096+ root : root. path ( ) . into ( ) ,
1097+ model : "model" . into ( ) ,
1098+ provider : crate :: ProviderKind :: OpenRouter ,
1099+ reasoning_effort : None ,
1100+ openrouter_api_key,
1101+ mcp_config : None ,
1102+ credential_storage : Default :: default ( ) ,
1103+ telemetry : Default :: default ( ) ,
1104+ harnesses : harnesses. clone ( ) ,
1105+ default_harness : "acp.external" . into ( ) ,
1106+ } ;
1107+ let command = harnesses. spawn ( "acp.external" , & config, None , 1 ) . unwrap ( ) ;
1108+ assert ! (
1109+ command
1110+ . as_std( )
1111+ . get_envs( )
1112+ . any( |( name, value) | { name == "OPENROUTER_API_KEY" && value. is_none( ) } )
1113+ ) ;
1114+ }
10631115 }
10641116
10651117 #[ test]
@@ -1235,6 +1287,7 @@ mod tests {
12351287 model : "unused" . into ( ) ,
12361288 provider : Default :: default ( ) ,
12371289 reasoning_effort : None ,
1290+ openrouter_api_key : None ,
12381291 mcp_config : None ,
12391292 credential_storage : Default :: default ( ) ,
12401293 telemetry : Default :: default ( ) ,
@@ -1285,6 +1338,7 @@ mod tests {
12851338 model : "unused" . into ( ) ,
12861339 provider : Default :: default ( ) ,
12871340 reasoning_effort : None ,
1341+ openrouter_api_key : None ,
12881342 mcp_config : None ,
12891343 credential_storage : Default :: default ( ) ,
12901344 telemetry : Default :: default ( ) ,
@@ -1334,6 +1388,7 @@ mod tests {
13341388 model : "unused" . into ( ) ,
13351389 provider : Default :: default ( ) ,
13361390 reasoning_effort : None ,
1391+ openrouter_api_key : None ,
13371392 mcp_config : None ,
13381393 credential_storage : Default :: default ( ) ,
13391394 telemetry : Default :: default ( ) ,
@@ -1370,6 +1425,7 @@ mod tests {
13701425 model : "test-model" . into ( ) ,
13711426 provider : crate :: ProviderKind :: OpenRouter ,
13721427 reasoning_effort : Some ( crate :: ReasoningEffort :: High ) ,
1428+ openrouter_api_key : Some ( crate :: provider:: OpenRouterApiKey :: new ( "child-secret" ) ) ,
13731429 mcp_config : None ,
13741430 credential_storage : CredentialStorage :: Filesystem ( root. path ( ) . join ( "credentials" ) ) ,
13751431 telemetry : crate :: telemetry:: Settings :: try_new (
@@ -1439,6 +1495,10 @@ mod tests {
14391495 . any( |pair| { pair == [ "--otel-message-content-max-bytes" , "4096" ] } )
14401496 ) ;
14411497 assert_eq ! ( command. as_std( ) . get_current_dir( ) , Some ( root. path( ) ) ) ;
1498+ assert ! ( args. iter( ) . all( |arg| arg != "child-secret" ) ) ;
1499+ assert ! ( command. as_std( ) . get_envs( ) . any( |( name, value) | {
1500+ name == "OPENROUTER_API_KEY" && value == Some ( std:: ffi:: OsStr :: new( "child-secret" ) )
1501+ } ) ) ;
14421502 }
14431503
14441504 #[ tokio:: test( flavor = "multi_thread" , worker_threads = 4 ) ]
@@ -1458,6 +1518,7 @@ mod tests {
14581518 model : "unused" . into ( ) ,
14591519 provider : Default :: default ( ) ,
14601520 reasoning_effort : None ,
1521+ openrouter_api_key : None ,
14611522 mcp_config : None ,
14621523 credential_storage : Default :: default ( ) ,
14631524 telemetry : Default :: default ( ) ,
@@ -1516,6 +1577,7 @@ mod tests {
15161577 model : "unused" . into ( ) ,
15171578 provider : Default :: default ( ) ,
15181579 reasoning_effort : None ,
1580+ openrouter_api_key : None ,
15191581 mcp_config : None ,
15201582 credential_storage : Default :: default ( ) ,
15211583 telemetry : Default :: default ( ) ,
0 commit comments