From 8e3078a470c2a73e3bbe0a34d7aaec9d80725d3d Mon Sep 17 00:00:00 2001 From: Alona King Date: Fri, 26 Sep 2025 17:36:00 -0400 Subject: [PATCH 1/2] fix: add provider tokens to resume conversation endpoint - Add Depends(get_provider_tokens) to /conversations/{id}/start endpoint - Override empty tokens with real provider tokens - Fixes 'Unable to access repo' error on conversation resume --- openhands/server/routes/manage_conversations.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openhands/server/routes/manage_conversations.py b/openhands/server/routes/manage_conversations.py index d996feecd951..c82f53c5948f 100644 --- a/openhands/server/routes/manage_conversations.py +++ b/openhands/server/routes/manage_conversations.py @@ -475,6 +475,7 @@ async def start_conversation( providers_set: ProvidersSetModel, conversation_id: str = Depends(validate_conversation_id), user_id: str = Depends(get_user_id), + provider_tokens: PROVIDER_TOKEN_TYPE = Depends(get_provider_tokens), settings: Settings = Depends(get_user_settings), conversation_store: ConversationStore = Depends(get_conversation_store), ) -> ConversationResponse: @@ -504,6 +505,10 @@ async def start_conversation( user_id, conversation_id, providers_set.providers_set or [] ) + # Override with real provider tokens + if provider_tokens: + conversation_init_data.git_provider_tokens = provider_tokens + # Start the agent loop agent_loop_info = await conversation_manager.maybe_start_agent_loop( sid=conversation_id, From 53db0268e69d941ee3b5c7bc716558033fe5c165 Mon Sep 17 00:00:00 2001 From: Alona King Date: Mon, 29 Sep 2025 13:24:02 -0400 Subject: [PATCH 2/2] fix: pass provider tokens during ConversationInitData construction Fixed frozen field issue where git_provider_tokens couldn't be reassigned after object creation. Now provider_tokens are passed to setup_init_conversation_settings and set during construction. - Added provider_tokens parameter to setup_init_conversation_settings - Use real tokens when provided (SAAS resume case) - Fall back to scaffold creation for non-SAAS modes - Maintains backward compatibility with existing callers --- .../server/routes/manage_conversations.py | 6 +----- .../server/services/conversation_service.py | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/openhands/server/routes/manage_conversations.py b/openhands/server/routes/manage_conversations.py index af6bf0bc03e7..7cfd701a12a4 100644 --- a/openhands/server/routes/manage_conversations.py +++ b/openhands/server/routes/manage_conversations.py @@ -489,13 +489,9 @@ async def start_conversation( # Set up conversation init data with provider information conversation_init_data = await setup_init_conversation_settings( - user_id, conversation_id, providers_set.providers_set or [] + user_id, conversation_id, providers_set.providers_set or [], provider_tokens ) - # Override with real provider tokens - if provider_tokens: - conversation_init_data.git_provider_tokens = provider_tokens - # Start the agent loop agent_loop_info = await conversation_manager.maybe_start_agent_loop( sid=conversation_id, diff --git a/openhands/server/services/conversation_service.py b/openhands/server/services/conversation_service.py index 9adfe8849e93..e2e26e1d8296 100644 --- a/openhands/server/services/conversation_service.py +++ b/openhands/server/services/conversation_service.py @@ -215,7 +215,10 @@ def create_provider_tokens_object( async def setup_init_conversation_settings( - user_id: str | None, conversation_id: str, providers_set: list[ProviderType] + user_id: str | None, + conversation_id: str, + providers_set: list[ProviderType], + provider_tokens: PROVIDER_TOKEN_TYPE | None = None, ) -> ConversationInitData: """Set up conversation initialization data with provider tokens. @@ -223,6 +226,7 @@ async def setup_init_conversation_settings( user_id: The user ID conversation_id: The conversation ID providers_set: List of provider types to set up tokens for + provider_tokens: Optional provider tokens to use (for SAAS mode resume) Returns: ConversationInitData with provider tokens configured @@ -243,11 +247,15 @@ async def setup_init_conversation_settings( session_init_args: dict = {} session_init_args = {**settings.__dict__, **session_init_args} - git_provider_tokens = create_provider_tokens_object(providers_set) - logger.info(f'Git provider scaffold: {git_provider_tokens}') + # Use provided tokens if available (for SAAS resume), otherwise create scaffold + if provider_tokens: + git_provider_tokens = provider_tokens + else: + git_provider_tokens = create_provider_tokens_object(providers_set) + logger.info(f'Git provider scaffold: {git_provider_tokens}') - if server_config.app_mode != AppMode.SAAS and user_secrets: - git_provider_tokens = user_secrets.provider_tokens + if server_config.app_mode != AppMode.SAAS and user_secrets: + git_provider_tokens = user_secrets.provider_tokens session_init_args['git_provider_tokens'] = git_provider_tokens if user_secrets: