1616from openhands .events .action import ChangeAgentStateAction , MessageAction
1717from openhands .events .event import Event , EventSource
1818from openhands .events .stream import EventStream
19- from openhands .integrations .provider import PROVIDER_TOKEN_TYPE , ProviderHandler
19+ from openhands .integrations .provider import CUSTOM_SECRETS_TYPE , PROVIDER_TOKEN_TYPE , ProviderHandler
2020from openhands .mcp import add_mcp_tools_to_agent
2121from openhands .memory .memory import Memory
2222from openhands .microagent .microagent import BaseMicroagent
2323from openhands .runtime import get_runtime_cls
2424from openhands .runtime .base import Runtime
2525from openhands .runtime .impl .remote .remote_runtime import RemoteRuntime
2626from openhands .security import SecurityAnalyzer , options
27+ from openhands .storage .data_models .user_secrets import UserSecrets
2728from openhands .storage .files import FileStore
2829from openhands .utils .async_utils import EXECUTOR , call_sync_from_async
2930from openhands .utils .shutdown_listener import should_continue
@@ -82,6 +83,7 @@ async def start(
8283 agent : Agent ,
8384 max_iterations : int ,
8485 git_provider_tokens : PROVIDER_TOKEN_TYPE | None = None ,
86+ custom_secrets : CUSTOM_SECRETS_TYPE | None = None ,
8587 max_budget_per_task : float | None = None ,
8688 agent_to_llm_config : dict [str , LLMConfig ] | None = None ,
8789 agent_configs : dict [str , AgentConfig ] | None = None ,
@@ -113,13 +115,17 @@ async def start(
113115 self ._started_at = started_at
114116 finished = False # For monitoring
115117 runtime_connected = False
118+
119+ custom_secrets_handler = UserSecrets (custom_secrets = custom_secrets if custom_secrets else {})
120+
116121 try :
117122 self ._create_security_analyzer (config .security .security_analyzer )
118123 runtime_connected = await self ._create_runtime (
119124 runtime_name = runtime_name ,
120125 config = config ,
121126 agent = agent ,
122127 git_provider_tokens = git_provider_tokens ,
128+ custom_secrets = custom_secrets ,
123129 selected_repository = selected_repository ,
124130 selected_branch = selected_branch ,
125131 )
@@ -157,12 +163,16 @@ async def start(
157163 self .memory = await self ._create_memory (
158164 selected_repository = selected_repository ,
159165 repo_directory = repo_directory ,
166+ custom_secrets_descriptions = custom_secrets_handler .get_custom_secrets_descriptions ()
160167 )
161168
162169 if git_provider_tokens :
163170 provider_handler = ProviderHandler (provider_tokens = git_provider_tokens )
164171 await provider_handler .set_event_stream_secrets (self .event_stream )
165172
173+ if custom_secrets :
174+ custom_secrets_handler .set_event_stream_secrets (self .event_stream )
175+
166176 if not self ._closed :
167177 if initial_message :
168178 self .event_stream .add_event (initial_message , EventSource .USER )
@@ -264,6 +274,7 @@ async def _create_runtime(
264274 config : AppConfig ,
265275 agent : Agent ,
266276 git_provider_tokens : PROVIDER_TOKEN_TYPE | None = None ,
277+ custom_secrets : CUSTOM_SECRETS_TYPE | None = None ,
267278 selected_repository : str | None = None ,
268279 selected_branch : str | None = None ,
269280 ) -> bool :
@@ -281,9 +292,11 @@ async def _create_runtime(
281292 if self .runtime is not None :
282293 raise RuntimeError ('Runtime already created' )
283294
295+ custom_secrets_handler = UserSecrets (custom_secrets = custom_secrets or {})
296+ env_vars = custom_secrets_handler .get_env_vars ()
297+
284298 self .logger .debug (f'Initializing runtime `{ runtime_name } ` now...' )
285299 runtime_cls = get_runtime_cls (runtime_name )
286-
287300 if runtime_cls == RemoteRuntime :
288301 self .runtime = runtime_cls (
289302 config = config ,
@@ -294,15 +307,17 @@ async def _create_runtime(
294307 headless_mode = False ,
295308 attach_to_existing = False ,
296309 git_provider_tokens = git_provider_tokens ,
310+ env_vars = env_vars ,
297311 user_id = self .user_id ,
298312 )
299313 else :
300314 provider_handler = ProviderHandler (
301315 provider_tokens = git_provider_tokens
302316 or cast (PROVIDER_TOKEN_TYPE , MappingProxyType ({}))
303317 )
304- env_vars = await provider_handler .get_env_vars (expose_secrets = True )
305-
318+
319+ # Merge git provider tokens with custom secrets before passing over to runtime
320+ env_vars .update (await provider_handler .get_env_vars (expose_secrets = True ))
306321 self .runtime = runtime_cls (
307322 config = config ,
308323 event_stream = self .event_stream ,
@@ -400,7 +415,7 @@ def _create_controller(
400415 return controller
401416
402417 async def _create_memory (
403- self , selected_repository : str | None , repo_directory : str | None
418+ self , selected_repository : str | None , repo_directory : str | None , custom_secrets_descriptions : dict [ str , str ]
404419 ) -> Memory :
405420 memory = Memory (
406421 event_stream = self .event_stream ,
@@ -410,7 +425,7 @@ async def _create_memory(
410425
411426 if self .runtime :
412427 # sets available hosts and other runtime info
413- memory .set_runtime_info (self .runtime )
428+ memory .set_runtime_info (self .runtime , custom_secrets_descriptions )
414429
415430 # loads microagents from repo/.openhands/microagents
416431 microagents : list [BaseMicroagent ] = await call_sync_from_async (
0 commit comments