mirror of
https://github.com/All-Hands-AI/OpenHands.git
synced 2026-04-29 03:00:45 -04:00
Compare commits
2 Commits
test/sdk-s
...
debug/lite
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b03f8eb80d | ||
|
|
7fbb48c406 |
@@ -159,7 +159,7 @@ poetry run pytest ./tests/unit/test_*.py
|
||||
To reduce build time (e.g., if no changes were made to the client-runtime component), you can use an existing Docker
|
||||
container image by setting the SANDBOX_RUNTIME_CONTAINER_IMAGE environment variable to the desired Docker image.
|
||||
|
||||
Example: `export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/openhands/runtime:0.61-nikolaik`
|
||||
Example: `export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/openhands/runtime:0.62-nikolaik`
|
||||
|
||||
## Develop inside Docker container
|
||||
|
||||
|
||||
@@ -82,17 +82,17 @@ You'll find OpenHands running at [http://localhost:3000](http://localhost:3000)
|
||||
You can also run OpenHands directly with Docker:
|
||||
|
||||
```bash
|
||||
docker pull docker.openhands.dev/openhands/runtime:0.61-nikolaik
|
||||
docker pull docker.openhands.dev/openhands/runtime:0.62-nikolaik
|
||||
|
||||
docker run -it --rm --pull=always \
|
||||
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.openhands.dev/openhands/runtime:0.61-nikolaik \
|
||||
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.openhands.dev/openhands/runtime:0.62-nikolaik \
|
||||
-e LOG_ALL_EVENTS=true \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v ~/.openhands:/.openhands \
|
||||
-p 3000:3000 \
|
||||
--add-host host.docker.internal:host-gateway \
|
||||
--name openhands-app \
|
||||
docker.openhands.dev/openhands/openhands:0.61
|
||||
docker.openhands.dev/openhands/openhands:0.62
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
@@ -12,7 +12,7 @@ services:
|
||||
- SANDBOX_API_HOSTNAME=host.docker.internal
|
||||
- DOCKER_HOST_ADDR=host.docker.internal
|
||||
#
|
||||
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/openhands/runtime:0.61-nikolaik}
|
||||
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/openhands/runtime:0.62-nikolaik}
|
||||
- SANDBOX_USER_ID=${SANDBOX_USER_ID:-1234}
|
||||
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
|
||||
ports:
|
||||
|
||||
@@ -7,7 +7,7 @@ services:
|
||||
image: openhands:latest
|
||||
container_name: openhands-app-${DATE:-}
|
||||
environment:
|
||||
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-docker.openhands.dev/openhands/runtime:0.61-nikolaik}
|
||||
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-docker.openhands.dev/openhands/runtime:0.62-nikolaik}
|
||||
#- SANDBOX_USER_ID=${SANDBOX_USER_ID:-1234} # enable this only if you want a specific non-root sandbox user but you will have to manually adjust permissions of ~/.openhands for this user
|
||||
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
|
||||
ports:
|
||||
|
||||
@@ -202,17 +202,54 @@ class SaasSettingsStore(SettingsStore):
|
||||
) -> Settings | None:
|
||||
logger.info(
|
||||
'saas_settings_store:update_settings_with_litellm_default:start',
|
||||
extra={'user_id': self.user_id},
|
||||
extra={
|
||||
'user_id': self.user_id,
|
||||
'LITE_LLM_API_KEY_set': LITE_LLM_API_KEY is not None,
|
||||
'LITE_LLM_API_URL': LITE_LLM_API_URL,
|
||||
'LOCAL_DEPLOYMENT': os.environ.get('LOCAL_DEPLOYMENT'),
|
||||
},
|
||||
)
|
||||
if LITE_LLM_API_KEY is None or LITE_LLM_API_URL is None:
|
||||
logger.warning(
|
||||
'saas_settings_store:update_settings_with_litellm_default:missing_config',
|
||||
extra={
|
||||
'user_id': self.user_id,
|
||||
'LITE_LLM_API_KEY_set': LITE_LLM_API_KEY is not None,
|
||||
'LITE_LLM_API_URL_set': LITE_LLM_API_URL is not None,
|
||||
},
|
||||
)
|
||||
return None
|
||||
local_deploy = os.environ.get('LOCAL_DEPLOYMENT', None)
|
||||
key = LITE_LLM_API_KEY
|
||||
if local_deploy:
|
||||
logger.info(
|
||||
'saas_settings_store:update_settings_with_litellm_default:local_deployment_mode',
|
||||
extra={'user_id': self.user_id, 'LOCAL_DEPLOYMENT': local_deploy},
|
||||
)
|
||||
if not local_deploy:
|
||||
# Get user info to add to litellm
|
||||
token_manager = TokenManager()
|
||||
keycloak_user_info = (
|
||||
await token_manager.get_user_info_from_user_id(self.user_id) or {}
|
||||
try:
|
||||
keycloak_user_info = (
|
||||
await token_manager.get_user_info_from_user_id(self.user_id) or {}
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
'saas_settings_store:update_settings_with_litellm_default:keycloak_error',
|
||||
extra={
|
||||
'user_id': self.user_id,
|
||||
'error': str(e),
|
||||
'error_type': type(e).__name__,
|
||||
},
|
||||
)
|
||||
raise
|
||||
|
||||
logger.debug(
|
||||
'saas_settings_store:update_settings_with_litellm_default:keycloak_info_retrieved',
|
||||
extra={
|
||||
'user_id': self.user_id,
|
||||
'has_email': 'email' in keycloak_user_info,
|
||||
},
|
||||
)
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
@@ -223,10 +260,37 @@ class SaasSettingsStore(SettingsStore):
|
||||
) as client:
|
||||
# Get the previous max budget to prevent accidental loss
|
||||
# In Litellm a get always succeeds, regardless of whether the user actually exists
|
||||
response = await client.get(
|
||||
f'{LITE_LLM_API_URL}/user/info?user_id={self.user_id}'
|
||||
user_info_url = f'{LITE_LLM_API_URL}/user/info?user_id={self.user_id}'
|
||||
logger.debug(
|
||||
'saas_settings_store:update_settings_with_litellm_default:fetching_user_info',
|
||||
extra={'user_id': self.user_id, 'url': user_info_url},
|
||||
)
|
||||
response.raise_for_status()
|
||||
try:
|
||||
response = await client.get(user_info_url)
|
||||
response.raise_for_status()
|
||||
except httpx.HTTPStatusError as e:
|
||||
logger.error(
|
||||
'saas_settings_store:update_settings_with_litellm_default:user_info_http_error',
|
||||
extra={
|
||||
'user_id': self.user_id,
|
||||
'status_code': e.response.status_code,
|
||||
'response_text': e.response.text[:500] if e.response.text else None,
|
||||
'url': user_info_url,
|
||||
},
|
||||
)
|
||||
raise
|
||||
except httpx.RequestError as e:
|
||||
logger.error(
|
||||
'saas_settings_store:update_settings_with_litellm_default:user_info_request_error',
|
||||
extra={
|
||||
'user_id': self.user_id,
|
||||
'error': str(e),
|
||||
'error_type': type(e).__name__,
|
||||
'url': user_info_url,
|
||||
},
|
||||
)
|
||||
raise
|
||||
|
||||
response_json = response.json()
|
||||
user_info = response_json.get('user_info') or {}
|
||||
logger.info(
|
||||
@@ -265,18 +329,39 @@ class SaasSettingsStore(SettingsStore):
|
||||
|
||||
# We explicitly delete here to guard against odd inherited settings on upgrade.
|
||||
# We don't care if this fails with a 404
|
||||
await client.post(
|
||||
delete_response = await client.post(
|
||||
f'{LITE_LLM_API_URL}/user/delete', json={'user_ids': [self.user_id]}
|
||||
)
|
||||
logger.debug(
|
||||
'saas_settings_store:update_settings_with_litellm_default:user_delete_response',
|
||||
extra={
|
||||
'user_id': self.user_id,
|
||||
'status_code': delete_response.status_code,
|
||||
},
|
||||
)
|
||||
|
||||
# Create the new litellm user
|
||||
logger.debug(
|
||||
'saas_settings_store:update_settings_with_litellm_default:creating_user',
|
||||
extra={
|
||||
'user_id': self.user_id,
|
||||
'email': email,
|
||||
'max_budget': max_budget,
|
||||
'spend': spend,
|
||||
},
|
||||
)
|
||||
response = await self._create_user_in_lite_llm(
|
||||
client, email, max_budget, spend
|
||||
)
|
||||
if not response.is_success:
|
||||
logger.warning(
|
||||
'duplicate_user_email',
|
||||
extra={'user_id': self.user_id, 'email': email},
|
||||
extra={
|
||||
'user_id': self.user_id,
|
||||
'email': email,
|
||||
'status_code': response.status_code,
|
||||
'response_text': response.text[:500] if response.text else None,
|
||||
},
|
||||
)
|
||||
# Litellm insists on unique email addresses - it is possible the email address was registered with a different user.
|
||||
response = await self._create_user_in_lite_llm(
|
||||
|
||||
4
frontend/package-lock.json
generated
4
frontend/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "openhands-frontend",
|
||||
"version": "0.61.0",
|
||||
"version": "0.62.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "openhands-frontend",
|
||||
"version": "0.61.0",
|
||||
"version": "0.62.0",
|
||||
"dependencies": {
|
||||
"@heroui/react": "^2.8.4",
|
||||
"@heroui/use-infinite-scroll": "^2.2.11",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openhands-frontend",
|
||||
"version": "0.61.0",
|
||||
"version": "0.62.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"engines": {
|
||||
|
||||
@@ -40,7 +40,7 @@ Two configuration options are required to use the Kubernetes runtime:
|
||||
2. **Runtime Container Image**: Specify the container image to use for the runtime environment
|
||||
```toml
|
||||
[sandbox]
|
||||
runtime_container_image = "docker.openhands.dev/openhands/runtime:0.61-nikolaik"
|
||||
runtime_container_image = "docker.openhands.dev/openhands/runtime:0.62-nikolaik"
|
||||
```
|
||||
|
||||
#### Additional Kubernetes Options
|
||||
|
||||
@@ -6,7 +6,7 @@ requires = [
|
||||
|
||||
[tool.poetry]
|
||||
name = "openhands-ai"
|
||||
version = "0.61.0"
|
||||
version = "0.62.0"
|
||||
description = "OpenHands: Code Less, Make More"
|
||||
authors = [ "OpenHands" ]
|
||||
license = "MIT"
|
||||
|
||||
Reference in New Issue
Block a user