Spaces:
Build error
Build error
| from types import MappingProxyType | |
| from typing import Any | |
| from pydantic import ( | |
| BaseModel, | |
| Field, | |
| SerializationInfo, | |
| field_serializer, | |
| model_validator, | |
| ) | |
| from pydantic.json import pydantic_encoder | |
| from openhands.events.stream import EventStream | |
| from openhands.integrations.provider import ( | |
| CUSTOM_SECRETS_TYPE, | |
| CUSTOM_SECRETS_TYPE_WITH_JSON_SCHEMA, | |
| PROVIDER_TOKEN_TYPE, | |
| PROVIDER_TOKEN_TYPE_WITH_JSON_SCHEMA, | |
| CustomSecret, | |
| ProviderToken, | |
| ) | |
| from openhands.integrations.service_types import ProviderType | |
| class UserSecrets(BaseModel): | |
| provider_tokens: PROVIDER_TOKEN_TYPE_WITH_JSON_SCHEMA = Field( | |
| default_factory=lambda: MappingProxyType({}) | |
| ) | |
| custom_secrets: CUSTOM_SECRETS_TYPE_WITH_JSON_SCHEMA = Field( | |
| default_factory=lambda: MappingProxyType({}) | |
| ) | |
| model_config = { | |
| 'frozen': True, | |
| 'validate_assignment': True, | |
| 'arbitrary_types_allowed': True, | |
| } | |
| def provider_tokens_serializer( | |
| self, provider_tokens: PROVIDER_TOKEN_TYPE, info: SerializationInfo | |
| ) -> dict[str, dict[str, str | Any]]: | |
| tokens = {} | |
| expose_secrets = info.context and info.context.get('expose_secrets', False) | |
| for token_type, provider_token in provider_tokens.items(): | |
| if not provider_token or not provider_token.token: | |
| continue | |
| token_type_str = ( | |
| token_type.value | |
| if isinstance(token_type, ProviderType) | |
| else str(token_type) | |
| ) | |
| token = None | |
| if provider_token.token: | |
| token = ( | |
| provider_token.token.get_secret_value() | |
| if expose_secrets | |
| else pydantic_encoder(provider_token.token) | |
| ) | |
| tokens[token_type_str] = { | |
| 'token': token, | |
| 'host': provider_token.host, | |
| 'user_id': provider_token.user_id, | |
| } | |
| return tokens | |
| def custom_secrets_serializer( | |
| self, custom_secrets: CUSTOM_SECRETS_TYPE, info: SerializationInfo | |
| ): | |
| secrets = {} | |
| expose_secrets = info.context and info.context.get('expose_secrets', False) | |
| if custom_secrets: | |
| for secret_name, secret_value in custom_secrets.items(): | |
| secrets[secret_name] = { | |
| 'secret': secret_value.secret.get_secret_value() | |
| if expose_secrets | |
| else pydantic_encoder(secret_value.secret), | |
| 'description': secret_value.description, | |
| } | |
| return secrets | |
| def convert_dict_to_mappingproxy( | |
| cls, data: dict[str, dict[str, Any] | MappingProxyType] | PROVIDER_TOKEN_TYPE | |
| ) -> dict[str, MappingProxyType | None]: | |
| """Custom deserializer to convert dictionary into MappingProxyType""" | |
| if not isinstance(data, dict): | |
| raise ValueError('UserSecrets must be initialized with a dictionary') | |
| new_data: dict[str, MappingProxyType | None] = {} | |
| if 'provider_tokens' in data: | |
| tokens = data['provider_tokens'] | |
| if isinstance( | |
| tokens, dict | |
| ): # Ensure conversion happens only for dict inputs | |
| converted_tokens = {} | |
| for key, value in tokens.items(): | |
| try: | |
| provider_type = ( | |
| ProviderType(key) if isinstance(key, str) else key | |
| ) | |
| converted_tokens[provider_type] = ProviderToken.from_value( | |
| value | |
| ) | |
| except ValueError: | |
| # Skip invalid provider types or tokens | |
| continue | |
| # Convert to MappingProxyType | |
| new_data['provider_tokens'] = MappingProxyType(converted_tokens) | |
| elif isinstance(tokens, MappingProxyType): | |
| new_data['provider_tokens'] = tokens | |
| if 'custom_secrets' in data: | |
| secrets = data['custom_secrets'] | |
| if isinstance(secrets, dict): | |
| converted_secrets = {} | |
| for key, value in secrets.items(): | |
| try: | |
| converted_secrets[key] = CustomSecret.from_value(value) | |
| except ValueError: | |
| continue | |
| new_data['custom_secrets'] = MappingProxyType(converted_secrets) | |
| elif isinstance(secrets, MappingProxyType): | |
| new_data['custom_secrets'] = secrets | |
| return new_data | |
| def set_event_stream_secrets(self, event_stream: EventStream) -> None: | |
| """ | |
| This ensures that provider tokens and custom secrets masked from the event stream | |
| Args: | |
| event_stream: Agent session's event stream | |
| """ | |
| secrets = self.get_env_vars() | |
| event_stream.set_secrets(secrets) | |
| def get_env_vars(self) -> dict[str, str]: | |
| secret_store = self.model_dump(context={'expose_secrets': True}) | |
| custom_secrets = secret_store.get('custom_secrets', {}) | |
| secrets = {} | |
| for secret_name, value in custom_secrets.items(): | |
| secrets[secret_name] = value['secret'] | |
| return secrets | |
| def get_custom_secrets_descriptions(self) -> dict[str, str]: | |
| secrets = {} | |
| for secret_name, secret in self.custom_secrets.items(): | |
| secrets[secret_name] = secret.description | |
| return secrets | |