fix: update openhands local runtime to handle provider tokens correctly (#9915)

Co-authored-by: Engel Nyst <enyst@users.noreply.github.com>
This commit is contained in:
greese-insight 2025-07-31 15:21:33 -04:00 committed by GitHub
parent b9abdf10ce
commit d88e68eb49
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 46 additions and 14 deletions

View File

@ -24,6 +24,7 @@ from openhands.core.setup import (
create_memory,
create_runtime,
generate_sid,
get_provider_tokens,
initialize_repository_for_runtime,
)
from openhands.events import EventSource, EventStreamSubscriber
@ -103,11 +104,14 @@ async def run_controller(
# when the runtime is created, it will be connected and clone the selected repository
repo_directory = None
if runtime is None:
# In itialize repository if needed
repo_tokens = get_provider_tokens()
runtime = create_runtime(
config,
sid=sid,
headless_mode=headless_mode,
agent=agent,
git_provider_tokens=repo_tokens,
)
# Connect to the runtime
call_async_from_sync(runtime.connect)
@ -116,6 +120,7 @@ async def run_controller(
if config.sandbox.selected_repo:
repo_directory = initialize_repository_for_runtime(
runtime,
immutable_provider_tokens=repo_tokens,
selected_repository=config.sandbox.selected_repo,
)

View File

@ -16,7 +16,11 @@ from openhands.core.config.config_utils import DEFAULT_WORKSPACE_MOUNT_PATH_IN_S
from openhands.core.logger import openhands_logger as logger
from openhands.events import EventStream
from openhands.events.event import Event
from openhands.integrations.provider import ProviderToken, ProviderType
from openhands.integrations.provider import (
PROVIDER_TOKEN_TYPE,
ProviderToken,
ProviderType,
)
from openhands.llm.llm import LLM
from openhands.memory.memory import Memory
from openhands.microagent.microagent import BaseMicroagent
@ -33,6 +37,7 @@ def create_runtime(
sid: str | None = None,
headless_mode: bool = True,
agent: Agent | None = None,
git_provider_tokens: PROVIDER_TOKEN_TYPE | None = None,
) -> Runtime:
"""Create a runtime for the agent to run on.
@ -77,8 +82,10 @@ def create_runtime(
sid=session_id,
plugins=agent_cls.sandbox_plugins,
headless_mode=headless_mode,
git_provider_tokens=git_provider_tokens,
)
# Log the plugins that have been registered with the runtime for debugging purposes
logger.debug(
f'Runtime created with plugins: {[plugin.name for plugin in runtime.plugins]}'
)
@ -86,19 +93,14 @@ def create_runtime(
return runtime
def initialize_repository_for_runtime(
runtime: Runtime, selected_repository: str | None = None
) -> str | None:
"""Initialize the repository for the runtime.
Args:
runtime: The runtime to initialize the repository for.
selected_repository: (optional) The GitHub repository to use.
def get_provider_tokens():
"""
Retrieve provider tokens from environment variables and return them as a dictionary.
Returns:
The repository directory path if a repository was cloned, None otherwise.
A dictionary mapping ProviderType to ProviderToken if tokens are found, otherwise None.
"""
# clone selected repository if provided
# Collect provider tokens from environment variables if available
provider_tokens = {}
if 'GITHUB_TOKEN' in os.environ:
github_token = SecretStr(os.environ['GITHUB_TOKEN'])
@ -112,12 +114,37 @@ def initialize_repository_for_runtime(
bitbucket_token = SecretStr(os.environ['BITBUCKET_TOKEN'])
provider_tokens[ProviderType.BITBUCKET] = ProviderToken(token=bitbucket_token)
# Wrap provider tokens in UserSecrets if any tokens were found
secret_store = (
UserSecrets(provider_tokens=provider_tokens) if provider_tokens else None # type: ignore[arg-type]
)
immutable_provider_tokens = secret_store.provider_tokens if secret_store else None
return secret_store.provider_tokens if secret_store else None
def initialize_repository_for_runtime(
runtime: Runtime,
immutable_provider_tokens: PROVIDER_TOKEN_TYPE | None = None,
selected_repository: str | None = None,
) -> str | None:
"""
Initialize the repository for the runtime by cloning or initializing it,
running setup scripts, and setting up git hooks if present.
Args:
runtime: The runtime to initialize the repository for.
immutable_provider_tokens: (optional) Provider tokens to use for authentication.
selected_repository: (optional) The repository to use.
Returns:
The repository directory path if a repository was cloned, None otherwise.
"""
# If provider tokens are not provided, attempt to retrieve them from the environment
if not immutable_provider_tokens:
immutable_provider_tokens = get_provider_tokens()
logger.debug(f'Selected repository {selected_repository}.')
# Clone or initialize the repository using the runtime
repo_directory = call_async_from_sync(
runtime.clone_or_init_repo,
GENERAL_TIMEOUT,
@ -125,9 +152,9 @@ def initialize_repository_for_runtime(
selected_repository,
None,
)
# Run setup script if it exists
# Run setup script if it exists in the repository
runtime.maybe_run_setup_script()
# Set up git hooks if pre-commit.sh exists
# Set up git hooks if pre-commit.sh exists in the repository
runtime.maybe_setup_git_hooks()
return repo_directory