11use anyhow:: Result ;
22use serde_json;
33use std:: process:: Stdio ;
4+ use std:: collections:: HashMap ;
45use tauri:: { AppHandle , Emitter } ;
56use tokio:: io:: { AsyncBufReadExt , AsyncWriteExt , BufReader } ;
67use tokio:: process:: { Child , Command } ;
@@ -48,13 +49,64 @@ impl CodexClient {
4849 cmd. args ( & args) ;
4950 }
5051 cmd. arg ( "proto" ) ;
52+
53+ // Set up environment variables for API keys
54+ let mut env_vars = HashMap :: new ( ) ;
55+ log:: debug!( "Config provider: {}, API key present: {}" ,
56+ config. provider,
57+ config. api_key. as_ref( ) . map_or( false , |k| !k. is_empty( ) ) ) ;
58+
59+ if let Some ( api_key) = & config. api_key {
60+ if !api_key. is_empty ( ) {
61+ log:: debug!( "API key provided, length: {}" , api_key. len( ) ) ;
62+ // Try to get the env_key from provider configuration first
63+ if let Ok ( providers) = read_model_providers ( ) . await {
64+ log:: debug!( "Successfully read providers, available: {:?}" , providers. keys( ) . collect:: <Vec <_>>( ) ) ;
65+
66+ // Try exact match first, then lowercase match
67+ let provider_config = providers. get ( & config. provider )
68+ . or_else ( || providers. get ( & config. provider . to_lowercase ( ) ) ) ;
69+
70+ if let Some ( provider_config) = provider_config {
71+ log:: debug!( "Found provider config: {:?}" , provider_config) ;
72+ if !provider_config. env_key . is_empty ( ) {
73+ log:: debug!( "Setting env var {} from provider config" , provider_config. env_key) ;
74+ env_vars. insert ( provider_config. env_key . clone ( ) , api_key. clone ( ) ) ;
75+ } else {
76+ log:: debug!( "Provider config has empty env_key" ) ;
77+ }
78+ } else {
79+ log:: debug!( "Provider {} not found in config" , config. provider) ;
80+ }
81+ } else {
82+ log:: debug!( "Failed to read providers, using fallback mapping" ) ;
83+ // Fallback mapping if config reading fails
84+ let env_var_name = match config. provider . as_str ( ) {
85+ "gemini" => "GEMINI_API_KEY" ,
86+ "openai" => "OPENAI_API_KEY" ,
87+ "openrouter" => "OPENROUTER_API_KEY" ,
88+ "ollama" => "OLLAMA_API_KEY" ,
89+ _ => "OPENAI_API_KEY" , // fallback
90+ } ;
91+ log:: debug!( "Using fallback env var: {}" , env_var_name) ;
92+ env_vars. insert ( env_var_name. to_string ( ) , api_key. clone ( ) ) ;
93+ }
94+ } else {
95+ log:: debug!( "API key is empty" ) ;
96+ }
97+ } else {
98+ log:: debug!( "No API key provided" ) ;
99+ }
51100
52101 // Load provider configuration from config.toml if provider is specified
53102 if !config. provider . is_empty ( ) && config. provider != "openai" {
54103 if let Ok ( providers) = read_model_providers ( ) . await {
55104 if let Ok ( profiles) = read_profiles ( ) . await {
56- // Check if there's a matching provider in config
57- if let Some ( provider_config) = providers. get ( & config. provider ) {
105+ // Check if there's a matching provider in config (try exact match first, then lowercase)
106+ let provider_config = providers. get ( & config. provider )
107+ . or_else ( || providers. get ( & config. provider . to_lowercase ( ) ) ) ;
108+
109+ if let Some ( provider_config) = provider_config {
58110 // Set model provider based on config
59111 cmd. arg ( "-c" )
60112 . arg ( format ! ( "model_provider={}" , provider_config. name) ) ;
@@ -65,14 +117,13 @@ impl CodexClient {
65117 . arg ( format ! ( "base_url={}" , provider_config. base_url) ) ;
66118 }
67119
68- // Set API key environment variable reference
69- if !provider_config. env_key . is_empty ( ) {
70- cmd. arg ( "-c" )
71- . arg ( format ! ( "api_key_env={}" , provider_config. env_key) ) ;
72- }
120+ // API key will be provided via environment variable - no need to modify provider config
73121
74122 // Use model from profile if available, otherwise from config
75- let model_to_use = if let Some ( profile) = profiles. get ( & config. provider ) {
123+ let profile = profiles. get ( & config. provider )
124+ . or_else ( || profiles. get ( & config. provider . to_lowercase ( ) ) ) ;
125+
126+ let model_to_use = if let Some ( profile) = profile {
76127 & profile. model
77128 } else {
78129 & config. model
@@ -93,6 +144,8 @@ impl CodexClient {
93144 if !config. model . is_empty ( ) {
94145 cmd. arg ( "-c" ) . arg ( format ! ( "model={}" , config. model) ) ;
95146 }
147+
148+ // API key will be provided via environment variable for custom providers
96149 }
97150 }
98151 } else {
@@ -107,6 +160,8 @@ impl CodexClient {
107160 if !config. model . is_empty ( ) {
108161 cmd. arg ( "-c" ) . arg ( format ! ( "model={}" , config. model) ) ;
109162 }
163+
164+ // API key will be provided via environment variable
110165 }
111166 } else {
112167 // Original logic for OSS and default cases
@@ -117,6 +172,8 @@ impl CodexClient {
117172 if !config. model . is_empty ( ) {
118173 cmd. arg ( "-c" ) . arg ( format ! ( "model={}" , config. model) ) ;
119174 }
175+
176+ // API key will be provided via environment variable for OpenAI
120177 }
121178
122179 if !config. approval_policy . is_empty ( ) {
@@ -140,7 +197,8 @@ impl CodexClient {
140197
141198 // Set working directory for the process
142199 if !config. working_directory . is_empty ( ) {
143- cmd. current_dir ( & config. working_directory ) ;
200+ log:: debug!( "working_directory: {:?}" , config. working_directory) ;
201+ cmd. arg ( "-c" ) . arg ( format ! ( "cwd={}" , config. working_directory) ) ;
144202 }
145203
146204 // Add custom arguments
@@ -153,10 +211,17 @@ impl CodexClient {
153211 // Print the command to be executed for debugging
154212 log:: debug!( "Starting codex with command: {:?}" , cmd) ;
155213
214+ // Apply environment variables to the command
215+ for ( key, value) in & env_vars {
216+ log:: debug!( "Setting environment variable: {}=***" , key) ;
217+ cmd. env ( key, value) ;
218+ }
219+
156220 let mut process = cmd
157221 . stdin ( Stdio :: piped ( ) )
158222 . stdout ( Stdio :: piped ( ) )
159223 . stderr ( Stdio :: piped ( ) )
224+ . current_dir ( & config. working_directory )
160225 . spawn ( ) ?;
161226
162227 let stdin = process. stdin . take ( ) . expect ( "Failed to open stdin" ) ;
@@ -194,7 +259,7 @@ impl CodexClient {
194259 log:: debug!( "Starting stdout reader for session: {}" , session_id_clone) ;
195260
196261 while let Ok ( Some ( line) ) = lines. next_line ( ) . await {
197- log:: debug!( "Received line from codex: {}" , line) ;
262+ // log::debug!("Received line from codex: {}", line);
198263 if let Ok ( event) = serde_json:: from_str :: < Event > ( & line) {
199264 // log::debug!("Parsed event: {:?}", event);
200265
0 commit comments